[PORTAL-7] Rebase
[portal.git] / ecomp-portal-FE-common / client / bower_components_external / b2b / js / b2b-angular / b2b-library.min.js
1 /*! b2b-angular-library - v1.0.1 - Last updated: 2017-03-02. Copyright (c) 2016 AT&T Services, Inc. */ \r
2 angular.module("b2b.att.tpls", ['b2bTemplate/audioPlayer/audioPlayer.html', 'b2bTemplate/audioRecorder/audioRecorder.html', 'b2bTemplate/backToTop/backToTop.html', 'b2bTemplate/boardstrip/b2bAddBoard.html', 'b2bTemplate/boardstrip/b2bBoard.html', 'b2bTemplate/boardstrip/b2bBoardstrip.html', 'b2bTemplate/calendar/datepicker-popup.html', 'b2bTemplate/calendar/datepicker.html', 'b2bTemplate/coachmark/coachmark.html', 'b2bTemplate/dropdowns/b2bDropdownDesktop.html', 'b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html', 'b2bTemplate/dropdowns/b2bDropdownListDesktop.html', 'b2bTemplate/fileUpload/fileUpload.html', 'b2bTemplate/flyout/flyout.html', 'b2bTemplate/flyout/flyoutContent.html', 'b2bTemplate/footer/footer_column_switch_tpl.html', 'b2bTemplate/horizontalTable/horizontalTable.html', 'b2bTemplate/hourPicker/b2bHourpicker.html', 'b2bTemplate/hourPicker/b2bHourpickerPanel.html', 'b2bTemplate/hourPicker/b2bHourpickerValue.html', 'b2bTemplate/leftNavigation/leftNavigation.html', 'b2bTemplate/listbox/listbox.html', 'b2bTemplate/modalsAndAlerts/b2b-backdrop.html', 'b2bTemplate/modalsAndAlerts/b2b-window.html', 'b2bTemplate/monthSelector/monthSelector-popup.html', 'b2bTemplate/monthSelector/monthSelector.html', 'b2bTemplate/monthSelector/monthSelectorLink.html', 'b2bTemplate/pagination/b2b-pagination.html', 'b2bTemplate/paneSelector/paneSelector.html', 'b2bTemplate/paneSelector/paneSelectorPane.html', 'b2bTemplate/profileCard/profileCard-addUser.html', 'b2bTemplate/profileCard/profileCard.html', 'b2bTemplate/searchField/searchField.html', 'b2bTemplate/seekBar/seekBar.html', 'b2bTemplate/slider/slider.html', 'b2bTemplate/spinButton/spinButton.html', 'b2bTemplate/statusTracker/statusTracker.html', 'b2bTemplate/stepTracker/stepTracker.html', 'b2bTemplate/switches/switches-spanish.html', 'b2bTemplate/switches/switches.html', 'b2bTemplate/tableMessages/tableMessage.html', 'b2bTemplate/tables/b2bTable.html', 'b2bTemplate/tables/b2bTableBody.html', 'b2bTemplate/tables/b2bTableHeaderSortable.html', 'b2bTemplate/tables/b2bTableHeaderUnsortable.html', 'b2bTemplate/tableScrollbar/tableScrollbar.html', 'b2bTemplate/tabs/b2bTab.html', 'b2bTemplate/tabs/b2bTabset.html', 'b2bTemplate/treeNav/groupedTree.html', 'b2bTemplate/treeNav/treeMember.html', 'b2bTemplate/treeNav/ungroupedTree.html', 'b2bTemplate/treeNodeCheckbox/groupedTree.html', 'b2bTemplate/treeNodeCheckbox/treeMember.html', 'b2bTemplate/treeNodeCheckbox/ungroupedTree.html']);angular.module("b2b.att", ["b2b.att.tpls", 'b2b.att.addressInputTemplate','b2b.att.arrows','b2b.att.audioPlayer','b2b.att.audioRecorder','b2b.att.backToTop','b2b.att.badgesForAlerts','b2b.att.boardstrip','b2b.att.breadcrumbs','b2b.att.buttonGroups','b2b.att.buttons','b2b.att.calendar','b2b.att.checkboxes','b2b.att.coachmark','b2b.att.configurationSection','b2b.att.directoryListingTemplate','b2b.att.dropdowns','b2b.att.fileUpload','b2b.att.filters','b2b.att.flyout','b2b.att.footer','b2b.att.header','b2b.att.headings','b2b.att.horizontalTable','b2b.att.hourPicker','b2b.att.inputTemplate','b2b.att.leftNavigation','b2b.att.links','b2b.att.listbox','b2b.att.loaderAnimation','b2b.att.messageWrapper','b2b.att.modalsAndAlerts','b2b.att.monthSelector','b2b.att.multiLevelNavigation','b2b.att.multipurposeExpander','b2b.att.notesMessagesAndErrors','b2b.att.notificationCardTemplate','b2b.att.orderConfirmationTemplate','b2b.att.pagination','b2b.att.paneSelector','b2b.att.phoneNumberInput','b2b.att.profileBlockTemplate','b2b.att.profileCard','b2b.att.radios','b2b.att.searchField','b2b.att.seekBar','b2b.att.selectorModule','b2b.att.separators','b2b.att.slider','b2b.att.spinButton','b2b.att.staticRouteTemplate','b2b.att.statusTracker','b2b.att.stepTracker','b2b.att.switches','b2b.att.tableMessages','b2b.att.tables','b2b.att.tableScrollbar','b2b.att.tabs','b2b.att.tagBadges','b2b.att.textArea','b2b.att.tooltipsForForms','b2b.att.treeNav','b2b.att.treeNodeCheckbox','b2b.att.utilities']);/**\r
3  * @ngdoc directive\r
4  * @name Template.att:Address Input\r
5  *\r
6  * @description\r
7  *  <file src="src/addressInputTemplate/docs/readme.md" />\r
8  *\r
9  * @usage\r
10 \r
11  *\r
12  * @example\r
13  *  <section id="code">   \r
14  <example module="b2b.att">\r
15  <file src="src/addressInputTemplate/docs/demo.html" />\r
16  <file src="src/addressInputTemplate/docs/demo.js" />\r
17  </example>\r
18  </section>\r
19  *\r
20  */\r
21 angular.module('b2b.att.addressInputTemplate', ['ngMessages']);\r
22 /**\r
23  * @ngdoc directive\r
24  * @name Buttons, links & UI controls.att:arrows\r
25  *\r
26  * @description\r
27  *  <file src="src/arrows/docs/readme.md" />\r
28  *\r
29  * @usage\r
30  *   Please refer demo.html tab in Example section below.\r
31  *\r
32  * @example\r
33  *  <section id="code">\r
34         <example module="b2b.att">\r
35             <file src="src/arrows/docs/demo.html" />\r
36             <file src="src/arrows/docs/demo.js" />\r
37        </example>\r
38     </section>\r
39  *\r
40  */\r
41 angular.module('b2b.att.arrows', []);\r
42 /**\r
43  * @ngdoc directive\r
44  * @name Videos, audio & animation.att:Audio Player\r
45  * @scope\r
46  * @param {string} audioSrcUrl - MP3 audio source URL or Blob URL\r
47  * @description\r
48  *  <file src="src/audioPlayer/docs/readme.md" />\r
49  *\r
50  * @usage\r
51  * \r
52  <div b2b-audio audio-src-url='audioSrcUrl'></div>\r
53  *\r
54  * @example\r
55  *  <section id="code">\r
56         <example module="b2b.att">\r
57             <file src="src/audioPlayer/docs/demo.html" />\r
58             <file src="src/audioPlayer/docs/demo.js" />\r
59        </example>\r
60     </section>\r
61  *\r
62  */\r
63  \r
64 angular.module('b2b.att.audioPlayer', ['b2b.att.utilities', 'b2b.att.seekBar'])\r
65     .constant('AudioPlayerConfig', {\r
66         'defaultVolume': 50,\r
67         'timeShiftInSeconds': 5\r
68     })\r
69     .filter('trustedAudioUrl', ['$sce', function ($sce) {\r
70         return function (audioFileFullPath) {\r
71             return audioFileFullPath ? $sce.trustAsResourceUrl(audioFileFullPath) : 'undefined';\r
72         };\r
73     }])\r
74     .directive('b2bAudio', ['$log', '$timeout', 'AudioPlayerConfig', '$compile', 'events', function ($log, $timeout, AudioPlayerConfig, $compile, events) {\r
75         return {\r
76             restrict: 'EA',\r
77             replace: true,\r
78             scope: {\r
79                 audioSrcUrl: '='\r
80             },\r
81             templateUrl: 'b2bTemplate/audioPlayer/audioPlayer.html',\r
82             controller: function ($scope) {\r
83 \r
84                 $scope.audio = {};\r
85 \r
86                 if (!angular.isDefined($scope.audioSrcUrl)) {\r
87                     $log.warn('b2b-audio : audio-src-url undefined');\r
88                     $scope.audioSrcUrl = undefined;\r
89                     $scope.audio.mp3 = undefined;\r
90                 }\r
91 \r
92             },\r
93             link: function (scope, element) {\r
94                 var audioElement = angular.element(element[0].querySelector('audio'))[0];\r
95                 scope.audio.audioElement = audioElement;\r
96                 \r
97                 function setAttributes(element, attributes) {\r
98                     Object.keys(attributes).forEach(function (name) {\r
99                         element.setAttribute(name, attributes[name]);\r
100                     });\r
101                 }\r
102 \r
103                 $timeout(function () {\r
104                     // TODO: Replace with DDA Tooltip\r
105                     var seekBarKnob = element[0].querySelector('.b2b-seek-bar-knob');\r
106                     var tooltipObject = {\r
107                         'tooltip': '{{timeFormatter(audio.currentTime)}}',\r
108                         'tooltip-placement': 'above',\r
109                         'tooltip-style': 'blue',\r
110                         'tooltip-trigger': 'mousedown',\r
111                         'tooltip-append-to-body': 'false',\r
112                         'tooltip-offset': '-10',\r
113                         'refer-by': 'seek-bar-tooltip'\r
114                     };\r
115                     setAttributes(seekBarKnob, tooltipObject);\r
116                     $compile(seekBarKnob)(scope);\r
117                 });\r
118 \r
119                 if (angular.isDefined(scope.audioSrcUrl)) {\r
120                     scope.audio.mp3 = scope.audioSrcUrl;\r
121                 }\r
122 \r
123                 scope.audio.currentTime = 0;\r
124                 scope.audio.currentVolume = AudioPlayerConfig.defaultVolume;\r
125                 scope.audio.timeShiftInSeconds = AudioPlayerConfig.timeShiftInSeconds;\r
126                 scope.isPlayInProgress = false;\r
127                 scope.isReady = false;\r
128                 scope.isAudioDragging = false;\r
129 \r
130                 $timeout(function () {\r
131                     audioElement.load();\r
132                     audioElement.volume = scope.audio.currentVolume / 100;\r
133                 });\r
134 \r
135                 scope.$watch('audioSrcUrl', function (newVal, oldVal) {\r
136                     if (newVal !== oldVal) {\r
137                         if (!newVal) {\r
138                             $log.warn('b2b-audio : audio-src-url undefined. Please provide a valid URL');\r
139                         }\r
140                         \r
141                         scope.audio.mp3 = newVal;\r
142                         $timeout(function () {\r
143                             audioElement.load();\r
144                         });\r
145                     }\r
146                 });\r
147 \r
148                 scope.playAudio = function () {\r
149                     if (scope.isReady) {\r
150                         audioElement.play();\r
151                     }\r
152                 };\r
153 \r
154                 audioElement.onplay = function () {\r
155                     scope.isPlayInProgress = true;\r
156                     scope.$digest();\r
157                 };\r
158 \r
159                 scope.pauseAudio = function () {\r
160                     audioElement.pause();\r
161                 };\r
162 \r
163                 audioElement.onpause = function () {\r
164                     scope.isPlayInProgress = false;\r
165                     scope.$digest();\r
166                 };\r
167 \r
168                 scope.toggleAudio = function () {\r
169                     if (audioElement.paused) {\r
170                         scope.playAudio();\r
171                     } else {\r
172                         scope.pauseAudio();\r
173                     }\r
174                 };\r
175 \r
176                 scope.volumeUp = function (delta) {\r
177                     if (!delta) {\r
178                         delta = 0.1;\r
179                     } else {\r
180                         delta = delta / 100;\r
181                     }\r
182                     audioElement.muted = false;\r
183                     if (audioElement.volume < 1) {\r
184                         audioElement.volume = Math.min((Math.round((audioElement.volume + delta) * 100) / 100), 1);\r
185                     }\r
186                     scope.audio.currentVolume = audioElement.volume * 100;\r
187                     return audioElement.volume;\r
188                 };\r
189 \r
190                 scope.volumeDown = function (delta) {\r
191                     if (!delta) {\r
192                         delta = 0.1;\r
193                     } else {\r
194                         delta = delta / 100;\r
195                     }\r
196                     audioElement.muted = false;\r
197                     if (audioElement.volume > 0) {\r
198                         audioElement.volume = Math.max((Math.round((audioElement.volume - delta) * 100) / 100), 0);\r
199                     }\r
200                     scope.audio.currentVolume = audioElement.volume * 100;\r
201                     return audioElement.volume;\r
202                 };\r
203 \r
204                 var volumeHandler = function (e) {\r
205                     events.preventDefault(e);\r
206                     if ((e.wheelDelta && e.wheelDelta > 0) || (e.detail && e.detail < 0)) {\r
207                         scope.volumeUp();\r
208                     } else {\r
209                         scope.volumeDown();\r
210                     }\r
211                     scope.$digest();\r
212                 };\r
213 \r
214                 \r
215 \r
216                 scope.$watch('audio.currentVolume', function (newVal, oldVal) {\r
217                     if (newVal !== oldVal) {\r
218                         audioElement.volume = newVal / 100;\r
219                     }\r
220                 });\r
221 \r
222                 scope.setCurrentTime = function (timeInSec) {\r
223                     audioElement.currentTime = timeInSec;\r
224                 };\r
225 \r
226                 scope.setAudioPosition = function (val) {\r
227                     if (scope.isReady) {\r
228                         scope.setCurrentTime(val);\r
229                         scope.isAudioDragging = false;\r
230                     }\r
231                 };\r
232 \r
233                 function getTimestampArray(timestamp) {\r
234                     var d = Math.abs(timestamp) / 1000; // delta\r
235                     var r = {}; // result\r
236                     var s = { // structure\r
237                         day: 86400,\r
238                         hour: 3600,\r
239                         minute: 60,\r
240                         second: 1\r
241                     };\r
242 \r
243                     Object.keys(s).forEach(function (key) {\r
244                         r[key] = Math.floor(d / s[key]);\r
245                         d -= r[key] * s[key];\r
246                     });\r
247 \r
248                     return r;\r
249                 };\r
250 \r
251                 scope.timeFormatter = function (timeInSec) {\r
252                     var formattedTime = '00:00';\r
253 \r
254                     if (!timeInSec || timeInSec < 1) {\r
255                         return formattedTime;\r
256                     }\r
257 \r
258                     if (typeof timeInSec === 'string') {\r
259                         return timeInSec;\r
260                     }\r
261 \r
262                     var dateArray = getTimestampArray(timeInSec * 1000);\r
263                     Object.keys(dateArray).forEach(function (key) {\r
264                         if (dateArray[key] === 0) {\r
265                             dateArray[key] = '00';\r
266                         } else if (dateArray[key] < 10) {\r
267                             dateArray[key] = '0' + dateArray[key];\r
268                         }\r
269                     });\r
270 \r
271                     formattedTime = dateArray['minute'] + ':' + dateArray['second'];\r
272 \r
273                     if (dateArray['hour'] !== '00') {\r
274                         formattedTime = dateArray['hour'] + ':' + formattedTime;\r
275                     }\r
276 \r
277                     if (dateArray['day'] !== '00') {\r
278                         formattedTime = dateArray['day'] + ':' + formattedTime;\r
279                     }\r
280 \r
281                     return formattedTime;\r
282                 };\r
283 \r
284                 audioElement.onloadedmetadata = function () {\r
285                     scope.audio.duration = audioElement.duration;\r
286                     scope.$digest();\r
287                 };\r
288 \r
289                 audioElement.ontimeupdate = function () {\r
290                     if (!scope.isAudioDragging) {\r
291                         scope.audio.currentTime = audioElement.currentTime;\r
292                         scope.$digest();\r
293                     }\r
294                 };\r
295 \r
296                 audioElement.onended = function () {\r
297                     scope.setCurrentTime(0);\r
298                     scope.audio.currentTime = 0;\r
299                     if (!audioElement.paused) {\r
300                         scope.pauseAudio();\r
301                     }\r
302                     scope.$digest();\r
303                 };\r
304 \r
305                 audioElement.oncanplay = function () {\r
306                     scope.isReady = true;\r
307                     scope.isPlayInProgress = !audioElement.paused;\r
308                     scope.$digest();\r
309                 };\r
310 \r
311                 var onloadstart = function () {\r
312                     scope.isReady = false;\r
313                     scope.isPlayInProgress = !audioElement.paused;\r
314                     scope.audio.currentTime = 0;\r
315                     scope.audio.duration = 0;\r
316                     scope.$digest();\r
317                 };\r
318                 audioElement.addEventListener("loadstart", onloadstart);\r
319             }\r
320         };\r
321     }]);\r
322 /**\r
323  * @ngdoc directive\r
324  * @name Videos, audio & animation.att:Audio Recorder\r
325  * @scope\r
326  * @param {function} callback - A callback to handle the WAV blob\r
327  * @param {object} config - A config object with properties startRecordingMessage & whileRecordingMessage\r
328  * @description\r
329  *  <file src="src/audioRecorder/docs/readme.md" />\r
330  *\r
331  *\r
332  * @example\r
333  *  <section id="code">\r
334         <example module="b2b.att">\r
335             <file src="src/audioRecorder/docs/demo.html" />\r
336             <file src="src/audioRecorder/docs/demo.js" />\r
337        </example>\r
338     </section>\r
339  *\r
340  */\r
341 angular.module('b2b.att.audioRecorder', ['b2b.att.utilities'])\r
342     .constant('AudioRecorderConfig', {\r
343         'startRecordingMessage': 'Click on REC icon to being recording',\r
344         'whileRecordingMessage': 'Recording...'\r
345     })\r
346     .directive('b2bAudioRecorder', ['$interval', 'AudioRecorderConfig', 'b2bUserAgent', 'b2bRecorder', function($interval, AudioRecorderConfig, b2bUserAgent, b2bRecorder) {\r
347         return {\r
348             restrict: 'EA',\r
349             replace: true,\r
350             scope: {\r
351                 callback: '&'\r
352             },\r
353             templateUrl: 'b2bTemplate/audioRecorder/audioRecorder.html',\r
354             controller: function($scope) {\r
355 \r
356                 function hasGetUserMedia() {\r
357                     return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||\r
358                         navigator.mozGetUserMedia || navigator.msGetUserMedia);\r
359                 }\r
360 \r
361                 if (!hasGetUserMedia()) {\r
362                     throw new Error('Your broswer does not support MediaRecorder API');\r
363                 }\r
364 \r
365                 if (!(b2bUserAgent.isFF() || b2bUserAgent.isChrome())) {\r
366                     throw new Error('b2bAudioRecorder does not support this browser!');\r
367                 }\r
368 \r
369             },\r
370             link: function(scope, element) {\r
371                 scope.elapsedTime = 0;\r
372                 scope.isRecording = false;\r
373                 scope.config = {};\r
374                 scope.config.startRecordingMessage = AudioRecorderConfig.startRecordingMessage;\r
375                 scope.config.whileRecordingMessage = AudioRecorderConfig.whileRecordingMessage;\r
376                 \r
377 \r
378                 var timer = undefined; // Interval promise\r
379                 navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;\r
380                 var stream;\r
381                 var audio = angular.element(element[0].querySelector('audio'))[0];\r
382                 var recorder = undefined;\r
383 \r
384                 function startRecording() {\r
385                     scope.isRecording = true;\r
386                     navigator.mediaDevices.getUserMedia({\r
387                         audio: true\r
388                     }).then(function(stream) {\r
389                         //create the MediaStreamAudioSourceNode\r
390                         context = new AudioContext();\r
391                         source = context.createMediaStreamSource(stream);\r
392                         recorder = new b2bRecorder(source);\r
393                         recorder.record();\r
394 \r
395                         timer = $interval(function() {\r
396                             scope.elapsedTime += 1;\r
397                         }, 1000, 0);\r
398                     }).catch(function(err) {\r
399                         angular.noop();\r
400                     });\r
401 \r
402                 };\r
403 \r
404                 function stopRecording() {\r
405                     scope.isRecording = false;\r
406                     recorder.stop();\r
407                     var audio = {};\r
408                     recorder.exportWAV(function(s) {\r
409                         audio.src = window.URL.createObjectURL(s);\r
410                         context.close().then(function() {\r
411                             if (timer) {\r
412                                 $interval.cancel(timer);\r
413                             }\r
414                             scope.elapsedTime = 0;\r
415                             \r
416                             recorder.clear();\r
417                             recorder = undefined;\r
418                         });\r
419                         if (angular.isFunction(scope.callback)){\r
420                             scope.callback({'data': audio});    \r
421                         }\r
422                     });\r
423                     \r
424                     \r
425                 }\r
426 \r
427                 scope.toggleRecording = function() {\r
428                     if (scope.isRecording) {\r
429                         stopRecording();\r
430                     } else {\r
431                         startRecording();\r
432                     }\r
433                 };\r
434 \r
435 \r
436 \r
437                 //TODO: Move this into utilities\r
438                 function getTimestampArray(timestamp) {\r
439                     var d = Math.abs(timestamp) / 1000; // delta\r
440                     var r = {}; // result\r
441                     var s = { // structure\r
442                         day: 86400,\r
443                         hour: 3600,\r
444                         minute: 60,\r
445                         second: 1\r
446                     };\r
447 \r
448                     Object.keys(s).forEach(function(key) {\r
449                         r[key] = Math.floor(d / s[key]);\r
450                         d -= r[key] * s[key];\r
451                     });\r
452 \r
453                     return r;\r
454                 };\r
455                 scope.timeFormatter = function(timeInSec) {\r
456                     var formattedTime = '00:00';\r
457 \r
458                     if (!timeInSec || timeInSec < 1) {\r
459                         return formattedTime;\r
460                     }\r
461 \r
462                     if (typeof timeInSec === 'string') {\r
463                         return timeInSec;\r
464                     }\r
465 \r
466                     var dateArray = getTimestampArray(timeInSec * 1000);\r
467                     Object.keys(dateArray).forEach(function(key) {\r
468                         if (dateArray[key] === 0) {\r
469                             dateArray[key] = '00';\r
470                         } else if (dateArray[key] < 10) {\r
471                             dateArray[key] = '0' + dateArray[key];\r
472                         }\r
473                     });\r
474 \r
475                     formattedTime = dateArray['minute'] + ':' + dateArray['second'];\r
476 \r
477                     if (dateArray['hour'] !== '00') {\r
478                         formattedTime = dateArray['hour'] + ':' + formattedTime;\r
479                     }\r
480 \r
481                     if (dateArray['day'] !== '00') {\r
482                         formattedTime = dateArray['day'] + ':' + formattedTime;\r
483                     }\r
484 \r
485                     return formattedTime;\r
486                 };\r
487 \r
488                 scope.$on('$destroy', function() {\r
489                     if (timer) {\r
490                         $interval.cancel(timer);\r
491                     }\r
492                 });\r
493             }\r
494         };\r
495     }]);\r
496 \r
497 /**\r
498  * @ngdoc directive\r
499  * @name Navigation.att:Back To Top\r
500  * @scope\r
501  * @description\r
502  *  <file src="src/backToTop/docs/readme.md" />\r
503  * @param {integer} scrollSpeed - Scroll speed in seconds, default is 1\r
504 *\r
505  * @usage\r
506  * \r
507     <div ng-controller="backToTopController">\r
508         <div b2b-backtotop></div>\r
509     </div>\r
510  * \r
511  * @example\r
512  *  <section id="code">\r
513         <example module="b2b.att">\r
514             <file src="src/backToTop/docs/demo.html" />\r
515             <file src="src/backToTop/docs/demo.js" />\r
516        </example>\r
517     </section>\r
518  *\r
519  */\r
520  \r
521 angular.module('b2b.att.backToTop', ['b2b.att.utilities','b2b.att.position'])\r
522     .directive('b2bBacktotopButton', [function () {\r
523         return {\r
524             restrict: 'EA',\r
525             replace: true,\r
526             templateUrl: 'b2bTemplate/backToTop/backToTop.html',\r
527             link: function (scope, elem, attr) {\r
528                 elem.bind('click', function(evt) {\r
529                     var scrollSpeed = parseInt(attr.scrollSpeed) || 1;\r
530                     TweenLite.to(window, scrollSpeed, {scrollTo:{x: 0, y: 0}});\r
531                 });\r
532             }\r
533         };\r
534     }]);\r
535 /**\r
536  * @ngdoc directive\r
537  * @name Messages, modals & alerts.att:badgesForAlerts\r
538  *\r
539  * @description\r
540  *  <file src="src/badgesForAlerts/docs/readme.md" />\r
541  * @example\r
542  *  <section id="code">\r
543         <example module="b2b.att">\r
544             <file src="src/badgesForAlerts/docs/demo.html" />\r
545             <file src="src/badgesForAlerts/docs/demo.js" />\r
546        </example>\r
547         </section>\r
548  *\r
549  */\r
550 angular.module('b2b.att.badgesForAlerts', []);\r
551 /**\r
552  * @ngdoc directive\r
553  * @name Misc.att:boardstrip\r
554  *\r
555  * @description\r
556  *  <file src="src/boardstrip/docs/readme.md" />\r
557  *\r
558  * @usage\r
559  * See demo section\r
560  * @example\r
561     <section id="code">\r
562         <b>HTML + AngularJS</b>\r
563         <example module="b2b.att">\r
564             <file src="src/boardstrip/docs/demo.html" />\r
565             <file src="src/boardstrip/docs/demo.js" />\r
566         </example>\r
567     </section>\r
568  */\r
569 angular.module('b2b.att.boardstrip', ['b2b.att.utilities'])\r
570     .constant('BoardStripConfig', {\r
571         'maxVisibleBoards': 4,\r
572         'boardsToScroll': 1,\r
573         /* These parameters are non-configurable and remain unaltered, until there is a change in corresponding CSS */\r
574         'boardLength': 140,\r
575         'boardMargin': 15\r
576     })\r
577     .directive('b2bBoard', [function () {\r
578         return {\r
579             restrict: 'AE',\r
580             replace: true,\r
581             transclude: true,\r
582             require: '^b2bBoardStrip',\r
583             scope: {\r
584                 boardIndex: '=',\r
585                 boardLabel: '='\r
586             },\r
587             templateUrl: 'b2bTemplate/boardstrip/b2bBoard.html',\r
588             link: function (scope, element, attrs, ctrls) {\r
589 \r
590                 var parentCtrl = ctrls;\r
591 \r
592                 scope.getCurrentIndex = function () {\r
593                     return parentCtrl.getCurrentIndex();\r
594                 };\r
595                 scope.selectBoard = function (boardIndex) {\r
596                     if (!isNaN(boardIndex)) {\r
597                         parentCtrl.setCurrentIndex(boardIndex);\r
598                     }\r
599                 };\r
600             }\r
601         };\r
602     }])\r
603     .directive('b2bBoardStrip', ['BoardStripConfig', '$timeout', function (BoardStripConfig, $timeout) {\r
604         return {\r
605             restrict: 'AE',\r
606             replace: true,\r
607             transclude: true,\r
608             require: ['?ngModel', 'b2bBoardStrip'],\r
609             scope: {\r
610                 boardsMasterArray: '=',\r
611                 onAddBoard: '&?'\r
612             },\r
613             templateUrl: 'b2bTemplate/boardstrip/b2bBoardstrip.html',\r
614             controller: function ($scope) {\r
615                 if (!angular.isDefined($scope.boardsMasterArray)) {\r
616                     $scope.boardsMasterArray = [];\r
617                 }\r
618 \r
619                 this.rectifyMaxVisibleBoards = function () {\r
620                     if (this.maxVisibleIndex >= $scope.boardsMasterArray.length) {\r
621                         this.maxVisibleIndex = $scope.boardsMasterArray.length - 1;\r
622                     }\r
623 \r
624                     if (this.maxVisibleIndex < 0) {\r
625                         this.maxVisibleIndex = 0;\r
626                     }\r
627                 };\r
628 \r
629                 this.resetBoardStrip = function () {\r
630                     $scope.currentIndex = 0;\r
631 \r
632                     this.maxVisibleIndex = BoardStripConfig.maxVisibleBoards - 1;\r
633                     this.minVisibleIndex = 0;\r
634 \r
635                     this.rectifyMaxVisibleBoards();\r
636                 };\r
637 \r
638                 this.getCurrentIndex = function () {\r
639                     return $scope.currentIndex;\r
640                 };\r
641                 this.setCurrentIndex = function (indx) {\r
642                     $scope.currentIndex = indx;\r
643                 };\r
644 \r
645                 this.getBoardsMasterArrayLength = function () {\r
646                     return $scope.boardsMasterArray.length;\r
647                 };\r
648 \r
649                 $scope.addBoardPressedFlag = false;\r
650                 this.getAddBoardPressedFlag = function () {\r
651                     return $scope.addBoardPressedFlag;\r
652                 };\r
653                 this.setAddBoardPressedFlag = function (booleanValue) {\r
654                     $scope.addBoardPressedFlag = booleanValue;\r
655                 };\r
656 \r
657             },\r
658             link: function (scope, element, attrs, ctrls) {\r
659 \r
660                 var ngModelCtrl = ctrls[0];\r
661                 var ctrl = ctrls[1];\r
662 \r
663                 var oldTimeout;\r
664                 var animationTimeout = 1000;\r
665 \r
666                 var getBoardViewportWidth = function (numberOfVisibleBoards) {\r
667                     return numberOfVisibleBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);\r
668                 };\r
669                 if (element[0].querySelector(".board-viewport")) {\r
670                     angular.element(element[0].querySelector(".board-viewport")).css({\r
671                         "width": getBoardViewportWidth(BoardStripConfig.maxVisibleBoards) + "px"\r
672                     });\r
673                 }\r
674 \r
675                 var getBoardstripContainerWidth = function (totalNumberOfBoards) {\r
676                     return totalNumberOfBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);\r
677                 };\r
678                 if (element[0].querySelector(".boardstrip-container")) {\r
679                     angular.element(element[0].querySelector(".boardstrip-container")).css({\r
680                         "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"\r
681                     });\r
682                     angular.element(element[0].querySelector(".boardstrip-container")).css({\r
683                         "left": "0px"\r
684                     });\r
685                 }\r
686 \r
687                 var calculateAndGetBoardstripContainerAdjustment = function () {\r
688 \r
689                     var calculatedAdjustmentValue;\r
690 \r
691                     if (ctrl.getBoardsMasterArrayLength() <= BoardStripConfig.maxVisibleBoards) {\r
692                         calculatedAdjustmentValue = 0;\r
693                     } else {\r
694                         calculatedAdjustmentValue = (ctrl.minVisibleIndex * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin)) * -1;\r
695                     }\r
696 \r
697                     return calculatedAdjustmentValue;\r
698                 };\r
699 \r
700                 var animateBoardstripContainerAdjustment = function (elementToFocusAfterAnimation) {\r
701                     var oldContainerAdjustment = angular.element(element[0].querySelector(".boardstrip-container"))[0].style.left;\r
702                     var containerAdjustment = calculateAndGetBoardstripContainerAdjustment();\r
703                     if (oldContainerAdjustment !== containerAdjustment + 'px') {\r
704                         angular.element(element[0].querySelector(".boardstrip-container")).css({\r
705                             "left": containerAdjustment + "px"\r
706                         });\r
707 \r
708                         $timeout.cancel(oldTimeout);\r
709                         oldTimeout = $timeout(function () {\r
710                             elementToFocusAfterAnimation.focus();\r
711                         }, animationTimeout);\r
712                     } else {\r
713                         elementToFocusAfterAnimation.focus();\r
714                     }\r
715                 };\r
716 \r
717                 var updateBoardsTabIndex = function (boardArray, minViewIndex, maxViewIndex) {\r
718                     for (var i = 0; i < boardArray.length; i++) {\r
719                         angular.element(boardArray[i]).attr('tabindex', '-1');\r
720                     }\r
721                     for (var j = minViewIndex; j <= maxViewIndex; j++) {\r
722                         angular.element(boardArray[j]).attr('tabindex', '0');\r
723                     }\r
724                 };\r
725 \r
726                 $timeout(function () {\r
727                     var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
728                     updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
729                 });\r
730 \r
731                 scope.$watchCollection('boardsMasterArray', function (newVal, oldVal) {\r
732                     if (newVal !== oldVal) {\r
733                         /* When a board is removed */\r
734                         if (newVal.length < oldVal.length) {\r
735                             ctrl.resetBoardStrip();\r
736                             $timeout(function () {\r
737 \r
738                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
739                                 if (currentBoardArray.length !== 0) {\r
740                                     animateBoardstripContainerAdjustment(currentBoardArray[0]);\r
741                                 } else {\r
742                                     element[0].querySelector('div.boardstrip-item--add').focus();\r
743                                 }\r
744 \r
745                                 angular.element(element[0].querySelector(".boardstrip-container")).css({\r
746                                     "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"\r
747                                 });\r
748                                 /* Update tabindecies to ensure keyboard navigation behaves correctly */\r
749                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
750                             });\r
751                         }\r
752                         /* When a board is added */\r
753                         else {\r
754                             if (ctrl.getAddBoardPressedFlag()) {\r
755                                 ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;\r
756                                 ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);\r
757 \r
758                                 ctrl.setCurrentIndex(ctrl.maxVisibleIndex);\r
759 \r
760                                 $timeout(function () {\r
761                                     angular.element(element[0].querySelector(".boardstrip-container")).css({\r
762                                         "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"\r
763                                     });\r
764 \r
765                                     var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
766                                     animateBoardstripContainerAdjustment(currentBoardArray[currentBoardArray.length - 1]);\r
767                                     /* Update tabindecies to ensure keyboard navigation behaves correctly */\r
768                                     updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
769                                 });\r
770                             } else {\r
771                                 if (ctrl.minVisibleIndex === 0 && ctrl.getBoardsMasterArrayLength() < BoardStripConfig.maxVisibleBoards + 1) {\r
772                                     ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;\r
773                                     ctrl.rectifyMaxVisibleBoards();\r
774                                 }\r
775 \r
776                                 $timeout(function () {\r
777                                     angular.element(element[0].querySelector(".boardstrip-container")).css({\r
778                                         "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"\r
779                                     });\r
780 \r
781                                     var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
782                                     /* Update tabindecies to ensure keyboard navigation behaves correctly */\r
783                                     updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
784                                 });\r
785                             }\r
786 \r
787                             ctrl.setAddBoardPressedFlag(false);\r
788                         }\r
789                     }\r
790                 });\r
791 \r
792                 scope.nextBoard = function () {\r
793                     ctrl.maxVisibleIndex += BoardStripConfig.boardsToScroll;\r
794                     ctrl.rectifyMaxVisibleBoards();\r
795                     ctrl.minVisibleIndex = ctrl.maxVisibleIndex - (BoardStripConfig.maxVisibleBoards - 1);\r
796 \r
797                     $timeout.cancel(oldTimeout);\r
798                     angular.element(element[0].querySelector(".boardstrip-container")).css({\r
799                         "left": calculateAndGetBoardstripContainerAdjustment() + "px"\r
800                     });\r
801 \r
802                     $timeout(function () {\r
803                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
804 \r
805                         /* Remove tabindex from non-visible boards */\r
806                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
807 \r
808                         if (!(scope.isNextBoard())) {\r
809                             try {\r
810                                 currentBoardArray[currentBoardArray.length - 1].focus();\r
811                             } catch (e) { /* IE8 may throw exception */ }\r
812                         }\r
813                     }, animationTimeout);\r
814                 };\r
815                 scope.prevBoard = function () {\r
816 \r
817                     ctrl.minVisibleIndex -= BoardStripConfig.boardsToScroll;\r
818                     if (ctrl.minVisibleIndex < 0) {\r
819                         ctrl.minVisibleIndex = 0;\r
820                     }\r
821 \r
822                     ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards - 1;\r
823                     ctrl.rectifyMaxVisibleBoards();\r
824 \r
825                     $timeout.cancel(oldTimeout);\r
826                     angular.element(element[0].querySelector(".boardstrip-container")).css({\r
827                         "left": calculateAndGetBoardstripContainerAdjustment() + "px"\r
828                     });\r
829 \r
830                     $timeout(function () {\r
831                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
832 \r
833                         /* Remove tabindex from non-visible boards */\r
834                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
835 \r
836                         if (ctrl.minVisibleIndex === 0) {\r
837                             try {\r
838                                 element[0].querySelector('div.boardstrip-item--add').focus();\r
839                             } catch (e) { /* IE8 may throw exception */ }\r
840                         }\r
841                     });\r
842                 };\r
843 \r
844                 scope.isPrevBoard = function () {\r
845                     return (ctrl.minVisibleIndex > 0);\r
846                 };\r
847                 scope.isNextBoard = function () {\r
848                     return (ctrl.getBoardsMasterArrayLength() - 1 > ctrl.maxVisibleIndex);\r
849                 };\r
850 \r
851                 ngModelCtrl.$render = function () {\r
852                     if (ngModelCtrl.$viewValue || ngModelCtrl.$viewValue === 0) {\r
853                         var newCurrentIndex = ngModelCtrl.$viewValue;\r
854 \r
855                         if (!(newCurrentIndex = parseInt(newCurrentIndex, 10))) {\r
856                             newCurrentIndex = 0;\r
857                         }\r
858 \r
859                         if (newCurrentIndex <= 0) {\r
860                             ctrl.resetBoardStrip();\r
861                             newCurrentIndex = 0;\r
862 \r
863                             var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
864                             if (currentBoardArray.length !== 0) {\r
865                                 animateBoardstripContainerAdjustment(currentBoardArray[0]);\r
866                             } else {\r
867                                 element[0].querySelector('div.boardstrip-item--add').focus();\r
868                             }\r
869                             /* Update tabindecies to ensure keyboard navigation behaves correctly */\r
870                             updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
871                         } else if (newCurrentIndex >= ctrl.getBoardsMasterArrayLength()) {\r
872                             ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;\r
873                             ctrl.rectifyMaxVisibleBoards();\r
874                             ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);\r
875 \r
876                             newCurrentIndex = ctrl.maxVisibleIndex;\r
877 \r
878                             $timeout(function () {\r
879                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
880                                 animateBoardstripContainerAdjustment(currentBoardArray[newCurrentIndex]);\r
881                                 /* Update tabindecies to ensure keyboard navigation behaves correctly */\r
882                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
883                             });\r
884                         } else {\r
885 \r
886                             if (!(newCurrentIndex >= ctrl.minVisibleIndex && newCurrentIndex <= ctrl.maxVisibleIndex)) {\r
887                                 ctrl.minVisibleIndex = newCurrentIndex;\r
888                                 ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards - 1;\r
889                                 ctrl.rectifyMaxVisibleBoards();\r
890 \r
891                                 if (ctrl.getBoardsMasterArrayLength() < BoardStripConfig.maxVisibleBoards) {\r
892                                     ctrl.minVisibleIndex = 0;\r
893                                 } else {\r
894                                     ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);\r
895                                 }\r
896 \r
897                                 $timeout(function () {\r
898                                     var currentBoardArray = element[0].querySelectorAll('[b2b-board]');\r
899                                     animateBoardstripContainerAdjustment(currentBoardArray[newCurrentIndex]);\r
900                                     /* Update tabindecies to ensure keyboard navigation behaves correctly */\r
901                                     updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);\r
902                                 });\r
903                             }\r
904                         }\r
905                         scope.currentIndex = newCurrentIndex;\r
906                         ngModelCtrl.$setViewValue(newCurrentIndex);\r
907                     } else {\r
908                         ctrl.resetBoardStrip();\r
909                         ngModelCtrl.$setViewValue(0);\r
910                     }\r
911                 };\r
912 \r
913                 scope.$watch('currentIndex', function (newVal, oldVal) {\r
914                     if (newVal !== oldVal && ngModelCtrl && ngModelCtrl.$viewValue !== newVal) {\r
915                         ngModelCtrl.$setViewValue(newVal);\r
916                     }\r
917                 });\r
918             }\r
919         };\r
920     }])\r
921     .directive('b2bAddBoard', ['BoardStripConfig', '$parse', function (BoardStripConfig, $parse) {\r
922         return {\r
923             restrict: 'AE',\r
924             replace: true,\r
925             require: '^b2bBoardStrip',\r
926             scope: {\r
927                 onAddBoard: '&?'\r
928             },\r
929             templateUrl: 'b2bTemplate/boardstrip/b2bAddBoard.html',\r
930             link: function (scope, element, attrs, ctrl) {\r
931                 scope.addBoard = function () {\r
932                     if (attrs['onAddBoard']) {\r
933                         scope.onAddBoard = $parse(scope.onAddBoard);\r
934                         scope.onAddBoard();\r
935                         ctrl.setAddBoardPressedFlag(true);\r
936                     }\r
937                 };\r
938             }\r
939         };\r
940     }])\r
941     .directive('b2bBoardNavigation', ['keymap', 'events', function (keymap, events) {\r
942         return {\r
943             restrict: 'AE',\r
944             link: function (scope, elem) {\r
945 \r
946                 var prevElem = keymap.KEY.LEFT;\r
947                 var nextElem = keymap.KEY.RIGHT;\r
948 \r
949                 elem.bind('keydown', function (ev) {\r
950 \r
951                     if (!(ev.keyCode)) {\r
952                         ev.keyCode = ev.which;\r
953                     }\r
954 \r
955                     switch (ev.keyCode) {\r
956                     case nextElem:\r
957                         events.preventDefault(ev);\r
958                         events.stopPropagation(ev);\r
959 \r
960                         if (elem[0].nextElementSibling && parseInt(angular.element(elem[0].nextElementSibling).attr('tabindex')) >= 0) {\r
961                             angular.element(elem[0])[0].nextElementSibling.focus();\r
962                         } else {\r
963                             /* IE8 fix */\r
964                             var el = angular.element(elem[0])[0];\r
965                             do {\r
966                                 if (el.nextSibling) {\r
967                                     el = el.nextSibling;\r
968                                 } else {\r
969                                     break;\r
970                                 }\r
971                             } while (el && el.tagName !== 'LI');\r
972 \r
973                             if (el.tagName && el.tagName === 'LI' && parseInt(angular.element(el).attr('tabindex')) >= 0) {\r
974                                 el.focus();\r
975                             }\r
976                         }\r
977 \r
978                         break;\r
979                     case prevElem:\r
980                         events.preventDefault(ev);\r
981                         events.stopPropagation(ev);\r
982 \r
983                         if (elem[0].previousElementSibling && parseInt(angular.element(elem[0].previousElementSibling).attr('tabindex')) >= 0) {\r
984                             angular.element(elem[0])[0].previousElementSibling.focus();\r
985                         } else {\r
986                             /* IE8 fix */\r
987                             var el1 = angular.element(elem[0])[0];\r
988                             do {\r
989                                 if (el1.previousSibling) {\r
990                                     el1 = el1.previousSibling;\r
991                                 } else {\r
992                                     break;\r
993                                 }\r
994                             } while (el1 && el1.tagName !== 'LI');\r
995 \r
996                             if (el1.tagName && el1.tagName === 'LI' && parseInt(angular.element(el1).attr('tabindex')) >= 0) {\r
997                                 el1.focus();\r
998                             }\r
999                         }\r
1000                         break;\r
1001                     default:\r
1002                         break;\r
1003                     }\r
1004                 });\r
1005             }\r
1006         };\r
1007     }]);\r
1008 /**\r
1009  * @ngdoc directive\r
1010  * @name Navigation.att:breadcrumbs\r
1011  *\r
1012  * @description\r
1013  *  <file src="src/breadcrumbs/docs/readme.md" />\r
1014  * @usage\r
1015     <ul class="breadcrumb">\r
1016         <li ng-repeat="link in breadCrumbsLink"><a tabindex="{{(idx==$index)?-1:0}}" href='javascript:void(0)' ng-click="clickActive($index)" ng-class="{'active':idx==$index, '': idx!=$index}">{{link.title}}</a></li>\r
1017     </ul>\r
1018  * @example\r
1019  <example module="b2b.att">\r
1020  <file src="src/breadcrumbs/docs/demo.html" />\r
1021  <file src="src/breadcrumbs/docs/demo.js" />\r
1022  </example>\r
1023  */\r
1024 angular.module('b2b.att.breadcrumbs',[])\r
1025 /**\r
1026  * @ngdoc directive\r
1027  * @name Buttons, links & UI controls.att:buttonGroups\r
1028  *\r
1029  * @description\r
1030  *  <file src="src/buttonGroups/docs/readme.md" />\r
1031  *\r
1032  * @usage\r
1033 <h2>Radio Aproach</h2>\r
1034 <div class="btn-group" b2b-key prev="37,38" next="39,40" circular-traversal role="radiogroup">\r
1035     <button type="button" class="btn btn-secondary" b2b-key-item ng-focus="radioModel='Button 1'" ng-model="radioModel" b2b-btn-radio="'Button 1'" tabindex="{{(!radioModel || 'Button 1'===radioModel)?0:-1}}">Button 1</button>\r
1036     <button type="button" class="btn btn-secondary" b2b-key-item ng-focus="radioModel='Button 2'" ng-model="radioModel" b2b-btn-radio="'Button 2'" tabindex="{{(!radioModel || 'Button 2'===radioModel)?0:-1}}">Button 2</button>\r
1037     <button type="button" class="btn btn-secondary" b2b-key-item ng-focus="radioModel='Button 3'" ng-model="radioModel" b2b-btn-radio="'Button 3'" tabindex="{{(!radioModel || 'Button 3'===radioModel)?0:-1}}">Button 3</button>\r
1038 </div>\r
1039 \r
1040 <h2>Checkbox Aproach</h2>\r
1041 <span b2b-button-group class="btn-group btn-fullwidth" role="group" max-select="3" ng-model="checkModel1">\r
1042     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button1" b2b-btn-checkbox>Button1</button>\r
1043     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button2" b2b-btn-checkbox>Button2</button>\r
1044     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button3" b2b-btn-checkbox>Button3</button>\r
1045     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button4" b2b-btn-checkbox>Button4</button>\r
1046     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button5" b2b-btn-checkbox>Button5</button>\r
1047 </span>\r
1048  *\r
1049  * @example\r
1050  *  <section id="code">\r
1051         <example module="b2b.att">\r
1052             <file src="src/buttonGroups/docs/demo.html" />\r
1053             <file src="src/buttonGroups/docs/demo.js" />\r
1054        </example>\r
1055         </section>\r
1056  *\r
1057  */\r
1058 angular.module('b2b.att.buttonGroups', ['b2b.att.utilities'])\r
1059     .constant('buttonConfig', {\r
1060         activeClass: 'active',\r
1061         toggleEvent: 'click'\r
1062     })\r
1063     .directive('b2bBtnRadio', ['buttonConfig', function (buttonConfig) {\r
1064         var activeClass = buttonConfig.activeClass || 'active';\r
1065         var toggleEvent = buttonConfig.toggleEvent || 'click';\r
1066 \r
1067         return {\r
1068             require: 'ngModel',\r
1069             link: function (scope, element, attrs, ngModelCtrl) {\r
1070                 var notMobile = !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\r
1071 \r
1072                 if (notMobile) {\r
1073                     element.bind('focus', function () {\r
1074                         scope.$apply(function () {\r
1075                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));\r
1076                             ngModelCtrl.$render();\r
1077                         });\r
1078                     });\r
1079                 }\r
1080 \r
1081                 element.attr('role', 'radio');\r
1082 \r
1083                 //model -> UI\r
1084                 ngModelCtrl.$render = function () {\r
1085                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio)));\r
1086                     if (angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio))) {\r
1087                         element.attr("aria-checked", true);\r
1088                     } else {\r
1089                         element.attr("aria-checked", false);\r
1090                     }\r
1091                 };\r
1092 \r
1093                 //ui->model\r
1094                 element.bind(toggleEvent, function () {\r
1095                     if (!element.hasClass(activeClass)) {\r
1096                         scope.$apply(function () {\r
1097                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));\r
1098                             ngModelCtrl.$render();\r
1099                         });\r
1100                     }\r
1101                 });\r
1102             }\r
1103         };\r
1104     }])\r
1105     .directive('b2bBtnCheckbox', ['buttonConfig', function (buttonConfig) {\r
1106         var activeClass = buttonConfig.activeClass || 'active';\r
1107         var toggleEvent = buttonConfig.toggleEvent || 'click';\r
1108 \r
1109         return {\r
1110             require: ['ngModel', '^^b2bButtonGroup'],\r
1111             link: function (scope, element, attrs, ctrls) {\r
1112 \r
1113                 var ngModelCtrl = ctrls[0];\r
1114                 var parentCtrl = ctrls[1];\r
1115 \r
1116                 element.attr('role', 'checkbox');\r
1117                 element.attr('aria-describedby', parentCtrl.getStateDescriptionElemId());\r
1118 \r
1119                 function getTrueValue() {\r
1120                     var trueValue = scope.$eval(attrs.b2bBtnCheckboxTrue);\r
1121                     return angular.isDefined(trueValue) ? trueValue : true;\r
1122                 }\r
1123 \r
1124                 function getFalseValue() {\r
1125                     var falseValue = scope.$eval(attrs.b2bBtnCheckboxFalse);\r
1126                     return angular.isDefined(falseValue) ? falseValue : false;\r
1127                 }\r
1128 \r
1129                 //model -> UI\r
1130                 ngModelCtrl.$render = function () {\r
1131                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));\r
1132                     if ((angular.equals(ngModelCtrl.$modelValue, getTrueValue()))) {\r
1133                         element.attr("aria-checked", true);\r
1134                     } else {\r
1135                         element.attr("aria-checked", false);\r
1136                     }\r
1137                 };\r
1138 \r
1139                 //ui->model\r
1140                 element.bind(toggleEvent, function () {\r
1141                     scope.$apply(function () {\r
1142                         ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? getFalseValue() : getTrueValue());\r
1143                         ngModelCtrl.$render();\r
1144                     });\r
1145                 });\r
1146             }\r
1147         };\r
1148     }])\r
1149     .directive('b2bButtonGroup', ['$timeout', '$compile', function ($timeout, $compile) {\r
1150         return {\r
1151             restrict: 'A',\r
1152             scope: {\r
1153                 maxSelect: "=",\r
1154                 ngModelButtonState: '=ngModel'\r
1155             },\r
1156             controller: ['$scope', '$element', function ($scope, $element) {\r
1157                 $scope.nSel = 0;\r
1158 \r
1159                 var stateDescriptionElem = angular.element('<span id="b2b_button_group_' + $scope.$id + '" class="hide" aria-hidden="true">{{nSel}} of {{maxSelect}} options selected.</span>');\r
1160                 $compile(stateDescriptionElem)($scope);\r
1161                 $element.after(stateDescriptionElem);\r
1162 \r
1163                 this.getStateDescriptionElemId = function () {\r
1164                     return stateDescriptionElem.attr('id');\r
1165                 };\r
1166             }],\r
1167             link: function (scope, element) {\r
1168 \r
1169 \r
1170                 var executeFxn = function () {\r
1171                     scope.nSel = 0;\r
1172                     angular.forEach(scope.ngModelButtonState, function (value, key) {\r
1173                         if (value === true) {\r
1174                             scope.nSel += 1;\r
1175                         }\r
1176                     });\r
1177 \r
1178                     if (scope.nSel >= scope.maxSelect) {\r
1179                         angular.forEach(element.children(), function (chd) {\r
1180                             if (chd.className.indexOf('active') < 0) {\r
1181                                 chd.disabled = true;\r
1182                                 chd.setAttribute('aria-disabled', true);\r
1183                             }\r
1184                         });\r
1185                     } else {\r
1186                         angular.forEach(element.children(), function (chd) {\r
1187                             chd.disabled = false;\r
1188                             chd.setAttribute('aria-disabled', false);\r
1189                         });\r
1190                     }\r
1191                     scope.$digest();\r
1192                 };\r
1193 \r
1194                 $timeout(function () {\r
1195                     executeFxn();\r
1196                 });\r
1197                 element.bind('click', executeFxn);\r
1198             }\r
1199         };\r
1200     }]);\r
1201 /**\r
1202  * @ngdoc directive\r
1203  * @name Buttons, links & UI controls.att:buttons\r
1204  * @element input\r
1205  * @function\r
1206  *\r
1207  * @description\r
1208  *  <file src="src/buttons/docs/readme.md" />\r
1209  * @usage\r
1210  *\r
1211 Button shape\r
1212 <button class="btn" type="button">Button</button> button.btn (button shape only)\r
1213 <button aria-label="Custom aria label" class="btn" type="button">Button</button> button.btn (button shape only) with custom aria label\r
1214 <button aria-label="Click on button/Press enter" class="btn" type="button" onclick="javascript:alert('It works!');">Click on button/Press enter</button> button.btn with click functionality\r
1215 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn" role="button">Button</a> a.btn (button shape only)\r
1216 <button class="btn btn-primary">Button</button> .btn-primary\r
1217 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-primary" role="button">Button</a> a.btn-primary\r
1218 \r
1219 5 Button colors\r
1220 <button class="btn btn-secondary">Button</button> .btn-secondary\r
1221 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-secondary" role="button">Button</a> a.btn-secondary\r
1222 <button class="btn btn-alt">Button</button> .btn-alt\r
1223 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-alt" role="button">Button</a> a.btn-alt\r
1224 <button class="btn btn-specialty">Button</button> .btn-specialty\r
1225 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-specialty" role="button">Button</a> a.btn-specialty\r
1226 <button class="btn btn-specialty" disabled="">Button</button> disabled="disabled"\r
1227 <a b2b-keyup-click="32" aria-disabled="true" href="javascript:void(0)" class="btn btn-primary disabled" role="button">Button</a> a.disabled\r
1228 \r
1229 3 button heights\r
1230 <button class="btn btn-secondary">Button</button> .btn is default and 46px height\r
1231 <button class="btn btn-secondary btn-medium">Button</button> .btn-medium is 42px\r
1232 <button class="btn btn-secondary btn-small">Button</button> .btn-small is 36px\r
1233 \r
1234 .row-nowrap 2 up buttons\r
1235 <div class="row-nowrap">\r
1236     <button class="btn btn-secondary btn-fullwidth" type="button">Cancel</button>\r
1237     <button class="btn btn-primary btn-fullwidth" type="button">Continue</button>\r
1238 </div>\r
1239 \r
1240 .row 2 up buttons (desktop) stacked (mobile) (different order)\r
1241 <div class="row cta-button-group">\r
1242     <button class="span btn btn-secondary btn-fullwidth hidden-phone" type="button">Cancel</button>\r
1243     <button class="span btn btn-primary btn-fullwidth" type="button">Continue</button>\r
1244     <button class="span btn btn-secondary btn-fullwidth visible-phone" type="button">Cancel</button>\r
1245 </div>\r
1246 \r
1247  * @example\r
1248  *  <section id="code">\r
1249                <b>HTML + AngularJS</b>\r
1250  *              <example module="b2b.att">\r
1251  *              <file src="src/buttons/docs/demo.html" />\r
1252                  <file src="src/buttons/docs/demo.js" />\r
1253  *              </example>\r
1254             </section>\r
1255  *\r
1256  */\r
1257 angular.module('b2b.att.buttons', ['b2b.att.utilities']);\r
1258 /**\r
1259  * @ngdoc directive\r
1260  * @name Forms.att:calendar\r
1261  *\r
1262  * @description\r
1263  *  <file src="src/calendar/docs/readme.md" />\r
1264  * @usage\r
1265  *  <input type="text" ng-model="dt" b2b-datepicker>\r
1266  *\r
1267  * @example\r
1268    <section id="code">\r
1269     <b>HTML + AngularJS</b>\r
1270     <example module="b2b.att">\r
1271      <file src="src/calendar/docs/demo.html" />\r
1272      <file src="src/calendar/docs/demo.js" />\r
1273     </example>\r
1274    </section>\r
1275  */\r
1276 angular.module('b2b.att.calendar', ['b2b.att.position', 'b2b.att.utilities'])\r
1277 \r
1278 .constant('b2bDatepickerConfig', {\r
1279     dateFormat: 'MM/dd/yyyy',\r
1280     dayFormat: 'd',\r
1281     monthFormat: 'MMMM',\r
1282     yearFormat: 'yyyy',\r
1283     dayHeaderFormat: 'EEEE',\r
1284     dayTitleFormat: 'MMMM yyyy',\r
1285     disableWeekend: false,\r
1286     disableSunday: false,\r
1287     disableDates: null,\r
1288     onSelectClose: null,\r
1289     startingDay: 0,\r
1290     minDate: null,\r
1291     maxDate: null,\r
1292     dueDate: null,\r
1293     fromDate: null,\r
1294     legendIcon: null,\r
1295     legendMessage: null,\r
1296     calendarDisabled: false,\r
1297     collapseWait: 0,\r
1298     orientation: 'left',\r
1299     inline: false,\r
1300     helperText: 'The date you selected is $date. In case of mobile double tap to open calendar. Select a date to close the calendar.',\r
1301     datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation'],\r
1302     datepickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],\r
1303     datepickerFunctionAttributes: ['disableDates', 'onSelectClose']\r
1304 })\r
1305 \r
1306 .factory('b2bDatepickerService', ['b2bDatepickerConfig', 'dateFilter', function (b2bDatepickerConfig, dateFilter) {\r
1307     var setAttributes = function (attr, elem) {\r
1308         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {\r
1309             var attributes = b2bDatepickerConfig.datepickerEvalAttributes.concat(b2bDatepickerConfig.datepickerWatchAttributes, b2bDatepickerConfig.datepickerFunctionAttributes);\r
1310             for (var key in attr) {\r
1311                 var val = attr[key];\r
1312                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
1313                     elem.attr(key.toSnakeCase(), key);\r
1314                 }\r
1315             }\r
1316         }\r
1317     };\r
1318 \r
1319     var bindScope = function (attr, scope) {\r
1320         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {\r
1321             var evalFunction = function (key, val) {\r
1322                 scope[key] = scope.$parent.$eval(val);\r
1323             };\r
1324 \r
1325             var watchFunction = function (key, val) {\r
1326                 scope.$parent.$watch(val, function (value) {\r
1327                     scope[key] = value;\r
1328                 });\r
1329                 scope.$watch(key, function (value) {\r
1330                     scope.$parent[val] = value;\r
1331                 });\r
1332             };\r
1333 \r
1334             var evalAttributes = b2bDatepickerConfig.datepickerEvalAttributes;\r
1335             var watchAttributes = b2bDatepickerConfig.datepickerWatchAttributes;\r
1336             for (var key in attr) {\r
1337                 var val = attr[key];\r
1338                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
1339                     evalFunction(key, val);\r
1340                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
1341                     watchFunction(key, val);\r
1342                 }\r
1343             }\r
1344         }\r
1345     };\r
1346 \r
1347     return {\r
1348         setAttributes: setAttributes,\r
1349         bindScope: bindScope\r
1350     };\r
1351 }])\r
1352 \r
1353 .controller('b2bDatepickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bDatepickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {\r
1354     var format = {\r
1355             date: getValue($attrs.dateFormat, dtConfig.dateFormat),\r
1356             day: getValue($attrs.dayFormat, dtConfig.dayFormat),\r
1357             month: getValue($attrs.monthFormat, dtConfig.monthFormat),\r
1358             year: getValue($attrs.yearFormat, dtConfig.yearFormat),\r
1359             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),\r
1360             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),\r
1361             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),\r
1362             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday),\r
1363             disableDates: getValue($attrs.disableDates, dtConfig.disableDates)\r
1364         },\r
1365         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);\r
1366 \r
1367     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;\r
1368     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;\r
1369     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;\r
1370     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;\r
1371     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;\r
1372     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;\r
1373     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;\r
1374     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);\r
1375     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);\r
1376     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);\r
1377 \r
1378     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;\r
1379 \r
1380     function getValue(value, defaultValue) {\r
1381         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;\r
1382     }\r
1383 \r
1384     function getDaysInMonth(year, month) {\r
1385         return new Date(year, month, 0).getDate();\r
1386     }\r
1387 \r
1388     function getDates(startDate, n) {\r
1389         var dates = new Array(n);\r
1390         var current = startDate,\r
1391             i = 0;\r
1392         while (i < n) {\r
1393             dates[i++] = new Date(current);\r
1394             current.setDate(current.getDate() + 1);\r
1395         }\r
1396         return dates;\r
1397     }\r
1398 \r
1399     this.updatePosition = function (b2bDatepickerPopupTemplate) {\r
1400         $scope.position = $position.offset($element);\r
1401         $scope.position.top = $scope.position.top + $element.find('input').prop('offsetHeight');\r
1402         if ($scope.orientation === 'right') {\r
1403             $scope.position.left = $scope.position.left - (((b2bDatepickerPopupTemplate && b2bDatepickerPopupTemplate.prop('offsetWidth')) || 290) - $element.find('input').prop('offsetWidth'));\r
1404         }\r
1405     };\r
1406 \r
1407     function isSelected(dt) {\r
1408         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {\r
1409             return true;\r
1410         }\r
1411         return false;\r
1412     }\r
1413 \r
1414     function isFromDate(dt) {\r
1415         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {\r
1416             return true;\r
1417         }\r
1418         return false;\r
1419     }\r
1420 \r
1421     function isDateRange(dt) {\r
1422         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {\r
1423             return true;\r
1424         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {\r
1425             return true;\r
1426         }\r
1427         return false;\r
1428     }\r
1429 \r
1430     function isOld(date, currentMonthDate) {\r
1431         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() < new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {\r
1432             return true;\r
1433         } else {\r
1434             return false;\r
1435         }\r
1436     }\r
1437 \r
1438     function isNew(date, currentMonthDate) {\r
1439         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() > new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {\r
1440             return true;\r
1441         } else {\r
1442             return false;\r
1443         }\r
1444     }\r
1445 \r
1446     function isPastDue(dt) {\r
1447         if ($scope.dueDate) {\r
1448             return (dt > $scope.dueDate);\r
1449         }\r
1450         return false;\r
1451     }\r
1452 \r
1453     function isDueDate(dt) {\r
1454         if ($scope.dueDate) {\r
1455             return (dt.getTime() === $scope.dueDate.getTime());\r
1456         }\r
1457         return false;\r
1458     }\r
1459 \r
1460     var isDisabled = function (date, currentMonthDate) {\r
1461         if ($attrs.from && !angular.isDate($scope.fromDate)) {\r
1462             return true;\r
1463         }\r
1464         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {\r
1465             return true;\r
1466         }\r
1467         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {\r
1468             return true;\r
1469         }\r
1470         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {\r
1471             return true;\r
1472         }\r
1473         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({\r
1474             date: date\r
1475         })));\r
1476     };\r
1477 \r
1478     var compare = function (date1, date2) {\r
1479         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));\r
1480     };\r
1481 \r
1482     function isMinDateAvailable(startDate, endDate) {\r
1483         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {\r
1484             $scope.disablePrev = true;\r
1485             $scope.visibilityPrev = "hidden";\r
1486         } else {\r
1487             $scope.disablePrev = false;\r
1488             $scope.visibilityPrev = "visible";\r
1489         }\r
1490     }\r
1491 \r
1492     function isMaxDateAvailable(startDate, endDate) {\r
1493         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {\r
1494             $scope.disableNext = true;\r
1495             $scope.visibilityNext = "hidden";\r
1496         } else {\r
1497             $scope.disableNext = false;\r
1498             $scope.visibilityNext = "visible";\r
1499         }\r
1500     }\r
1501 \r
1502     function getLabel(label) {\r
1503         if (label) {\r
1504             var labelObj = {\r
1505                 pre: label.substr(0, 1).toUpperCase(),\r
1506                 post: label\r
1507             };\r
1508             return labelObj;\r
1509         }\r
1510         return;\r
1511     }\r
1512 \r
1513     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {\r
1514         return {\r
1515             date: date,\r
1516             label: dateFilter(date, dayFormat),\r
1517             header: dateFilter(date, dayHeaderFormat),\r
1518             selected: !!isSelected,\r
1519             fromDate: !!isFromDate,\r
1520             dateRange: !!isDateRange,\r
1521             oldMonth: !!isOld,\r
1522             nextMonth: !!isNew,\r
1523             disabled: !!isDisabled,\r
1524             dueDate: !!dueDate,\r
1525             pastDue: !!pastDue,\r
1526             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))\r
1527         };\r
1528     }\r
1529 \r
1530     this.modes = [\r
1531         {\r
1532             name: 'day',\r
1533             getVisibleDates: function (date) {\r
1534                 var year = date.getFullYear(),\r
1535                     month = date.getMonth(),\r
1536                     firstDayOfMonth = new Date(year, month, 1),\r
1537                     lastDayOfMonth = new Date(year, month + 1, 0);\r
1538                 var difference = startingDay - firstDayOfMonth.getDay(),\r
1539                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,\r
1540                     firstDate = new Date(firstDayOfMonth),\r
1541                     numDates = 0;\r
1542 \r
1543                 if (numDisplayedFromPreviousMonth > 0) {\r
1544                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);\r
1545                     numDates += numDisplayedFromPreviousMonth; // Previous\r
1546                 }\r
1547                 numDates += getDaysInMonth(year, month + 1); // Current\r
1548                 numDates += (7 - numDates % 7) % 7; // Next\r
1549 \r
1550                 var days = getDates(firstDate, numDates),\r
1551                     labels = new Array(7);\r
1552                 for (var i = 0; i < numDates; i++) {\r
1553                     var dt = new Date(days[i]);\r
1554                     days[i] = makeDate(dt,\r
1555                         format.day,\r
1556                         format.dayHeader,\r
1557                         isSelected(dt),\r
1558                         isFromDate(dt),\r
1559                         isDateRange(dt),\r
1560                         isOld(dt, date),\r
1561                         isNew(dt, date),\r
1562                         isDisabled(dt, date),\r
1563                         isDueDate(dt),\r
1564                         isPastDue(dt));\r
1565                 }\r
1566                 for (var j = 0; j < 7; j++) {\r
1567                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));\r
1568                 }\r
1569                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);\r
1570                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);\r
1571                 return {\r
1572                     objects: days,\r
1573                     title: dateFilter(date, format.dayTitle),\r
1574                     labels: labels\r
1575                 };\r
1576             },\r
1577             split: 7,\r
1578             step: {\r
1579                 months: 1\r
1580             }\r
1581         }\r
1582     ];\r
1583 }])\r
1584 \r
1585 .directive('b2bDatepickerPopup', ['$parse', '$log', '$timeout', '$document', '$documentBind', '$isElement', '$templateCache', '$compile', 'trapFocusInElement', '$position', '$window', function ($parse, $log, $timeout, $document, $documentBind, $isElement, $templateCache, $compile, trapFocusInElement, $position, $window) {\r
1586     return {\r
1587         restrict: 'EA',\r
1588         replace: true,\r
1589         transclude: true,\r
1590         templateUrl: function (elem, attr) {\r
1591             if (attr.inline === 'true') {\r
1592                 return 'b2bTemplate/calendar/datepicker-popup.html';\r
1593             } else {\r
1594                 return 'b2bTemplate/calendar/datepicker.html';\r
1595             }\r
1596         },\r
1597         scope: {},\r
1598         require: ['b2bDatepickerPopup', 'ngModel', '?^b2bDatepickerGroup'],\r
1599         controller: 'b2bDatepickerController',\r
1600         link: function (scope, element, attrs, ctrls) {\r
1601             var datepickerCtrl = ctrls[0],\r
1602                 ngModel = ctrls[1],\r
1603                 b2bDatepickerGroupCtrl = ctrls[2];\r
1604             var b2bDatepickerPopupTemplate;\r
1605 \r
1606             if (!ngModel) {\r
1607                 $log.error("ng-model is required.");\r
1608                 return; // do nothing if no ng-model\r
1609             }\r
1610 \r
1611             // Configuration parameters\r
1612             var mode = 0,\r
1613                 selected;\r
1614             scope.isOpen = false;\r
1615 \r
1616             scope.headers = [];\r
1617             scope.footers = [];\r
1618 \r
1619             if (b2bDatepickerGroupCtrl) {\r
1620                 b2bDatepickerGroupCtrl.registerDatepickerScope(scope);\r
1621             }\r
1622 \r
1623             element.find('button').bind('click', function () {\r
1624                 element.find('input')[0].click();\r
1625             });\r
1626 \r
1627             element.find('input').bind('click', function () {\r
1628                 if (!scope.ngDisabled) {\r
1629                     scope.isOpen = !scope.isOpen;\r
1630                     toggleCalendar(scope.isOpen);\r
1631                     scope.$apply();\r
1632                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);\r
1633                     $timeout(function () { \r
1634                         angular.element(element[0].querySelector('.datepicker-input')).scrollTop=0;\r
1635                     },10);\r
1636                 }\r
1637             });\r
1638             var toggleCalendar = function (flag) {\r
1639                 if (!scope.inline) {\r
1640                     if (flag) {\r
1641                         b2bDatepickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/calendar/datepicker-popup.html'));\r
1642                         b2bDatepickerPopupTemplate = $compile(b2bDatepickerPopupTemplate)(scope);\r
1643                         $document.find('body').append(b2bDatepickerPopupTemplate);\r
1644                         b2bDatepickerPopupTemplate.bind('keydown', keyPress);\r
1645                         $timeout(function () {\r
1646                             scope.getFocus = true;\r
1647                             trapFocusInElement(flag, b2bDatepickerPopupTemplate);\r
1648                             scope.$apply();\r
1649                             $timeout(function () {\r
1650                                 scope.getFocus = false; \r
1651                                 scope.$apply();\r
1652                             }, 100);\r
1653                         });\r
1654                     } else {\r
1655                         b2bDatepickerPopupTemplate.unbind('keydown', keyPress);\r
1656                         b2bDatepickerPopupTemplate.remove();\r
1657                         element.find('button')[0].focus();\r
1658                         scope.getFocus = false;\r
1659                         trapFocusInElement(flag, b2bDatepickerPopupTemplate);\r
1660                     }\r
1661                 }\r
1662             };\r
1663 \r
1664             var outsideClick = function (e) {\r
1665                 var isElement = $isElement(angular.element(e.target), element, $document);\r
1666                 var isb2bDatepickerPopupTemplate = $isElement(angular.element(e.target), b2bDatepickerPopupTemplate, $document);\r
1667                 if (!(isElement || isb2bDatepickerPopupTemplate)) {\r
1668                     scope.isOpen = false;\r
1669                     toggleCalendar(scope.isOpen);\r
1670                     scope.$apply();\r
1671                 }\r
1672             };\r
1673 \r
1674             var keyPress = function (ev) {\r
1675                 if (!ev.keyCode) {\r
1676                     if (ev.which) {\r
1677                         ev.keyCode = ev.which;\r
1678                     } else if (ev.charCode) {\r
1679                         ev.keyCode = ev.charCode;\r
1680                     }\r
1681                 }\r
1682                 if (ev.keyCode) {\r
1683                     if (ev.keyCode === 27) {\r
1684                         scope.isOpen = false;\r
1685                         toggleCalendar(scope.isOpen);\r
1686                         ev.preventDefault();\r
1687                         ev.stopPropagation();\r
1688                     } else if (ev.keyCode === 33) {\r
1689                         !scope.disablePrev && scope.move(-1);\r
1690                         $timeout(function () {\r
1691                             scope.getFocus = true;\r
1692                             scope.$apply();\r
1693                             $timeout(function () {\r
1694                                 scope.getFocus = false;\r
1695                                 scope.$apply();\r
1696                             }, 100);\r
1697                         });\r
1698                         ev.preventDefault();\r
1699                         ev.stopPropagation();\r
1700                     } else if (ev.keyCode === 34) {\r
1701                         !scope.disableNext && scope.move(1);\r
1702                         $timeout(function () {\r
1703                             scope.getFocus = true;\r
1704                             scope.$apply();\r
1705                             $timeout(function () {\r
1706                                 scope.getFocus = false;\r
1707                                 scope.$apply();\r
1708                             }, 100);\r
1709                         });\r
1710                         ev.preventDefault();\r
1711                         ev.stopPropagation();\r
1712                     }\r
1713                     scope.$apply();\r
1714                 }\r
1715             };\r
1716 \r
1717             $documentBind.click('isOpen', outsideClick, scope);\r
1718 \r
1719             var modalContainer = angular.element(document.querySelector('.modalwrapper'));\r
1720             var modalBodyContainer = angular.element(document.querySelector('.modal-body'));\r
1721             if (modalContainer) {\r
1722                 modalContainer.bind('scroll', function () {\r
1723                     if (b2bDatepickerPopupTemplate) {\r
1724                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);\r
1725                         scope.$apply();\r
1726                     }\r
1727                 });\r
1728             }\r
1729             if (modalBodyContainer) {\r
1730                 modalBodyContainer.bind('scroll', function () {\r
1731                     if (b2bDatepickerPopupTemplate) {\r
1732                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);\r
1733                         var datepickerTextfield = $position.offset(element.find('input'));\r
1734                         var modalBodyPosition = $position.offset(modalBodyContainer);\r
1735 \r
1736                         if (((datepickerTextfield.top + datepickerTextfield.height) < modalBodyPosition.top || datepickerTextfield.top > (modalBodyPosition.top + modalBodyPosition.height)) && scope.isOpen) {\r
1737                             scope.isOpen = false;\r
1738                             toggleCalendar(scope.isOpen);\r
1739                         }\r
1740                         scope.$apply();\r
1741                     }\r
1742                 });\r
1743             }\r
1744             var window = angular.element($window);\r
1745             window.bind('resize', function () {\r
1746                 if (b2bDatepickerPopupTemplate) {\r
1747                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);\r
1748                     scope.$apply();\r
1749                 }\r
1750             });\r
1751 \r
1752             scope.$on('$destroy', function () {\r
1753                 if (scope.isOpen) {\r
1754                     scope.isOpen = false;\r
1755                     toggleCalendar(scope.isOpen);\r
1756                 }\r
1757             });\r
1758 \r
1759             scope.resetTime = function (date) {\r
1760                 if (typeof date === 'string') {\r
1761                     date = date + 'T12:00:00';\r
1762                 }\r
1763                 var dt;\r
1764                 if (!isNaN(new Date(date))) {\r
1765                     dt = new Date(date);\r
1766                 } else {\r
1767                     return null;\r
1768                 }\r
1769                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());\r
1770             };\r
1771 \r
1772             if (attrs.min) {\r
1773                 scope.$parent.$watch($parse(attrs.min), function (value) {\r
1774                     scope.minDate = value ? scope.resetTime(value) : null;\r
1775                     refill();\r
1776                 });\r
1777             }\r
1778             if (attrs.max) {\r
1779                 scope.$parent.$watch($parse(attrs.max), function (value) {\r
1780                     scope.maxDate = value ? scope.resetTime(value) : null;\r
1781                     refill();\r
1782                 });\r
1783             }\r
1784             if (attrs.due) {\r
1785                 scope.$parent.$watch($parse(attrs.due), function (value) {\r
1786                     scope.dueDate = value ? scope.resetTime(value) : null;\r
1787                     refill();\r
1788                 });\r
1789             }\r
1790             if (attrs.from) {\r
1791                 scope.$parent.$watch($parse(attrs.from), function (value) {\r
1792                     scope.fromDate = value ? scope.resetTime(value) : null;\r
1793                     refill();\r
1794                 });\r
1795             }\r
1796 \r
1797             if (attrs.legendIcon) {\r
1798                 scope.$parent.$watch(attrs.legendIcon, function (value) {\r
1799                     scope.legendIcon = value ? value : null;\r
1800                     refill();\r
1801                 });\r
1802             }\r
1803             if (attrs.legendMessage) {\r
1804                 scope.$parent.$watch(attrs.legendMessage, function (value) {\r
1805                     scope.legendMessage = value ? value : null;\r
1806                     refill();\r
1807                 });\r
1808             }\r
1809             if (attrs.ngDisabled) {\r
1810                 scope.$parent.$watch(attrs.ngDisabled, function (value) {\r
1811                     scope.ngDisabled = value ? value : null;\r
1812                 });\r
1813             }\r
1814 \r
1815             // Split array into smaller arrays\r
1816             function split(arr, size) {\r
1817                 var arrays = [];\r
1818                 while (arr.length > 0) {\r
1819                     arrays.push(arr.splice(0, size));\r
1820                 }\r
1821                 return arrays;\r
1822             }\r
1823 \r
1824             function refill(date) {\r
1825                 if (angular.isDate(date) && !isNaN(date)) {\r
1826                     selected = new Date(date);\r
1827                 } else {\r
1828                     if (!selected) {\r
1829                         selected = new Date();\r
1830                     }\r
1831                 }\r
1832 \r
1833                 if (selected) {\r
1834                     var currentMode = datepickerCtrl.modes[mode],\r
1835                         data = currentMode.getVisibleDates(selected);\r
1836                     scope.rows = split(data.objects, currentMode.split);\r
1837                     var flag = false;\r
1838                     var startFlag = false;\r
1839                     var firstSelected = false;\r
1840                     for (var i = 0; i < scope.rows.length; i++) {\r
1841                         for (var j = 0; j < scope.rows[i].length; j++) {\r
1842 \r
1843                             if (scope.rows[i][j].label === "1" && !firstSelected) {\r
1844                                 firstSelected = true;\r
1845                                 var firstDay = scope.rows[i][j];\r
1846                             }\r
1847 \r
1848                             if (scope.rows[i][j].selected === true) {\r
1849                                 flag = true;\r
1850                                 break;\r
1851                             }\r
1852                         }\r
1853                         if (flag) {\r
1854                             break;\r
1855                         }\r
1856                     }\r
1857                     if (!flag) {\r
1858                         firstDay.firstFocus = true;\r
1859                     }\r
1860 \r
1861                     scope.labels = data.labels || [];\r
1862                     scope.title = data.title;\r
1863 \r
1864                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);\r
1865                 }\r
1866             }\r
1867 \r
1868             scope.select = function (date) {\r
1869                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());\r
1870                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({\r
1871                         date: dt\r
1872                     }) !== false)) {\r
1873                     scope.currentDate = dt;\r
1874                     if (angular.isNumber(scope.collapseWait)) {\r
1875                         $timeout(function () {\r
1876                             scope.isOpen = false;\r
1877                             toggleCalendar(scope.isOpen);\r
1878                         }, scope.collapseWait);\r
1879                     } else {\r
1880                         scope.isOpen = false;\r
1881                         toggleCalendar(scope.isOpen);\r
1882                     }\r
1883                 }\r
1884             };\r
1885 \r
1886             scope.move = function (direction,$event) {\r
1887                 var step = datepickerCtrl.modes[mode].step;\r
1888                 selected.setDate(1);\r
1889                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));\r
1890                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));\r
1891                 refill();\r
1892 \r
1893                 $timeout(function () {\r
1894                     trapFocusInElement();\r
1895                 }, 100);\r
1896 \r
1897                 $event.preventDefault();\r
1898                 $event.stopPropagation();\r
1899             };\r
1900 \r
1901             scope.trapFocus = function () {\r
1902                 $timeout(function () {\r
1903                     trapFocusInElement();\r
1904                 }, 100);\r
1905             };\r
1906 \r
1907             scope.$watch('currentDate', function (value) {\r
1908                 if (angular.isDefined(value) && value !== null) {\r
1909                     refill(value);\r
1910                 } else {\r
1911                     refill();\r
1912                 }\r
1913                 ngModel.$setViewValue(value);\r
1914             });\r
1915 \r
1916             ngModel.$render = function () {\r
1917                 scope.currentDate = ngModel.$viewValue;\r
1918             };\r
1919 \r
1920             var stringToDate = function (value) {\r
1921                 if (!isNaN(new Date(value))) {\r
1922                     value = new Date(value);\r
1923                 }\r
1924                 return value;\r
1925             };\r
1926             ngModel.$formatters.unshift(stringToDate);\r
1927         }\r
1928     };\r
1929 }])\r
1930 \r
1931 .directive('b2bDatepicker', ['$compile', '$log', 'b2bDatepickerConfig', 'b2bDatepickerService', function ($compile, $log, b2bDatepickerConfig, b2bDatepickerService) {\r
1932     return {\r
1933         restrict: 'A',\r
1934         scope: {\r
1935             disableDates: '&',\r
1936             onSelectClose: '&'\r
1937         },\r
1938         require: 'ngModel',\r
1939         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
1940             var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : b2bDatepickerConfig.dateFormat;\r
1941             var helperText = angular.isDefined(attr.helperText) ? scope.$parent.$eval(attr.helperText) : b2bDatepickerConfig.helperText;\r
1942             helperText = helperText.replace('$date', '{{dt | date : \'' + dateFormatString + '\'}}');\r
1943 \r
1944             var inline = false;\r
1945             if (elem.prop('nodeName') !== 'INPUT') {\r
1946                 inline = true;\r
1947             }\r
1948 \r
1949             var calendarIcon = '<i class="icon-primary-calendar" aria-hidden="true"></i>'\r
1950             var selectedDateMessage = '<button id="' + attr.btnId + '" type="button" class="span12 faux-input" ng-disabled="ngDisabled"><span class="hidden-spoken">' + helperText + '</span></button>';\r
1951 \r
1952             elem.removeAttr('b2b-datepicker');\r
1953             elem.removeAttr('ng-model');\r
1954             elem.removeAttr('ng-disabled');\r
1955             elem.addClass('datepicker-input');\r
1956             elem.attr('ng-model', 'dt');\r
1957             elem.attr('aria-describedby', 'datepicker');\r
1958             elem.attr('aria-hidden', 'true');\r
1959             elem.attr('tabindex', '-1');\r
1960             elem.attr('readonly', 'true');\r
1961             elem.attr('ng-disabled', 'ngDisabled');\r
1962             elem.attr('b2b-format-date', dateFormatString);\r
1963 \r
1964             var wrapperElement = angular.element('<div></div>');\r
1965             wrapperElement.attr('b2b-datepicker-popup', '');\r
1966             wrapperElement.attr('ng-model', 'dt');\r
1967             if (inline) {\r
1968                 wrapperElement.attr('inline', inline);\r
1969             }\r
1970 \r
1971             b2bDatepickerService.setAttributes(attr, wrapperElement);\r
1972             b2bDatepickerService.bindScope(attr, scope);\r
1973 \r
1974             wrapperElement.html('');\r
1975             wrapperElement.append(calendarIcon);\r
1976             wrapperElement.append(selectedDateMessage);\r
1977             wrapperElement.append(elem.prop('outerHTML'));\r
1978 \r
1979             var elm = wrapperElement.prop('outerHTML');\r
1980             elm = $compile(elm)(scope);\r
1981             elem.replaceWith(elm);\r
1982         }],\r
1983         link: function (scope, elem, attr, ctrl) {\r
1984             if (!ctrl) {\r
1985                 $log.error("ng-model is required.");\r
1986                 return; // do nothing if no ng-model\r
1987             }\r
1988 \r
1989             scope.$watch('dt', function (value) {\r
1990                 ctrl.$setViewValue(value);\r
1991             });\r
1992             ctrl.$render = function () {\r
1993                 scope.dt = ctrl.$viewValue;\r
1994             };\r
1995         }\r
1996     };\r
1997 }])\r
1998 \r
1999 .directive('b2bDatepickerGroup', [function () {\r
2000     return {\r
2001         restrict: 'EA',\r
2002         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
2003             this.$$headers = [];\r
2004             this.$$footers = [];\r
2005             this.registerDatepickerScope = function (datepickerScope) {\r
2006                 datepickerScope.headers = this.$$headers;\r
2007                 datepickerScope.footers = this.$$footers;\r
2008             };\r
2009         }],\r
2010         link: function (scope, elem, attr, ctrl) {}\r
2011     };\r
2012 }])\r
2013 \r
2014 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {\r
2015     return {\r
2016         restrict: 'A',\r
2017         require: 'ngModel',\r
2018         link: function (scope, elem, attr, ctrl) {\r
2019             var b2bFormatDate = "";\r
2020             attr.$observe('b2bFormatDate', function (value) {\r
2021                 b2bFormatDate = value;\r
2022             });\r
2023             var dateToString = function (value) {\r
2024                 if (!isNaN(new Date(value))) {\r
2025                     return dateFilter(new Date(value), b2bFormatDate);\r
2026                 }\r
2027                 return value;\r
2028             };\r
2029             ctrl.$formatters.unshift(dateToString);\r
2030         }\r
2031     };\r
2032 }])\r
2033 \r
2034 .directive('b2bDatepickerHeader', [function () {\r
2035     return {\r
2036         restrict: 'EA',\r
2037         require: '^b2bDatepickerGroup',\r
2038         transclude: true,\r
2039         replace: true,\r
2040         template: '',\r
2041         compile: function (elem, attr, transclude) {\r
2042             return function link(scope, elem, attr, ctrl) {\r
2043                 if (ctrl) {\r
2044                     ctrl.$$headers.push(transclude(scope, function () {}));\r
2045                 }\r
2046                 elem.remove();\r
2047             };\r
2048         }\r
2049     };\r
2050 }])\r
2051 \r
2052 .directive('b2bDatepickerFooter', [function () {\r
2053     return {\r
2054         restrict: 'EA',\r
2055         require: '^b2bDatepickerGroup',\r
2056         transclude: true,\r
2057         replace: true,\r
2058         template: '',\r
2059         compile: function (elem, attr, transclude) {\r
2060             return function link(scope, elem, attr, ctrl) {\r
2061                 if (ctrl) {\r
2062                     ctrl.$$footers.push(transclude(scope, function () {}));\r
2063                 }\r
2064                 elem.remove();\r
2065             };\r
2066         }\r
2067     };\r
2068 }]);\r
2069 /**\r
2070  * @ngdoc directive\r
2071  * @name Forms.att:checkboxes\r
2072  *\r
2073  * @description\r
2074  *  <file src="src/checkboxes/docs/readme.md" />\r
2075  * @usage\r
2076  * See demo section\r
2077  * @example\r
2078  <example module="b2b.att">\r
2079  <file src="src/checkboxes/docs/demo.html" />\r
2080  <file src="src/checkboxes/docs/demo.js" />\r
2081  </example>\r
2082  */\r
2083 angular.module('b2b.att.checkboxes', ['b2b.att.utilities'])\r
2084 .directive('b2bSelectGroup', [function (){\r
2085         return {\r
2086             restrict: 'A',\r
2087             require: 'ngModel',\r
2088             scope: {\r
2089                 checkboxes: "="\r
2090             },\r
2091             link: function (scope, elem, attr, ctrl) {\r
2092                 elem.bind('change', function () {\r
2093                     var isChecked = elem.prop('checked');\r
2094                     angular.forEach(scope.checkboxes, function (item) {\r
2095                         item.isSelected = isChecked;\r
2096                     });\r
2097                     scope.$apply();\r
2098                 });\r
2099                 scope.$watch('checkboxes', function () {\r
2100                     var setBoxes = 0;\r
2101                     if(scope.checkboxes === undefined) {\r
2102                         return;\r
2103                     }\r
2104                     angular.forEach(scope.checkboxes, function (item) {\r
2105                         if (item.isSelected) {\r
2106                             setBoxes++; \r
2107                         } \r
2108                     });\r
2109                     elem.prop('indeterminate', false);\r
2110                     if ( scope.checkboxes !==undefined && setBoxes === scope.checkboxes.length && scope.checkboxes.length > 0) { \r
2111                         ctrl.$setViewValue(true); \r
2112                         elem.removeClass('indeterminate');\r
2113                     } else if (setBoxes === 0) { \r
2114                        ctrl.$setViewValue(false); \r
2115                        elem.removeClass('indeterminate');\r
2116                     } else { \r
2117                         ctrl.$setViewValue(false); \r
2118                         elem.addClass('indeterminate');\r
2119                         elem.prop('indeterminate', true); \r
2120                     }\r
2121                     ctrl.$render();\r
2122                 }, true);\r
2123             }\r
2124         };\r
2125     }]);\r
2126 /**\r
2127  * @ngdoc directive\r
2128  * @name Misc.att:coachmark\r
2129  *\r
2130  * @description\r
2131  * <file src="src/coachmark/docs/readme.md" />\r
2132  *\r
2133  * @usage\r
2134  *\r
2135 <button b2b-coachmark start-coachmark-callback="startCoachmark()" end-coachmark-callback="endCoachmark()" action-coachmark-callback="actionCoachmark(action)" coachmark-index="coachmarkIndex" coachmarks="coachmarkElements" id="coachmark0" class="btn btn-alt">Initiate tour</button>\r
2136 \r
2137  * @example\r
2138     <section id="code">   \r
2139         <b>HTML + AngularJS</b>\r
2140         <example module="b2b.att">\r
2141             <file src="src/coachmark/docs/demo.html" />\r
2142             <file src="src/coachmark/docs/demo.js" />\r
2143         </example>\r
2144     </section>\r
2145  */\r
2146 \r
2147 angular.module('b2b.att.coachmark', ['b2b.att.utilities','b2b.att.position'])\r
2148         \r
2149     .directive('b2bCoachmark', ['$document', '$compile', '$position', '$timeout', function($document, $compile, $position, $timeout) {\r
2150         return {\r
2151             restrict: 'A',\r
2152              scope: {\r
2153                 coachmarks: '=',\r
2154                 coachmarkIndex: '=',\r
2155                 startCoachmarkCallback: '&',\r
2156                 endCoachmarkCallback: '&',\r
2157                 actionCoachmarkCallback: '&'\r
2158             },\r
2159             link: function (scope, element, attrs, ctrl) {\r
2160                 var coachmarkItems = scope.coachmarks;\r
2161                 var body = $document.find('body').eq(0);\r
2162                 var coackmarkJqContainer;\r
2163                 var coackmarkContainer;\r
2164                 var coachMarkElement;\r
2165                 var backdropjqLiteEl;\r
2166                 var coachmarkHighlight;\r
2167                 var initaitedCoachmark = false;\r
2168                 scope.coackmarkElPos ={\r
2169                     'top':'',\r
2170                     'left':''\r
2171                 };\r
2172                 \r
2173                 scope.currentCoachmark = {};\r
2174                 \r
2175                 \r
2176                 var coachmarkBackdrop = function(){\r
2177                     backdropjqLiteEl = angular.element('<div class="b2b-modal-backdrop fade in hidden-by-modal"></div>');\r
2178                     body.append(backdropjqLiteEl);\r
2179 \r
2180                     backdropjqLiteEl.bind('click', function() {\r
2181                         scope.closeCoachmark();\r
2182                         scope.$apply();\r
2183                     });\r
2184                 };\r
2185                 \r
2186                 \r
2187                 scope.closeButtonFocus = function(){\r
2188                     if(document.getElementsByClassName('b2b-coachmark-header').length >0){\r
2189                         document.getElementsByClassName('b2b-coachmark-header')[0].scrollLeft = 0;\r
2190                         document.getElementsByClassName('b2b-coachmark-header')[0].scrollTop = 0;\r
2191                     }\r
2192                 }\r
2193 \r
2194                 scope.actionCoachmark = function(action){\r
2195                     scope.actionCoachmarkCallback({\r
2196                         'action':action\r
2197                     })\r
2198                 };\r
2199                 \r
2200                 scope.closeCoachmark = function(){\r
2201                     initaitedCoachmark = false;\r
2202                     backdropjqLiteEl.remove();  \r
2203                     coackmarkContainer.remove();\r
2204                     coachmarkHighlight.remove();\r
2205                     if(coachMarkElement !== undefined && coachMarkElement !==""){\r
2206                         coachMarkElement.removeClass('b2b-coachmark-label')\r
2207                     }\r
2208                     if (angular.isFunction(scope.endCoachmarkCallback)){\r
2209                         scope.endCoachmarkCallback();   \r
2210                     }\r
2211                     element[0].focus();\r
2212                 }\r
2213                 \r
2214                 function showCoachmark(targetElement) {\r
2215                     scope.currentCoachmark = targetElement;\r
2216                     if(coachMarkElement !== undefined && coachMarkElement !==""){\r
2217                         coachMarkElement.removeClass('b2b-coachmark-label')\r
2218                         coackmarkContainer.remove();\r
2219                         coachmarkHighlight.remove();\r
2220                     }\r
2221                     coachMarkElement = angular.element(document.querySelector(targetElement.elementId));\r
2222                     coachMarkElement.addClass('b2b-coachmark-label');\r
2223                     var elementPosition = $position.offset(coachMarkElement);\r
2224                     \r
2225                     coachmarkHighlight = angular.element('<div class="b2b-coachmark-highlight"></div><div class="b2b-coachmark-highlight b2b-coachmark-highlight-mask"></div>');\r
2226                     coachmarkHighlight.css({\r
2227                         'width': (elementPosition.width + 20) +'px',\r
2228                         'top': (elementPosition.top -10) + 'px',\r
2229                         'left': (elementPosition.left - 10) + 'px',\r
2230                         'height': (elementPosition.height + 20) +'px'\r
2231                     }); \r
2232                     body.append(coachmarkHighlight);\r
2233                     \r
2234                     scope.coackmarkElPos.top = (elementPosition.top + elementPosition.height + 32) + 'px';\r
2235                     scope.coackmarkElPos.left = (elementPosition.left - 158 + elementPosition.width / 2 ) + 'px';\r
2236                     coackmarkJqContainer = angular.element('<div b2b-coachmark-container b2b-trap-focus-inside-element="true"></div>');\r
2237                     coackmarkContainer = $compile(coackmarkJqContainer)(scope);\r
2238                     body.append(coackmarkContainer);\r
2239                     \r
2240                     $timeout(function () {\r
2241                         var currentCoachmarkContainer = document.getElementsByClassName('b2b-coachmark-container')[0];\r
2242                         currentCoachmarkContainer.focus();\r
2243                         var coachmarkHeight = window.getComputedStyle(currentCoachmarkContainer).height.split('px')[0];\r
2244                         var newOffsetHeight = (Math.round(elementPosition.top) - Math.round(coachmarkHeight));\r
2245                         \r
2246                         // We need a slight offset to show the lightboxed item\r
2247                         TweenLite.to(window, 2, {scrollTo:{x: (scope.coackmarkElPos.left.split('px')[0]-100), y: newOffsetHeight}});\r
2248                     }, 200);\r
2249                 }\r
2250                 \r
2251                 element.bind('click', function (e) {\r
2252                     initaitedCoachmark = true;\r
2253                     if(scope.coachmarkIndex === -1 || scope.coachmarkIndex >= coachmarkItems.length ){\r
2254                         scope.coachmarkIndex = 0;\r
2255                     }\r
2256                     scope.$watch('coachmarkIndex', function () {\r
2257                         if(initaitedCoachmark === true){\r
2258                             if(scope.coachmarkIndex === -1 || scope.coachmarkIndex >= coachmarkItems.length ){\r
2259                                 scope.closeCoachmark();\r
2260                             }else{\r
2261                                 showCoachmark(coachmarkItems[scope.coachmarkIndex]);\r
2262                             }\r
2263                         }\r
2264                     });\r
2265                     coachmarkBackdrop();\r
2266                     showCoachmark(coachmarkItems[scope.coachmarkIndex]);\r
2267                     if (angular.isFunction(scope.startCoachmarkCallback)){\r
2268                         scope.startCoachmarkCallback(); \r
2269                     }\r
2270                     $document.bind('keydown', function (evt) {\r
2271                         if (evt.which === 27 && initaitedCoachmark) {\r
2272                             scope.closeCoachmark();\r
2273                             scope.$apply(); \r
2274                         }\r
2275                     });\r
2276                 });\r
2277 \r
2278             }\r
2279         };\r
2280     }])\r
2281     .directive('b2bCoachmarkContainer', ['$document', '$position', function($document, $position) {\r
2282         return {\r
2283             restrict: 'A',\r
2284             transclude: true,\r
2285             replace: true,\r
2286             templateUrl: 'b2bTemplate/coachmark/coachmark.html',\r
2287             link: function (scope, element, attrs, ctrl) {\r
2288                             \r
2289             }\r
2290         };  \r
2291     }]);\r
2292     \r
2293 /** \r
2294  * @ngdoc directive \r
2295  * @name Template.att:Configuration Section \r
2296  * \r
2297  * @description \r
2298  *  <file src="src/configurationSection/docs/readme.md" /> \r
2299  * \r
2300  * @example \r
2301  *  <section id="code"> \r
2302         <b>HTML + AngularJS</b> \r
2303         <example module="b2b.att"> \r
2304             <file src="src/configurationSection/docs/demo.html" /> \r
2305             <file src="src/configurationSection/docs/demo.js" /> \r
2306        </example> \r
2307     </section>    \r
2308  * \r
2309  */\r
2310 angular.module('b2b.att.configurationSection', [])\r
2311   \r
2312 /** \r
2313  * @ngdoc directive \r
2314  * @name Template.att:Directory Listing \r
2315  * \r
2316  * @description \r
2317  *  <file src="src/directoryListingTemplate/docs/readme.md" /> \r
2318  * \r
2319  * @example \r
2320  *  <section id="code"> \r
2321         <b>HTML + AngularJS</b> \r
2322         <example module="b2b.att"> \r
2323             <file src="src/directoryListingTemplate/docs/demo.html" /> \r
2324             <file src="src/directoryListingTemplate/docs/demo.js" /> \r
2325        </example> \r
2326     </section>    \r
2327  * \r
2328  */\r
2329 angular.module('b2b.att.directoryListingTemplate', [])\r
2330   \r
2331 /**\r
2332  * @ngdoc directive\r
2333  * @name Forms.att:dropdowns\r
2334  *\r
2335  * @description\r
2336  *  <file src="src/dropdowns/docs/readme.md" />\r
2337  * @usage\r
2338  *\r
2339  * @example\r
2340    <section id="code">\r
2341     <example module="b2b.att">\r
2342      <file src="src/dropdowns/docs/demo.html" />\r
2343      <file src="src/dropdowns/docs/demo.js" />\r
2344     </example>\r
2345    </section>\r
2346  */\r
2347 angular.module('b2b.att.dropdowns', ['b2b.att.utilities', 'b2b.att.position', 'ngSanitize'])\r
2348 \r
2349 .constant('b2bDropdownConfig', {\r
2350     prev: '37,38',\r
2351     next: '39,40',\r
2352     menuKeyword: 'menu',\r
2353     linkMenuKeyword: 'link-menu',\r
2354     largeKeyword: 'large',\r
2355     smallKeyword: 'small'\r
2356 })  \r
2357 \r
2358 .directive("b2bDropdown", ['$timeout', '$compile', '$templateCache', 'b2bUserAgent', 'b2bDropdownConfig', '$position', function ($timeout, $compile, $templateCache, b2bUserAgent, b2bDropdownConfig, $position) {\r
2359     return {\r
2360         restrict: 'A',\r
2361         scope: true,\r
2362         require: 'ngModel',\r
2363         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
2364             scope.isInputDropdown = true;\r
2365             scope.placeHoldertext = attr.placeholderText;\r
2366             if (attr.type) {\r
2367                 if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1 || attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {\r
2368                     scope.isInputDropdown = false;\r
2369                     if (attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {\r
2370                         scope.dropdownType = b2bDropdownConfig.linkMenuKeyword;\r
2371                     } else if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1) {\r
2372                         scope.dropdownType = b2bDropdownConfig.menuKeyword;\r
2373                     }\r
2374                 }\r
2375                 if (attr.type.indexOf(b2bDropdownConfig.largeKeyword) > -1) {\r
2376                     scope.dropdownSize = b2bDropdownConfig.largeKeyword;\r
2377                 } else if (attr.type.indexOf(b2bDropdownConfig.smallKeyword) > -1) {\r
2378                     scope.dropdownSize = b2bDropdownConfig.smallKeyword;\r
2379                 }\r
2380             }\r
2381 \r
2382             scope.labelText = attr.labelText;\r
2383 \r
2384             scope.setBlur = function () {\r
2385                 scope.setTouched();\r
2386             };\r
2387 \r
2388             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {\r
2389                 var formCtrl = elem.controller('form');\r
2390                 scope.setNgModelController = function (name, ngModelCtrl) {\r
2391                     if (name && formCtrl && ngModelCtrl) {\r
2392                         formCtrl[name] = ngModelCtrl;\r
2393                     }\r
2394                 };\r
2395                 scope.setOptionalCta = function (optionalCta) {\r
2396                     scope.optionalCta = optionalCta;\r
2397                 };\r
2398                 var innerHtml = angular.element('<div></div>').append(elem.html());\r
2399                 innerHtml = ($compile(innerHtml)(scope)).html();\r
2400                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownDesktop.html'));\r
2401                 template.find('ul').eq(0).append(innerHtml);\r
2402                 template = $compile(template)(scope);\r
2403                 elem.replaceWith(template);\r
2404             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {\r
2405                 elem.css({\r
2406                     'opacity': '0',\r
2407                     'filter': 'alpha(opacity=0)'\r
2408                 });\r
2409                 elem.addClass('awd-select isWrapped');\r
2410                 elem.wrap('<span class="selectWrap"></span>');\r
2411                 var cover = angular.element('<span aria-hidden="true"><i class="icon-primary-down" aria-hidden="true"></i></span>');\r
2412                 elem.parent().append(cover);\r
2413                 elem.parent().append('<i class="icon-primary-down" aria-hidden="true"></i>');\r
2414                 var set = function () {\r
2415                     var sel = elem[0] ? elem[0] : elem;\r
2416                     var selectedText = "";\r
2417                     var selIndex = sel.selectedIndex;\r
2418                     if (typeof selIndex !== 'undefined') {\r
2419                         selectedText = sel.options[selIndex].text;\r
2420                     }\r
2421                     cover.text(selectedText).append('<i class="icon-primary-down" aria-hidden="true"></i>');\r
2422                 };\r
2423                 var update = function (value) {\r
2424                     $timeout(set, 100);\r
2425                 };\r
2426 \r
2427                 if (attr.ngModel) {\r
2428                     scope.$watch(attr.ngModel, function (newVal, oldVal) {\r
2429                         update();\r
2430                     });\r
2431                 }\r
2432                 elem.bind('keyup', function (ev) {\r
2433                     if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {\r
2434                         return;\r
2435                     }\r
2436                     set();\r
2437                 });\r
2438             }\r
2439         }],  \r
2440         link: function (scope, elem, attr, ctrl) {\r
2441             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {\r
2442                 scope.updateModel = function () {\r
2443                     if (ctrl.$dirty) {\r
2444                         debugger;\r
2445                     }\r
2446                     ctrl.$setViewValue(scope.currentSelected.value);\r
2447                     if (scope.dropdownRequired && scope.currentSelected.value === '') {\r
2448                         scope.setRequired(false);\r
2449                     } else {\r
2450                         scope.setRequired(true);\r
2451                     }\r
2452 \r
2453                     if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {\r
2454                         $timeout(function () {\r
2455                             scope.appendCaretPositionStyle();\r
2456                         }, 100);\r
2457                     }\r
2458                 };\r
2459                 ctrl.$render = function () {\r
2460 //                    if(ctrl.$dirty || ctrl.$pristine) {\r
2461                         $timeout(function () {\r
2462 \r
2463                             if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && (angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '')) {\r
2464                                 scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();\r
2465                             } else if ((angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '') && ctrl.$viewValue !== '' ) {\r
2466                                 scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();\r
2467                             } else if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && scope.placeHoldertext !== '' )  {\r
2468                                 scope.currentSelected.text = scope.placeHoldertext; \r
2469                             } else {\r
2470                                 scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();\r
2471                             }\r
2472 \r
2473                         }, 100);\r
2474                     };\r
2475 //                }\r
2476                 scope.disabled = false;\r
2477                 scope.dropdownName = attr.name;\r
2478                 scope.dropdownId = attr.id;\r
2479                 scope.labelId = attr.ariaLabelledby;\r
2480                 scope.dropdownDescribedBy = attr.ariaDescribedby;\r
2481                 if (attr.required) {\r
2482                     scope.dropdownRequired = true;\r
2483                 } else {\r
2484                     scope.dropdownRequired = false;\r
2485                 }\r
2486                 elem.removeAttr('name');\r
2487                 elem.removeAttr('id');\r
2488                 scope.$parent.$watch(attr.ngDisabled, function (val) {\r
2489                     scope.disabled = val;\r
2490                 });\r
2491             }\r
2492         }\r
2493     };\r
2494 }])\r
2495 \r
2496 .directive("b2bDropdownToggle", ['$document', '$documentBind', '$isElement', 'b2bDropdownConfig', 'keymap', 'b2bUtilitiesConfig', '$timeout', '$position', function ($document, $documentBind, $isElement, b2bDropdownConfig, keymap, b2bUtilitiesConfig, $timeout, $position) {\r
2497     return {\r
2498         restrict: 'A',\r
2499         require: '?^b2bKey',\r
2500         link: function (scope, elem, attr, ctrl) {\r
2501             scope.appendCaretPositionStyle = function () {\r
2502                 while (document.querySelector('style.b2bDropdownCaret')) {\r
2503                     document.querySelector('style.b2bDropdownCaret').remove();\r
2504                 };\r
2505                 var caretPosition = $position.position(elem).width - 26;\r
2506                 if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {\r
2507                     var template = angular.element('<style class="b2bDropdownCaret" type="text/css">.linkSelectorModule .active+.moduleWrapper:before {left: ' + caretPosition + 'px;}</style>');\r
2508                     $document.find('head').append(template);\r
2509                 }\r
2510             };\r
2511 \r
2512             if (scope.isInputDropdown && (scope.labelText !== undefined)) {\r
2513                 elem.attr('aria-label', scope.labelText);\r
2514             }\r
2515 \r
2516             scope.toggleFlag = false;\r
2517             scope.dropdownLists = {};\r
2518             scope.dropdownListValues = [];\r
2519             scope.dropdown = {\r
2520                 totalIndex: -1\r
2521             };\r
2522             scope.currentSelected = {\r
2523                 value: '',\r
2524                 text: '',\r
2525                 label: '',\r
2526                 index: -1\r
2527             };\r
2528             var searchString = '';\r
2529             var searchElement = function (searchExp) {\r
2530                 var regex = new RegExp("\\b" + searchExp, "gi");\r
2531                 var position = scope.dropdownListValues.regexIndexOf(regex, scope.currentSelected.index + 1, true);\r
2532                 if (position > -1) {\r
2533                     return position;\r
2534                 }\r
2535                 return undefined;\r
2536             };\r
2537             var startTimer = function (time) {\r
2538                 if (searchString === '') {\r
2539                     $timeout(function () {\r
2540                         searchString = '';\r
2541                     }, time);\r
2542                 }\r
2543             };\r
2544             scope.toggleDropdown = function (toggleFlag) {\r
2545                 if (!scope.disabled) {\r
2546                     if (angular.isDefined(toggleFlag)) {\r
2547                         scope.toggleFlag = toggleFlag;\r
2548                     } else {\r
2549                         scope.toggleFlag = !scope.toggleFlag;\r
2550                     }\r
2551                     if (!scope.toggleFlag) {\r
2552                         if (scope.isInputDropdown) {\r
2553                             elem.parent().find('input')[0].focus();\r
2554                         } else {\r
2555                             elem.parent().find('button')[0].focus();\r
2556                         }\r
2557                     } else {\r
2558                         scope.dropdown.highlightedValue = scope.currentSelected.value;\r
2559                         if (ctrl && ctrl.enableSearch) {\r
2560                             if (angular.isDefined(scope.dropdownLists[scope.currentSelected.value])) {\r
2561                                 ctrl.resetCounter(scope.dropdownLists[scope.currentSelected.value][2]);\r
2562                             }\r
2563                         }\r
2564                         if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {\r
2565                             scope.appendCaretPositionStyle();\r
2566                         }\r
2567                     }\r
2568                 }\r
2569             };\r
2570 \r
2571             elem.bind('keydown', function (ev) {\r
2572                 if (!ev.keyCode) {\r
2573                     if (ev.which) {\r
2574                         ev.keyCode = ev.which;\r
2575                     } else if (ev.charCode) {\r
2576                         ev.keyCode = ev.charCode;\r
2577                     }\r
2578                 }\r
2579                 if (!scope.toggleFlag) {\r
2580                     if (ev.keyCode) {\r
2581                         var currentIndex = scope.currentSelected.index;\r
2582                         if (ev.altKey === true && ev.keyCode === keymap.KEY.DOWN) {\r
2583                             scope.toggleDropdown(true);\r
2584                             ev.preventDefault();\r
2585                             ev.stopPropagation();\r
2586                         } else if (b2bDropdownConfig.prev.split(',').indexOf(ev.keyCode.toString()) > -1) {\r
2587                             angular.isDefined(scope.dropdownListValues[currentIndex - 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex - 1]][0].updateDropdownValue() : angular.noop();\r
2588                             ev.preventDefault();\r
2589                             ev.stopPropagation();\r
2590                         } else if (b2bDropdownConfig.next.split(',').indexOf(ev.keyCode.toString()) > -1) {\r
2591                             angular.isDefined(scope.dropdownListValues[currentIndex + 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex + 1]][0].updateDropdownValue() : angular.noop();\r
2592                             ev.preventDefault();\r
2593                             ev.stopPropagation();\r
2594                         } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {\r
2595                             startTimer(b2bUtilitiesConfig.searchTimer);\r
2596                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');\r
2597                             var position = searchElement(searchString);\r
2598                             angular.isDefined(scope.dropdownListValues[position]) ? scope.dropdownLists[scope.dropdownListValues[position]][0].updateDropdownValue() : angular.noop();\r
2599                             ev.preventDefault();\r
2600                             ev.stopPropagation();\r
2601                         }\r
2602                     }\r
2603                 } else {\r
2604                     if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {\r
2605                         scope.toggleDropdown(false);\r
2606                         ev.preventDefault();\r
2607                         ev.stopPropagation();\r
2608                     } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {\r
2609                         scope.toggleDropdown(false);\r
2610                         ev.preventDefault();\r
2611                         ev.stopPropagation();\r
2612                     }\r
2613                 }\r
2614                 scope.$apply(); // TODO: Move this into each block to avoid expensive digest cycles\r
2615             });\r
2616             var outsideClick = function (e) {\r
2617                 var isElement = $isElement(angular.element(e.target), elem.parent(), $document);\r
2618                 if (!isElement) {\r
2619                     scope.toggleDropdown(false);\r
2620                     scope.$apply();\r
2621                 }\r
2622             };\r
2623             $documentBind.click('toggleFlag', outsideClick, scope);\r
2624         }\r
2625     };\r
2626 }])\r
2627 \r
2628 .directive("b2bDropdownGroup", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {\r
2629     return {\r
2630         restrict: 'A',\r
2631         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
2632             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {\r
2633                 var innerHtml = angular.element('<div></div>').append(elem.html());\r
2634                 innerHtml = ($compile(innerHtml)(scope)).html();\r
2635                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html'));\r
2636                 template.attr('ng-repeat', attr.optGroupRepeat);\r
2637                 template.attr('label', elem.attr('label'));\r
2638                 template.find('ul').append(innerHtml);\r
2639                 elem.replaceWith(template);\r
2640             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {\r
2641                 var template = angular.element(elem.prop('outerHTML'));\r
2642                 template.attr('ng-repeat', attr.optGroupRepeat);\r
2643                 template.removeAttr('b2b-dropdown-group');\r
2644                 template.removeAttr('opt-group-repeat');\r
2645                 template = $compile(template)(scope);\r
2646                 elem.replaceWith(template);\r
2647             }\r
2648         }]\r
2649     };\r
2650 }])\r
2651 \r
2652 .directive("b2bDropdownGroupDesktop", [function () {\r
2653     return {\r
2654         restrict: 'A',\r
2655         scope: true,\r
2656         link: function (scope, elem, attr, ctrl) {\r
2657             scope.groupHeader = attr.label;\r
2658         }\r
2659     };\r
2660 }])\r
2661 \r
2662 .directive("b2bDropdownList", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {\r
2663     return {\r
2664         restrict: 'A',\r
2665         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
2666             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {\r
2667                 var innerHtml = angular.element('<div></div>').append(elem.html());\r
2668                 innerHtml = ($compile(innerHtml)(scope)).html();\r
2669                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownListDesktop.html'));\r
2670                 template.attr('ng-repeat', attr.optionRepeat);\r
2671                 template.attr('value', elem.attr('value'));\r
2672                 template.attr('search-key', elem.attr('value'));\r
2673                 if (elem.attr('aria-describedby')){\r
2674                     template.attr('aria-describedby', attr.ariaDescribedby);\r
2675                 }\r
2676                 if (elem.attr('imgsrc')) {\r
2677                     if (elem.attr('imgalt')) {\r
2678                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt="' + elem.attr('imgalt') + '"/>');\r
2679                     } else {\r
2680                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt=""/>');\r
2681                     }\r
2682                 }\r
2683                 template.append(innerHtml);\r
2684                 elem.replaceWith(template);\r
2685             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {\r
2686                 var template = angular.element(elem.prop('outerHTML'));\r
2687                 template.attr('ng-repeat', attr.optionRepeat);\r
2688                 if (elem.attr('aria-describedby')){\r
2689                     template.attr('aria-describedby', attr.ariaDescribedby);\r
2690                 }\r
2691                 template.removeAttr('b2b-dropdown-list');\r
2692                 template.removeAttr('option-repeat');\r
2693                 template = $compile(template)(scope);\r
2694                 elem.replaceWith(template);\r
2695             }\r
2696         }]\r
2697     };\r
2698 }])\r
2699 \r
2700 .directive("b2bDropdownListDesktop", ['$sce', 'keymap', 'b2bDropdownConfig', function ($sce, keymap, b2bDropdownConfig) {\r
2701     return {\r
2702         restrict: 'A',\r
2703         scope: true,\r
2704         link: function (scope, elem, attr, ctrl) {\r
2705             var dropdownListValue = scope.dropdownListValue = attr.value;\r
2706             scope.dropdown.totalIndex++;\r
2707             var dropdownListIndex = scope.dropdown.totalIndex;\r
2708             scope.dropdownListValues.push(dropdownListValue);\r
2709             scope.dropdownLists[dropdownListValue] = [];\r
2710             scope.dropdownLists[dropdownListValue][0] = scope;\r
2711             scope.dropdownLists[dropdownListValue][1] = elem;\r
2712             scope.dropdownLists[dropdownListValue][2] = dropdownListIndex;\r
2713             scope.updateDropdownValue = function () {\r
2714                 scope.currentSelected.value = dropdownListValue;\r
2715                 if (scope.isInputDropdown) {\r
2716                     scope.currentSelected.text = elem.text();\r
2717                 } else if ((scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) || (scope.dropdownType === b2bDropdownConfig.menuKeyword && scope.dropdownSize === b2bDropdownConfig.smallKeyword)) {\r
2718                     scope.currentSelected.text = dropdownListValue;\r
2719                 } else if (scope.dropdownType === b2bDropdownConfig.menuKeyword) {\r
2720                     scope.currentSelected.text = $sce.trustAsHtml(elem.html());\r
2721                 }\r
2722                 if (scope.isInputDropdown) {\r
2723                     scope.currentSelected.label = elem.text();\r
2724                 } else if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {\r
2725                     scope.currentSelected.label = dropdownListValue;\r
2726                 } else if (scope.dropdownType === b2bDropdownConfig.menuKeyword) {\r
2727                     scope.currentSelected.label = elem.text();\r
2728                 }\r
2729                 scope.currentSelected.index = dropdownListIndex;\r
2730                 scope.updateModel();\r
2731             };\r
2732             scope.selectDropdownItem = function () {\r
2733                 scope.setDirty();\r
2734                 scope.updateDropdownValue();\r
2735                 scope.toggleDropdown(false);\r
2736             };\r
2737             scope.highlightDropdown = function () {\r
2738                 scope.dropdown.highlightedValue = dropdownListValue;\r
2739             };\r
2740             elem.bind('mouseover', function (ev) {\r
2741                 elem[0].focus();\r
2742             });\r
2743             elem.bind('keydown', function (ev) {\r
2744                 if (!ev.keyCode) {\r
2745                     if (ev.which) {\r
2746                         ev.keyCode = ev.which;\r
2747                     } else if (ev.charCode) {\r
2748                         ev.keyCode = ev.charCode;\r
2749                     }\r
2750                 }\r
2751                 if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {\r
2752                     scope.toggleDropdown(false);\r
2753                     ev.preventDefault();\r
2754                     ev.stopPropagation();\r
2755                 } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {\r
2756                     scope.toggleDropdown(false);\r
2757                     ev.preventDefault();\r
2758                     ev.stopPropagation();\r
2759                 }\r
2760                 scope.$apply();\r
2761             });\r
2762         }\r
2763     };\r
2764 }])\r
2765 \r
2766 .directive("b2bDropdownRepeat", ['$compile', 'b2bUserAgent', function ($compile, b2bUserAgent) {\r
2767     return {\r
2768         restrict: 'A',\r
2769         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
2770             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {\r
2771                 var innerHtml = angular.element('<div></div>').append(elem.html());\r
2772                 innerHtml = ($compile(innerHtml)(scope)).html();\r
2773                 var template = angular.element('<div></div>');\r
2774                 template.attr('ng-repeat', attr.b2bDropdownRepeat);\r
2775                 template.append(innerHtml);\r
2776                 elem.replaceWith(template);\r
2777             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {\r
2778                 angular.noop();\r
2779             }\r
2780         }]\r
2781     };\r
2782 }])\r
2783 \r
2784 .directive("b2bDropdownValidation", ['$timeout', function ($timeout) {\r
2785     return {\r
2786         restrict: 'A',\r
2787         require: 'ngModel',\r
2788         link: function (scope, elem, attr, ctrl) {\r
2789             $timeout(function () {\r
2790                 scope.setNgModelController(attr.name, ctrl);\r
2791             }, 100);\r
2792             scope.setDirty = function () {\r
2793                 if (ctrl.$dirty === false) {\r
2794                     ctrl.$dirty = true;\r
2795                     ctrl.$pristine = false;\r
2796                 }\r
2797             };\r
2798             scope.setTouched = function () {\r
2799                 if (ctrl.$touched === false) {\r
2800                     ctrl.$touched = true;\r
2801                     ctrl.$pristine = false;\r
2802                 }\r
2803             };\r
2804             scope.setRequired = function (flag) {\r
2805                 ctrl.$setValidity('required', flag);\r
2806             };\r
2807         }\r
2808     };\r
2809 }])\r
2810 \r
2811 .directive('b2bDropdownOptionalCta', [function () {\r
2812     return {\r
2813         restrict: 'EA',\r
2814         transclude: true,\r
2815         replace: true,\r
2816         template: '',\r
2817         compile: function (elem, attr, transclude) {\r
2818             return function link(scope, elem, attr, ctrl) {\r
2819                 if (scope.setOptionalCta) {\r
2820                     scope.setOptionalCta(transclude(scope, function () {}));\r
2821                 }\r
2822                 elem.remove();\r
2823             };\r
2824         }\r
2825     };\r
2826 }]);\r
2827 /**\r
2828  * @ngdoc directive\r
2829  * @name Forms.att:File Upload\r
2830  *\r
2831  * @description\r
2832  *  <file src="src/fileUpload/docs/readme.md" />\r
2833  *\r
2834  * @usage\r
2835  * \r
2836 <form id="dragDropFile">        \r
2837     <div b2b-file-drop file-model="fileModel" on-drop="triggerFileUpload()"  align="center">\r
2838         <p>\r
2839             <br>To upload a file, drag & drop it here or \r
2840             <span b2b-file-link file-model="fileModel" on-file-select="triggerFileUpload()" >\r
2841                 click here to select from your computer.\r
2842             </span><br>\r
2843         </p>\r
2844     </div>\r
2845 </form>\r
2846  *\r
2847  * @example\r
2848  *  <section id="code">\r
2849         <example module="b2b.att">\r
2850             <file src="src/fileUpload/docs/demo.html" />\r
2851             <file src="src/fileUpload/docs/demo.js" />\r
2852        </example>\r
2853     </section>\r
2854  *\r
2855  */\r
2856 angular.module('b2b.att.fileUpload', ['b2b.att.utilities'])\r
2857     .directive('b2bFileDrop', [function() {\r
2858             return {\r
2859                 restrict: 'EA',\r
2860                 scope: {\r
2861                     fileModel: '=',\r
2862                     onDrop: '&'\r
2863                 },\r
2864                 controller: ['$scope', '$attrs', function($scope, $attrs) {\r
2865                     this.onDrop = $scope.onDrop;\r
2866                 }],\r
2867                 link: function(scope, element) {\r
2868                     element.addClass('b2b-dragdrop');\r
2869                     element.bind(\r
2870                         'dragover',\r
2871                         function(e) {\r
2872                             if (e.originalEvent) {\r
2873                                 e.dataTransfer = e.originalEvent.dataTransfer;\r
2874                             }\r
2875                             e.dataTransfer.dropEffect = 'move';\r
2876                             // allows us to drop\r
2877                             if (e.preventDefault) {\r
2878                                 e.preventDefault();\r
2879                             }\r
2880                             element.addClass('b2b-dragdrop-over');\r
2881                             return false;\r
2882                         }\r
2883                     );\r
2884                     element.bind(\r
2885                         'dragenter',\r
2886                         function(e) {\r
2887                             // allows us to drop\r
2888                             if (e.preventDefault) {\r
2889                                 e.preventDefault();\r
2890                             }\r
2891                             element.addClass('b2b-dragdrop-over');\r
2892                             return false;\r
2893                         }\r
2894                     );\r
2895                     element.bind(\r
2896                         'dragleave',\r
2897                         function() {\r
2898                             element.removeClass('b2b-dragdrop-over');\r
2899                             return false;\r
2900                         }\r
2901                     );\r
2902                     element.bind(\r
2903                         'drop',\r
2904                         function(e) {\r
2905                             // Stops some browsers from redirecting.\r
2906                             if (e.preventDefault) {\r
2907                                 e.preventDefault();\r
2908                             }\r
2909                             if (e.stopPropagation) {\r
2910                                 e.stopPropagation();\r
2911                             }\r
2912                             if (e.originalEvent) {\r
2913                                 e.dataTransfer = e.originalEvent.dataTransfer;\r
2914                             }\r
2915                             element.removeClass('b2b-dragdrop-over');\r
2916                             if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\r
2917                                 scope.fileModel = e.dataTransfer.files[0];\r
2918                                 scope.$apply();\r
2919                                 if (angular.isFunction(scope.onDrop)) {\r
2920                                     scope.onDrop();\r
2921                                 }\r
2922                             }\r
2923                             return false;\r
2924                         }\r
2925                     );\r
2926                 }\r
2927             };\r
2928         }])\r
2929         .directive('b2bFileLink', [function() {\r
2930             return {\r
2931                 restrict: 'EA',\r
2932                 require: '^?b2bFileDrop',\r
2933                 replace: true,\r
2934                 transclude: true,\r
2935                 templateUrl: 'b2bTemplate/fileUpload/fileUpload.html',\r
2936                 scope: {\r
2937                     fileModel: '=?',\r
2938                     onFileSelect: '&'\r
2939                 },\r
2940                 controller: ['$scope', function($scope) {\r
2941                     this.setFileModel = function(fileModel) {\r
2942                         if ($scope.takeFileModelFromParent) {\r
2943                             $scope.$parent.fileModel = fileModel;\r
2944                             $scope.$parent.$apply();\r
2945                         } else {\r
2946                             $scope.fileModel = fileModel;\r
2947                             $scope.$apply();\r
2948                         }\r
2949                     };\r
2950                     this.callbackFunction = function() {\r
2951                         if (angular.isFunction($scope.onFileSelect)) {\r
2952                             $scope.onFileSelect();\r
2953                         }\r
2954                     };\r
2955         \r
2956                 }],\r
2957                 link: function(scope, element, attr, b2bFileDropCtrl) {\r
2958                     scope.takeFileModelFromParent = false;\r
2959                     if (!(attr.fileModel) && b2bFileDropCtrl) {\r
2960                         scope.takeFileModelFromParent = true;\r
2961                     }\r
2962                     if (!(attr.onFileSelect) && b2bFileDropCtrl) {\r
2963                         scope.onFileSelect = b2bFileDropCtrl.onDrop;\r
2964                     }\r
2965                 }\r
2966             };\r
2967         }])\r
2968         .directive('b2bFileChange', ['$log', '$rootScope', function($log, $rootScope) {\r
2969             return {\r
2970                 restrict: 'A',\r
2971                 require: '^b2bFileLink',\r
2972                 link: function(scope, element, attr, b2bFileLinkCtrl) {\r
2973                     element.bind('change', changeFileModel);\r
2974 \r
2975                     function changeFileModel(e) {\r
2976                         if (e.target.files && e.target.files.length > 0) {\r
2977                             b2bFileLinkCtrl.setFileModel(e.target.files[0]);\r
2978                             b2bFileLinkCtrl.callbackFunction();\r
2979                         } else {\r
2980                             var strFileName = e.target.value;\r
2981                             try {\r
2982                                 var objFSO = new ActiveXObject("Scripting.FileSystemObject");\r
2983                                 b2bFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));\r
2984                                 b2bFileLinkCtrl.callbackFunction();\r
2985                             } catch (e) {\r
2986                                 var errMsg = "There was an issue uploading " + strFileName + ". Please try again.";\r
2987                                 $log.error(errMsg);\r
2988                                 $rootScope.$broadcast('b2b-file-link-failure', errMsg);\r
2989                             }\r
2990                         }\r
2991                     }\r
2992                 }\r
2993             };\r
2994         }]);\r
2995 /**\r
2996  * @ngdoc directive\r
2997  * @name Navigation.att:filters\r
2998  *\r
2999  * @description\r
3000  *  <file src="src/filters/docs/readme.md" />\r
3001  *\r
3002  * @usage\r
3003  *  <div b2b-filters></div>\r
3004  *\r
3005  * @example\r
3006  *  <section id="code">\r
3007        <b>HTML + AngularJS</b>\r
3008         <example module="b2b.att">\r
3009             <file src="src/filters/docs/demo.html" />\r
3010             <file src="src/filters/docs/demo.js" />\r
3011        </example>\r
3012     </section>\r
3013  * \r
3014  */\r
3015 angular.module('b2b.att.filters', ['b2b.att.utilities', 'b2b.att.multipurposeExpander'])\r
3016     .filter('filtersSelectedItemsFilter', [function () {\r
3017         return function (listOfItemsArray) {\r
3018 \r
3019             if (!listOfItemsArray) {\r
3020                 listOfItemsArray = [];\r
3021             }\r
3022 \r
3023             var returnArray = [];\r
3024 \r
3025             for (var i = 0; i < listOfItemsArray.length; i++) {\r
3026                 for (var j = 0; j < listOfItemsArray[i].filterTypeItems.length; j++) {\r
3027                     if (listOfItemsArray[i].filterTypeItems[j].selected && !listOfItemsArray[i].filterTypeItems[j].inProgress) {\r
3028                         returnArray.push(listOfItemsArray[i].filterTypeItems[j]);\r
3029                     }\r
3030                 }\r
3031             }\r
3032 \r
3033             return returnArray;\r
3034         };\r
3035     }]);\r
3036 /**\r
3037  * @ngdoc directive\r
3038  * @name Messages, modals & alerts.att:flyout\r
3039  *\r
3040  * @description\r
3041  *  <file src="src/flyout/docs/readme.md" />\r
3042  * @example\r
3043  *  <section id="code">\r
3044         <example module="b2b.att">\r
3045             <file src="src/flyout/docs/demo.html" />\r
3046             <file src="src/flyout/docs/demo.js" />\r
3047        </example>\r
3048     </section>\r
3049  *\r
3050  */\r
3051 angular.module('b2b.att.flyout', ['b2b.att.utilities', 'b2b.att.position'])\r
3052     .directive('b2bFlyout', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {\r
3053         return {\r
3054             restrict: 'EA',\r
3055             transclude: true,\r
3056             templateUrl: 'b2bTemplate/flyout/flyout.html',\r
3057             controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
3058                 scope.flyoutOpened = false;\r
3059                 var contentScope = '';\r
3060                 var togglerScope = '';\r
3061                 this.registerContentScope = function (scp) {\r
3062                     contentScope = scp;\r
3063                 };\r
3064                 this.registerTogglerScope = function (scp) {\r
3065                     togglerScope = scp;\r
3066                 };\r
3067 \r
3068                 this.toggleFlyoutState = function () {\r
3069                     if (contentScope) {\r
3070                         contentScope.toggleFlyout();\r
3071                     }\r
3072                 };\r
3073                 this.getTogglerDimensions = function () {\r
3074                     return togglerScope.getTogglerDimensions();\r
3075                 }\r
3076                 this.setTogglerFocus = function () {\r
3077                     return togglerScope.setTogglerFocus();\r
3078                 }\r
3079 \r
3080                 this.closeFlyout = function (e) {\r
3081                     contentScope.closeFromChild(e);\r
3082                 };\r
3083                 this.gotFocus = function () {\r
3084                     contentScope.gotFocus();\r
3085                 };\r
3086 \r
3087                 this.updateAriaModel = function (val) {\r
3088                     scope.flyoutOpened = val;\r
3089                 };\r
3090 \r
3091                 var firstTabableElement = undefined,\r
3092                     lastTabableElement = undefined;\r
3093 \r
3094                 var firstTabableElementKeyhandler = function (e) {\r
3095                     if (!e.keyCode) {\r
3096                         e.keyCode = e.which;\r
3097                     }\r
3098                     if (e.keyCode === keymap.KEY.TAB && e.shiftKey && scope.flyoutOpened) { \r
3099                         contentScope.gotFocus();\r
3100                         events.preventDefault(e);\r
3101                         events.stopPropagation(e);\r
3102                     }\r
3103                 };\r
3104 \r
3105                 var lastTabableElementKeyhandler = function (e) {\r
3106                     if (!e.keyCode) {\r
3107                         e.keyCode = e.which;\r
3108                     }\r
3109                     if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {\r
3110                         contentScope.gotFocus();    \r
3111                         events.preventDefault(e);\r
3112                         events.stopPropagation(e);\r
3113                     }\r
3114                 };\r
3115                 this.associateTabEvent = function(){\r
3116                     $timeout(function () {\r
3117                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];\r
3118                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);\r
3119                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);\r
3120                         if(angular.isUndefined(firstTabableElement)){\r
3121                             angular.element(element).css('display','block');\r
3122                             firstTabableElement = b2bDOMHelper.firstTabableElement(element);\r
3123                             lastTabableElement = b2bDOMHelper.lastTabableElement(element);\r
3124                             angular.element(element).css('display','none');\r
3125                         }\r
3126                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);\r
3127                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);\r
3128                     });\r
3129                 }\r
3130                 this.updateTabbableElements = function(){\r
3131                     $timeout(function () {\r
3132                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];\r
3133                         angular.element(element).css('display','block');\r
3134                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);\r
3135                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);\r
3136                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);\r
3137                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);\r
3138                         angular.element(element).css('display','none');\r
3139                     });\r
3140                 }\r
3141                 this.unbindTabbaleEvents = function(){\r
3142                     if(angular.isDefined(firstTabableElement)){\r
3143                         angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);\r
3144                     }\r
3145 \r
3146                     if(angular.isDefined(lastTabableElement)){\r
3147                         angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);\r
3148                     }\r
3149                 }\r
3150             }],\r
3151             link: function (scope, element, attrs, ctrl) {\r
3152 \r
3153             }\r
3154         };\r
3155     }])\r
3156     .directive('b2bFlyoutToggler', [function () {\r
3157         return {\r
3158             restrict: 'A',\r
3159             require: '^b2bFlyout',\r
3160             link: function (scope, element, attrs, ctrl) {\r
3161                 element.bind('click', function (e) {\r
3162                     ctrl.toggleFlyoutState();\r
3163                 });\r
3164 \r
3165                 scope.getTogglerDimensions = function () {\r
3166                     return element[0].getBoundingClientRect();\r
3167                 }\r
3168 \r
3169                 scope.setTogglerFocus = function () {\r
3170                     element[0].focus();\r
3171                 }\r
3172 \r
3173                 ctrl.registerTogglerScope(scope);\r
3174             }\r
3175         };\r
3176     }])\r
3177     .directive('b2bFlyoutContent', ['$position', '$timeout', '$documentBind', '$isElement', '$document', function ($position, $timeout, $documentBind, $isElement, $document) {\r
3178         return {\r
3179             restrict: 'EA',\r
3180             transclude: true,\r
3181             replace: true,\r
3182             require: '^b2bFlyout',\r
3183             scope: {\r
3184                 horizontalPlacement: '@',\r
3185                 verticalPlacement: '@',\r
3186                 flyoutStyle: '@',\r
3187                 flyoutTitle: '@',\r
3188                 contentUpdated: "=?"\r
3189             },\r
3190             templateUrl: 'b2bTemplate/flyout/flyoutContent.html',\r
3191             link: function (scope, element, attrs, ctrl) {\r
3192                 var flyoutStyleArray, eachCssProperty, cssPropertyKey, cssPropertyVal, temp;\r
3193                 scope.openFlyout = false;\r
3194                 if (!scope.horizontalPlacement) {\r
3195                     scope.horizontalPlacement = 'center';\r
3196                 }\r
3197                 if (!scope.verticalPlacement) {\r
3198                     scope.verticalPlacement = 'below';\r
3199                 }\r
3200 \r
3201                 scope.toggleFlyout = function () {\r
3202 \r
3203                     scope.openFlyout = !scope.openFlyout;\r
3204 \r
3205                     if (scope.openFlyout) {\r
3206 \r
3207                         if (angular.isDefined(scope.flyoutStyle) && scope.flyoutStyle != "") {\r
3208                             flyoutStyleArray = scope.flyoutStyle.split(";");\r
3209                             for (i = 0; i < flyoutStyleArray.length; i++) {\r
3210                                 eachCssProperty = flyoutStyleArray[i].split(":");\r
3211                                 if (eachCssProperty.length == 2) {\r
3212                                     cssPropertyKey = eachCssProperty[0].trim();\r
3213                                     cssPropertyVal = eachCssProperty[1].trim();\r
3214                                     angular.element(element[0])[0].style[cssPropertyKey] = cssPropertyVal;\r
3215                                 }\r
3216                             }\r
3217                         }\r
3218 \r
3219                         angular.element(element[0]).css({\r
3220                             'opacity': 0,\r
3221                             'display': 'block'\r
3222                         });\r
3223 \r
3224                         var flyoutIcons = angular.element(document.querySelectorAll(".b2b-flyout-icon"));\r
3225                         angular.forEach(flyoutIcons, function (elm) {\r
3226                             angular.element(elm)[0].blur();\r
3227                         });\r
3228 \r
3229                         $timeout(function () {\r
3230                             ctrl.setTogglerFocus();\r
3231 \r
3232                             var togglerDimensions = ctrl.getTogglerDimensions();\r
3233                             var flyoutDimensions = element[0].getBoundingClientRect();\r
3234 \r
3235                             switch (scope.horizontalPlacement) {\r
3236                             case "left":\r
3237                                 angular.element(element[0]).css({\r
3238                                     'left': ((togglerDimensions.width / 2) - 26) + 'px'\r
3239                                 });\r
3240                                 break;\r
3241                             case "right":\r
3242                                 angular.element(element[0]).css({\r
3243                                     'right': ((togglerDimensions.width / 2) - 23) + 'px'\r
3244                                 });\r
3245                                 break;  \r
3246 \r
3247                             case "centerLeft":\r
3248                                 var marginLeft =  10-(flyoutDimensions.width)-20;\r
3249                                 angular.element(element[0]).css({\r
3250                                     'margin-left': marginLeft + 'px'\r
3251                                 });\r
3252                                 break;\r
3253                             case "centerRight":\r
3254                                 angular.element(element[0]).css({\r
3255                                     'left': ((togglerDimensions.width + 9 )) + 'px'\r
3256                                 });\r
3257                                 break;    \r
3258 \r
3259                             default:\r
3260                                 var marginLeft = (togglerDimensions.width / 2) - (flyoutDimensions.width / 2) - 8;\r
3261                                 angular.element(element[0]).css({\r
3262                                     'margin-left': marginLeft + 'px'\r
3263                                 });\r
3264                             }\r
3265 \r
3266                             switch (scope.verticalPlacement) {\r
3267                             case "above":\r
3268                                 angular.element(element[0]).css({\r
3269                                     'top': -(flyoutDimensions.height + 13) + 'px'\r
3270                                 });\r
3271                                 break;\r
3272                             case "centerLeft":\r
3273                                 angular.element(element[0]).css({\r
3274                                     'top': -((togglerDimensions.height-13))+ 'px'\r
3275                                 });\r
3276                                 break;\r
3277                             case "centerRight":\r
3278                                 angular.element(element[0]).css({\r
3279                                     'top': -(flyoutDimensions.height - 23)+ 'px'\r
3280                                 });\r
3281                                 break;                                    \r
3282                             default:\r
3283                                 angular.element(element[0]).css({\r
3284                                     'top': (togglerDimensions.height + 13) + 'px'\r
3285                                 });\r
3286                             }\r
3287 \r
3288                             angular.element(element[0]).css({\r
3289                                 'opacity': 1\r
3290                             });\r
3291                         }, 100);\r
3292                     } else {\r
3293                         scope.hideFlyout();\r
3294                     }\r
3295                 };\r
3296 \r
3297                 scope.gotFocus = function () {\r
3298                     scope.openFlyout = false;\r
3299                     scope.hideFlyout();\r
3300                     ctrl.setTogglerFocus();\r
3301                     scope.$apply();\r
3302                 };\r
3303 \r
3304                 scope.closeFromChild = function (e) {\r
3305                     scope.openFlyout = false;\r
3306                     scope.hideFlyout();\r
3307                     ctrl.setTogglerFocus();\r
3308                     scope.$apply();\r
3309                 };\r
3310 \r
3311                 scope.hideFlyout = function () {\r
3312                     angular.element(element[0]).css({\r
3313                         'opacity': 0,\r
3314                         'display': 'none'\r
3315                     });\r
3316                 };\r
3317 \r
3318                 scope.closeFlyout = function (e) {\r
3319                     var isElement = $isElement(angular.element(e.target), element, $document);\r
3320                     if ((e.type === "keydown" && e.which === 27) || ((e.type === "click" || e.type==="touchend") && !isElement)) {\r
3321                         scope.openFlyout = false;\r
3322                         scope.hideFlyout();\r
3323                         ctrl.setTogglerFocus();\r
3324                         scope.$apply();\r
3325                     }\r
3326                 };\r
3327 \r
3328                 scope.$watch('openFlyout', function () {\r
3329                     ctrl.updateAriaModel(scope.openFlyout);\r
3330                 });\r
3331 \r
3332                 $documentBind.click('openFlyout', scope.closeFlyout, scope);\r
3333                 $documentBind.event('keydown', 'openFlyout', scope.closeFlyout, scope);\r
3334                 $documentBind.event('touchend', 'openFlyout', scope.closeFlyout, scope);\r
3335                 ctrl.registerContentScope(scope);\r
3336 \r
3337                 if (angular.isDefined(scope.contentUpdated) && scope.contentUpdated !== null) {\r
3338                     scope.$watch('contentUpdated', function (newVal, oldVal) {\r
3339                         if(newVal){\r
3340                             if (newVal !== oldVal) {\r
3341                                 ctrl.unbindTabbaleEvents();\r
3342                                 ctrl.associateTabEvent();\r
3343                             }\r
3344                             scope.contentUpdated = false;\r
3345                         } \r
3346                     });\r
3347                 }  \r
3348 \r
3349             }\r
3350         };\r
3351     }])\r
3352     .directive('b2bCloseFlyout', [function () {\r
3353         return {\r
3354             restrict: 'A',\r
3355             require: '^b2bFlyout',\r
3356             scope: {\r
3357                 closeFlyout: '&'\r
3358             },\r
3359             link: function (scope, element, attrs, ctrl) {\r
3360                 element.bind('click', function (e) {\r
3361                     scope.closeFlyout(e);\r
3362                     ctrl.closeFlyout(e);\r
3363                 });\r
3364             }\r
3365         };\r
3366     }])\r
3367     .directive('b2bFlyoutTrapFocusInside', [function () {\r
3368         return {\r
3369             restrict: 'A',\r
3370             transclude: false,\r
3371             require: '^b2bFlyout',\r
3372             link: function (scope, elem, attr, ctrl) {\r
3373                 /* Before opening modal, find the focused element */\r
3374                 ctrl.updateTabbableElements();\r
3375             }\r
3376         };\r
3377     }]);\r
3378 /**\r
3379  * @ngdoc directive\r
3380  * @name Layouts.att:footer\r
3381  *\r
3382  * @description\r
3383  *  <file src="src/footer/docs/readme.md" />\r
3384  *\r
3385  * @usage\r
3386  * \r
3387  <footer class="b2b-footer-wrapper" role="contentinfo" aria-label="footer">\r
3388         <div class="b2b-footer-container" b2b-column-switch-footer footer-link-items='footerItems'>\r
3389             <hr>\r
3390             <div class="divider-bottom-footer">\r
3391                 <div class="span2 dispalyInline">&nbsp;</div>\r
3392                 <div class="span6 dispalyInline">\r
3393                     <ul class="footer-nav-content">\r
3394                         <li><a href="Terms_of_use.html" title="Terms of use" id="foot0">Terms of use</a>|</li>\r
3395                         <li><a href="Privacy_policy.html" title="Privacy policy" id="foot1" class="active">Privacy policy</a>|</li>\r
3396                         <li><a href="Tollfree_directory_assistance.html" title="Tollfree directory assistance" id="foot2">Tollfree directory assistance</a>|</li>\r
3397                         <li><a href="compliance.html" title="Accessibility" id="foot3">Accessibility</a></li>\r
3398 \r
3399                     </ul>\r
3400                     <p><a href="//www.att.com/gen/privacy-policy?pid=2587" target="_blank">© <span class="copyright">2016</span> AT&amp;T Intellectual Property</a>. All rights reserved. AT&amp;T,the AT&amp;T Globe logo and all other AT&amp;T marks contained herein are tardemarks of AT&amp;T intellectual property and/or AT&amp;T affiliated companines.\r
3401 \r
3402                     </p>\r
3403                 </div>\r
3404                 <div class="span3 footerLogo dispalyInline">\r
3405                     <a href="index.html" class="footer-logo">\r
3406                         <i class="icon-primary-att-globe"><span class="hidden-spoken">A T &amp; T</span></i>\r
3407                         <h2 class="logo-title">AT&amp;T</h2>\r
3408                     </a>\r
3409                 </div>\r
3410             </div>\r
3411 \r
3412         </div>  \r
3413     </footer>\r
3414 \r
3415  * @example\r
3416  *  <section id="code">   \r
3417  <example module="b2b.att">\r
3418  <file src="src/footer/docs/demo.html" />\r
3419  <file src="src/footer/docs/demo.js" />\r
3420  </example>\r
3421  </section>\r
3422  *\r
3423  */\r
3424 angular.module('b2b.att.footer', ['b2b.att.utilities']).\r
3425         directive('b2bColumnSwitchFooter', [function() {\r
3426                 return {\r
3427                     restrict: 'A',\r
3428                     transclude: true,\r
3429                     scope: {\r
3430                         footerLinkItems: "="\r
3431                     },\r
3432                     templateUrl: 'b2bTemplate/footer/footer_column_switch_tpl.html',\r
3433                     link: function(scope) {\r
3434                         var tempFooterColumns = scope.footerLinkItems.length;\r
3435                         scope.footerColumns = 3;\r
3436                         if ( (tempFooterColumns === 5) || (tempFooterColumns === 4) ) {\r
3437                             scope.footerColumns = tempFooterColumns;\r
3438                         }\r
3439                     }\r
3440 \r
3441                 };\r
3442 \r
3443             }]);\r
3444      \r
3445 \r
3446 /**\r
3447  * @ngdoc directive\r
3448  * @name Layouts.att:header\r
3449  *\r
3450  * @description\r
3451  *  <file src="src/header/docs/readme.md" />\r
3452  *\r
3453  * @usage\r
3454  *  <li b2b-header-menu class="header__item b2b-headermenu" ng-repeat="item in tabItems" role="presentation">\r
3455         <a href="#" class="menu__item" role="menuitem">{{item.title}}</a>\r
3456         <div class="header-secondary-wrapper">\r
3457             <ul class="header-secondary" role="menu">\r
3458                 <li class="header-subitem" b2b-header-submenu ng-repeat="i in item.subitems" role="presentation">\r
3459                     <a href="#" class="menu__item" aria-haspopup="true" role="menuitem">{{i.value}}</a>\r
3460                     <div class="header-tertiary-wrapper" ng-if="i.links">\r
3461                         <ul class="header-tertiary" role="menu">\r
3462                             <li b2b-header-tertiarymenu ng-repeat="link in i.links" role="presentation">\r
3463                                 <label>{{link.title}}</label>\r
3464                                 <div b2b-tertiary-link ng-repeat="title in link.value">\r
3465                                     <a href="{{link.href}}" class="header-tertiaryitem" ng-if="!title.subitems" aria-haspopup="false" role="menuitem"><span class="b2b-label-hide">{{link.title}}</span>{{title.title}}</a>\r
3466                                     <a href="{{link.href}}" class="header-tertiaryitem" b2b-header-togglemenu ng-if="title.subitems" aria-haspopup="true" role="menuitem"><span class="b2b-label-hide">{{link.title}}</span>{{title.title}}</a>\r
3467                                     <ul class="header-quarternary" role="menu"  ng-if="title.subitems">\r
3468                                         <li b2b-header-quarternarymenu role="presentation">\r
3469                                             <a href="{{nav.href}}" ng-repeat="nav in title.subitems" role="menuitem" aria-haspopup="true">{{nav.title}}</a>\r
3470                                         </li>\r
3471                                     </ul>\r
3472                                 </div>\r
3473                             </li>\r
3474                         </ul>\r
3475                     </div>\r
3476                 </li>\r
3477             </ul>\r
3478         </div>\r
3479     </li> \r
3480  *\r
3481  * @example\r
3482  *  <section id="code">\r
3483  <example module="b2b.att.header">\r
3484  <file src="src/header/docs/demo.html" />\r
3485  <file src="src/header/docs/demo.js" />\r
3486  </example>\r
3487  </section>\r
3488  *\r
3489  */\r
3490 angular.module('b2b.att.header', ['b2b.att.dropdowns','b2b.att.utilities'])\r
3491     .directive('b2bHeaderMenu', ['keymap', '$documentBind', '$timeout', '$isElement', '$document', function (keymap, $documentBind, $timeout, $isElement, $document) {\r
3492         return {\r
3493             restrict: 'A',\r
3494             controller:['$scope',function($scope){\r
3495                 this.nextSiblingFocus = function (elObj,flag) {\r
3496                         if (elObj.nextElementSibling) {\r
3497                             if(flag){\r
3498                                 var nextmenuItem = this.getFirstElement(elObj.nextElementSibling,'a');\r
3499                                 nextmenuItem.focus();\r
3500                             }else{\r
3501                                 elObj.nextElementSibling.focus();\r
3502                             }\r
3503                         }\r
3504                 };\r
3505                 \r
3506                 this.previousSiblingFocus = function (elObj,flag) {\r
3507                         if (elObj.previousElementSibling) {\r
3508                             if(flag){\r
3509                                 var prevmenuItem = this.getFirstElement(elObj.previousElementSibling,'a');\r
3510                                 prevmenuItem.focus();\r
3511                             }else{\r
3512                                 elObj.previousElementSibling.focus();\r
3513                             }\r
3514                         }\r
3515                 };\r
3516                     \r
3517                 this.getFirstElement = function(elmObj,selector){\r
3518                         return elmObj.querySelector(selector);                        \r
3519                     };\r
3520             }],\r
3521             link: function (scope, elem,attr,ctrl) {\r
3522                 scope.showMenu = false;\r
3523                 var activeElm, subMenu, tertiaryMenu, el= angular.element(elem)[0], \r
3524                         menuItem = angular.element(elem[0].children[0]);\r
3525                 menuItem.bind('click', function () {\r
3526                     elem.parent().children().removeClass('active');\r
3527                     elem.addClass('active');\r
3528                     var elems= this.parentElement.parentElement.querySelectorAll('li[b2b-header-menu]>a');\r
3529                     for (var i=0; i<elems.length; i++) {\r
3530                         elems[i].setAttribute("aria-expanded",false);\r
3531                     }\r
3532                     scope.showMenu = true;\r
3533                     var elmTofocus = ctrl.getFirstElement(this.parentElement,'li[b2b-header-submenu]');\r
3534                     elmTofocus.firstElementChild.focus();\r
3535                     this.setAttribute('aria-expanded',true);\r
3536                     scope.$apply();\r
3537                 });\r
3538                \r
3539                 elem.bind('keydown', function (evt) {\r
3540                     activeElm = document.activeElement;\r
3541                     subMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-submenu]');\r
3542                     tertiaryMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-tertiarymenu]');\r
3543                     switch (evt.keyCode) {\r
3544                         case keymap.KEY.ENTER:\r
3545                         case keymap.KEY.SPACE:\r
3546                             elem[0].click();\r
3547                             break;\r
3548                         case keymap.KEY.UP:\r
3549                             evt.stopPropagation();\r
3550                             evt.preventDefault();\r
3551                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {\r
3552                                 menuItem[0].focus();\r
3553                             }\r
3554                             break;\r
3555                         case keymap.KEY.DOWN:\r
3556                             evt.stopPropagation();\r
3557                             evt.preventDefault();\r
3558                             if (subMenu) {\r
3559                                 subMenu.firstElementChild.focus();\r
3560                             } else if (tertiaryMenu) {\r
3561                                 var firstSubitem = ctrl.getFirstElement(tertiaryMenu,'a.header-tertiaryitem');\r
3562                                 firstSubitem.focus();\r
3563                             }\r
3564                             break;\r
3565                         case keymap.KEY.RIGHT:\r
3566                             evt.stopPropagation();\r
3567                             evt.preventDefault();\r
3568                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {\r
3569                                 var elm = angular.element(activeElm.parentElement)[0];\r
3570                                 ctrl.nextSiblingFocus(elm,true);\r
3571                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {\r
3572                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];\r
3573                                 if (tertiaryLI.nextElementSibling) {\r
3574                                     var nextElm = ctrl.getFirstElement(tertiaryLI.nextElementSibling,"a.header-tertiaryitem");\r
3575                                     nextElm.focus();\r
3576                                 }\r
3577                             }\r
3578                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')){\r
3579                                 ctrl.nextSiblingFocus(el,true);\r
3580                             }\r
3581                             break;\r
3582                         case keymap.KEY.LEFT:\r
3583                             evt.stopPropagation();\r
3584                             evt.preventDefault();\r
3585                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {\r
3586                                 var previousElm = angular.element(activeElm.parentElement)[0];\r
3587                                 ctrl.previousSiblingFocus(previousElm,true);\r
3588                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {\r
3589                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];\r
3590                                 if (tertiaryLI.previousElementSibling) {\r
3591                                     var prevElm = ctrl.getFirstElement(tertiaryLI.previousElementSibling,"a.header-tertiaryitem");\r
3592                                     prevElm.focus();\r
3593                                 }\r
3594                             }\r
3595                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')) {\r
3596                                 ctrl.previousSiblingFocus(el,true);\r
3597                             }\r
3598                             break;\r
3599                         case keymap.KEY.ESC:\r
3600                             evt.stopPropagation();\r
3601                             evt.preventDefault();\r
3602                             scope.showMenu = false;\r
3603                             elem.removeClass('active');\r
3604                             menuItem.attr('aria-expanded',false);\r
3605                             $timeout(function(){\r
3606                                 menuItem[0].focus();\r
3607                             },100);\r
3608                             scope.$apply();\r
3609                             break;\r
3610                         default:\r
3611                             break;\r
3612                     }\r
3613                 });\r
3614                 var outsideClick = function (e) {\r
3615                     var isElement = $isElement(angular.element(e.target), elem, $document);\r
3616                     if (!isElement) {\r
3617                         scope.showMenu = false;\r
3618                         elem.removeClass('active');\r
3619                         scope.$apply();\r
3620                     }\r
3621                 };\r
3622                 $documentBind.click('showMenu', outsideClick, scope);\r
3623                 /*Change for ECOMP - hide header menu when click on iframe in a new tab*/\r
3624                 $(window).blur(function() {\r
3625                         if(scope.showMenu){\r
3626                          scope.showMenu = false;\r
3627                      elem.removeClass('active');\r
3628                      scope.$apply();\r
3629                         }\r
3630                 });\r
3631             }\r
3632         };\r
3633     }]).directive('b2bHeaderSubmenu', ['$timeout',function ($timeout) {\r
3634         return{\r
3635             restrict: 'A',\r
3636             link: function (scope, elem) {\r
3637                 var caretSign = angular.element("<i class='menuCaret'></i>");\r
3638                 $timeout(function(){\r
3639                     var menuItem = angular.element(elem[0].children[0]);\r
3640                     menuItem.bind('focus mouseenter', function () {\r
3641                         elem.parent().children().removeClass('active');\r
3642                         elem.addClass('active');\r
3643                         if(elem[0].childElementCount > 1){ // > 1 has third level menu\r
3644                             menuItem.attr('aria-expanded',true);\r
3645                             menuItem.attr('aria-haspopup',true);\r
3646                         }\r
3647                         var caretLeft = (elem[0].offsetLeft +  elem[0].offsetWidth/2) - 10;\r
3648                         caretSign.css({left: caretLeft + 'px'});\r
3649                         angular.element(caretSign);\r
3650                         var tertiaryItems = elem[0].querySelectorAll('[b2b-header-tertiarymenu]');\r
3651                         if(tertiaryItems.length >=1){\r
3652                             elem.append(caretSign);\r
3653                         }\r
3654                     });\r
3655                     menuItem.bind('blur', function () {\r
3656                         $timeout(function () {\r
3657                             var parentElm = document.activeElement.parentElement.parentElement;\r
3658                             if(parentElm){\r
3659                                 if (!(parentElm.hasAttribute('b2b-header-tertiarymenu'))) {\r
3660                                     elem.removeClass('active');\r
3661                                     if(elem[0].childElementCount > 1){ // > 1 has third level menu\r
3662                                         menuItem.attr('aria-expanded',false);\r
3663                                     }\r
3664                                     var caret = elem[0].querySelector('.menuCaret');\r
3665                                     if(caret){\r
3666                                         caret.remove();\r
3667                                     }   \r
3668                                 }\r
3669                             }\r
3670                         });\r
3671                     });\r
3672                 });\r
3673             }\r
3674         };\r
3675     }]).directive('b2bHeaderTertiarymenu', ['$timeout','keymap', function ($timeout,keymap){\r
3676         return{\r
3677             restrict: 'A',\r
3678             require:'^b2bHeaderMenu',\r
3679             link: function (scope, elem,attr,ctrl) {\r
3680                 \r
3681                 elem.bind('keydown', function (evt) {\r
3682                     var activeElm = document.activeElement;\r
3683                     var activeParentElm = activeElm.parentElement;\r
3684                     var activeParentObj  = angular.element(activeParentElm)[0];\r
3685                     \r
3686                     if(activeParentElm.hasAttribute('b2b-tertiary-link')){\r
3687                         var quarterNav = angular.element(activeParentElm)[0].querySelector('li[b2b-header-quarternarymenu]');\r
3688                         if(quarterNav){\r
3689                             var links = ctrl.getFirstElement(angular.element(quarterNav)[0],'a');\r
3690                         }\r
3691                     }\r
3692                     var tertiaryMenu = activeElm.parentElement.parentElement.parentElement;\r
3693                     var tertiaryMenuFlag = tertiaryMenu.hasAttribute('b2b-tertiary-link');\r
3694                     \r
3695                     switch (evt.keyCode) {\r
3696                         case keymap.KEY.DOWN:\r
3697                             evt.stopPropagation();\r
3698                             evt.preventDefault();\r
3699                             if (activeParentElm.hasAttribute('b2b-tertiary-link')) {\r
3700                                 if(angular.element(quarterNav).hasClass('active')){\r
3701                                     links.focus();\r
3702                                 }else if(activeParentObj.nextElementSibling){\r
3703                                     ctrl.nextSiblingFocus(activeParentObj,true);\r
3704                                 }\r
3705                             }\r
3706                             else if(angular.element(activeParentElm).hasClass('active')){\r
3707                                 ctrl.nextSiblingFocus(activeElm);\r
3708                             }\r
3709                             break;                        \r
3710                         case keymap.KEY.UP:\r
3711                             evt.stopPropagation();\r
3712                             evt.preventDefault();\r
3713                             if(activeParentElm.hasAttribute('b2b-tertiary-link')){\r
3714                                 if(activeParentObj.previousElementSibling.hasAttribute('b2b-tertiary-link')){\r
3715                                     ctrl.previousSiblingFocus(activeParentObj,true);\r
3716                                 }else{\r
3717                                     var elm = angular.element(activeElm.parentElement.parentElement.parentElement.parentElement.parentElement)[0];\r
3718                                     ctrl.getFirstElement(elm,"a").focus();\r
3719                                 }\r
3720                             }else if(angular.element(activeParentElm).hasClass('active')){\r
3721                                     if (activeElm.previousElementSibling) {\r
3722                                         ctrl.previousSiblingFocus(activeElm);\r
3723                                     }else if (tertiaryMenuFlag) {\r
3724                                         var elm = angular.element(tertiaryMenu)[0];\r
3725                                         ctrl.getFirstElement(elm,"a.header-tertiaryitem").focus();\r
3726                                     }\r
3727                                 }\r
3728                             break;\r
3729                         default:\r
3730                             break;\r
3731                     }\r
3732                 });\r
3733             }            \r
3734         };          \r
3735     }]).directive('b2bHeaderTogglemenu', ['$timeout', 'keymap', function ($timeout, keymap) {\r
3736         return{\r
3737             restrict: 'A',\r
3738             require: '^b2bHeaderMenu',\r
3739             link: function (scope, elem, attrs, ctrl) {\r
3740                 var quarterNav;\r
3741                 $timeout(function () {\r
3742                     quarterNav = angular.element(elem.parent())[0].querySelector('li[b2b-header-quarternarymenu]');\r
3743                     elem.bind('click', function () {\r
3744                         angular.element(quarterNav).toggleClass('active');\r
3745                     });\r
3746                 });\r
3747             }\r
3748         };\r
3749     }]).directive('b2bHeaderResponsive', ['$timeout',function ($timeout) {\r
3750         return{\r
3751             restrict: 'A',\r
3752             controller: function($scope){\r
3753                 this.applyMediaQueries = function(value){\r
3754                     document.querySelector('style').textContent += \r
3755                         "@media screen and (max-width:950px) { \\r
3756                             .header__item.profile { right: " + value + "px; } \\r
3757                         }";\r
3758                 };\r
3759                 this.arrangeResponsiveHeader = function(children){\r
3760                     /* \r
3761                      * clientWidth of 1090 === max-width of 1100px\r
3762                      * clientWidth of 920 === max-width of 950px\r
3763                      * see b2b-angular.css for rest of responsive header CSS\r
3764                      */\r
3765                   if (document.documentElement.clientWidth <= 920) { \r
3766                         switch(children){\r
3767                             case 1:\r
3768                                 this.applyMediaQueries(200);                    \r
3769                                 break;\r
3770                             case 2:\r
3771                                 this.applyMediaQueries(200);                            \r
3772                                 break;\r
3773                             default: // anthing above 3, however, should not have more than 3 to date\r
3774                                 this.applyMediaQueries(200);                                                                            \r
3775                         }\r
3776                     }\r
3777                 }\r
3778             },\r
3779             link: function (scope, elem, attrs, ctrl) {\r
3780                 var children;\r
3781                 var profile;\r
3782                 \r
3783                 // onload of page\r
3784                 $timeout(function(){ \r
3785                     profile = document.querySelector('li.header__item.profile');\r
3786                     children = angular.element(profile).children().length;\r
3787                     \r
3788                     ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers\r
3789                 });\r
3790 \r
3791                 // on screen resize\r
3792                 window.addEventListener('resize', function(event){ // caret adjustmet\r
3793                     var activeSubmenu = elem[0].querySelector('[b2b-header-menu] [b2b-header-submenu].active');\r
3794                     var activeSubmenuEl = angular.element(activeSubmenu);\r
3795                     if(activeSubmenu){\r
3796                         var caretSign = activeSubmenu.querySelector('i.menuCaret');\r
3797                         if(caretSign){\r
3798                             var caretSignEl = angular.element(caretSign);\r
3799                             var caretLeft = (activeSubmenu.offsetLeft +  activeSubmenu.offsetWidth/2) - 10;\r
3800                             caretSignEl.css({left: caretLeft + 'px'});\r
3801                         }\r
3802                     }\r
3803 \r
3804                     ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers\r
3805                 });\r
3806             }\r
3807         };\r
3808     }]);\r
3809 \r
3810 /**\r
3811  * @ngdoc directive\r
3812  * @name Layouts.att:headings\r
3813  *\r
3814  * @description\r
3815  *  <file src="src/headings/docs/readme.md" />\r
3816  *\r
3817  * @usage\r
3818     <h1 class="heading-page">38px page heading</h1>\r
3819     <h2 class="heading-major-section">30px major section heading</h2>\r
3820     <h3 class="heading-sub-section">24px sub-section heading</h3>\r
3821     <h2 class="heading-medium">20px medium heading</h2>\r
3822     <h2 class="heading-medium-emphasis">20px medium emphasis heading</h2>\r
3823     <h3 class="heading-small">18px small heading</h3>\r
3824     <h3 class="heading-small-emphasis">18px small emphasis heading</h3>\r
3825     <h3 class="heading-micro">13px micro heading</h3>\r
3826 \r
3827     <h2 class="heading-group">Lead</h2>\r
3828     <h1 class="heading-page">This is 38px heading</h1>\r
3829     <h2 class="lead">This is lead text...The next big thing since the last big thing we announced.</h2>\r
3830     <h2 class="heading-group">Eyebrow</h2>\r
3831     <h3 class="eyebrow">EYEBROW TEXT</h3>\r
3832     <h2 class="heading-major-section">This is a 30px heading</h2>\r
3833     <h3 class="eyebrow">EYEBROW TEXT</h3>\r
3834     <h3 class="heading-sub-section">24px sub-section heading</h3>\r
3835     <h2 class="heading-group">Subheading</h2>\r
3836     <h2 class="heading-major-section">This is a 30px heading</h2>\r
3837     <h3 class="subheading">A subheading here to support what was said above</h3>\r
3838  * @example\r
3839  <section id="code">\r
3840     <b>HTML + AngularJS</b>\r
3841     <example module="b2b.att">\r
3842     <file src="src/headings/docs/demo.html" />\r
3843 </example>\r
3844 </section>\r
3845  */\r
3846 \r
3847 var b2bLegalCopy = angular.module('b2b.att.headings', []);\r
3848 /**\r
3849  * @ngdoc directive\r
3850  * @name Tabs, tables & accordions.att:horizontalTable\r
3851  *\r
3852  * @description\r
3853  *  <file src="src/horizontalTable/docs/readme.md" />\r
3854  *\r
3855  * @usage\r
3856  * @param {int} sticky - Number of sticky columns to have. Maximum of 3.\r
3857  * @param {boolean} refresh - A boolean that when set to true will force a re-render of table. Only use when using 'bulk mode'\r
3858  * @example\r
3859  *  <section id="code">\r
3860         <example module="b2b.att">\r
3861             <file src="src/horizontalTable/docs/demo.html" />\r
3862             <file src="src/horizontalTable/docs/demo.js" />\r
3863        </example>\r
3864     </section>\r
3865  *\r
3866  */\r
3867 angular.module('b2b.att.horizontalTable', [])\r
3868     .constant('b2bHorizontalTableConfig', {\r
3869         'maxStickyColumns': 3\r
3870     })\r
3871     .directive('b2bHorizontalTable', ['$timeout', 'b2bHorizontalTableConfig', 'b2bDOMHelper', function ($timeout, b2bHorizontalTableConfig, b2bDOMHelper) {\r
3872         return {\r
3873             restrict: 'EA',\r
3874             scope: true,\r
3875             transclude: true,\r
3876             scope: {\r
3877                 numOfStickyCols: '=?sticky',\r
3878                 refresh: '=?'\r
3879 \r
3880             },\r
3881             templateUrl: 'b2bTemplate/horizontalTable/horizontalTable.html',\r
3882             link: function (scope, element, attrs, ctrl) {\r
3883                 scope.numOfStickyCols = scope.numOfStickyCols || 1;\r
3884                 scope.viewportIndex = scope.numOfStickyCols;\r
3885 \r
3886                 // JM520E: This is a temporary hack until I solve the ngRepeat issue\r
3887                 function hack() {\r
3888                     if (element.find('th').length < scope.numOfStickyCols) {\r
3889                         // DOM ngRepeat is not ready, let's check back in 10 ms\r
3890                         console.info('THs are not ready, trying again in 10ms');\r
3891                         $timeout(hack, 10, false);\r
3892                     } else {\r
3893                         init();\r
3894                     }\r
3895                 }\r
3896                 hack();\r
3897 \r
3898                 if (attrs.refresh !== undefined && attrs.refresh !== '') {\r
3899                     scope.$watch('refresh', function(oldVal, newVal) {\r
3900                         if (scope.refresh) {\r
3901                             // From testing it takes about 30 ms before ngRepeat executes, so let's set initial timeout\r
3902                             // NOTE: May need to expose timeout to developers. Application is known to have digest cycle of 3-5k watches.\r
3903                             $timeout(init, 100, false);\r
3904                             scope.refresh = false;\r
3905                         }\r
3906                     });\r
3907                 }\r
3908 \r
3909                 var tableElement = element.find('table');\r
3910                 var thElements = element.find('th');\r
3911                 var innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));\r
3912                 var outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));\r
3913 \r
3914                 var tableColumns = [];\r
3915                 var tableRows = element.find('tr');\r
3916 \r
3917                 var maxWidth = 0,\r
3918                     maxHeight = 0;\r
3919                 var totalWidth = element.children()[0].offsetWidth;\r
3920                 var lastVisibleColumn = 0;\r
3921                 var collectiveColumnWidth = [];\r
3922                 var collectiveRowHeight = [];\r
3923                 var columnSets = [];\r
3924                 var setIndex = 0; \r
3925                 var stickyPixels = 0;\r
3926 \r
3927                 var displayNoneCSS = {'display': 'none'};\r
3928                 var displayBlockCSS = {'display': 'table-cell'};\r
3929 \r
3930                 function calculateVisibleColumns(startingPoint) {\r
3931                     var usedWidth = 0, \r
3932                         visibleColumns = startingPoint || scope.numOfStickyCols;\r
3933 \r
3934                     while(usedWidth < stickyPixels && visibleColumns < collectiveColumnWidth.length) {\r
3935                         if (usedWidth+collectiveColumnWidth[visibleColumns] > stickyPixels) {\r
3936                             if (startingPoint === visibleColumns) {\r
3937                                 return visibleColumns; // The next cell is too large to fit, it should be only thing to fit\r
3938                             }\r
3939                             visibleColumns--;\r
3940                             return visibleColumns;\r
3941                         }\r
3942                         usedWidth += collectiveColumnWidth[visibleColumns];\r
3943                         visibleColumns++;\r
3944                     }\r
3945 \r
3946                     if (usedWidth > stickyPixels) {\r
3947                         return --visibleColumns;\r
3948                     }\r
3949                     return visibleColumns;\r
3950                 }\r
3951 \r
3952                 function updateCellDisplay(set) {\r
3953                     for (var i = scope.numOfStickyCols; i < tableColumns.length; i++) {\r
3954                         angular.element(tableColumns[i]).css(displayNoneCSS);\r
3955                     }\r
3956 \r
3957                     for (var i = set[0]; i <= set[1]; i++) {\r
3958                         angular.element(tableColumns[i]).css(displayBlockCSS);\r
3959                     }\r
3960                 }\r
3961 \r
3962                 function forceDigest() {\r
3963                     if (!scope.$$phase) {\r
3964                         scope.$digest();\r
3965                     }\r
3966                 }\r
3967 \r
3968                 function findMax(arr, prop) {\r
3969                     var max = 0;\r
3970                     var localVal = 0;\r
3971                     var prevDisplay;\r
3972                     var item;\r
3973                     for (var i = 0; i < arr.length; i++) {\r
3974                         item = arr[i];\r
3975                         prevDisplay = angular.element(item).css('display');\r
3976                         if (scope.$$phase) {\r
3977                             scope.$digest();\r
3978                         }\r
3979                         if (prop === 'width') {\r
3980                             localVal = Math.ceil(parseInt(window.getComputedStyle(item).width.split('px')[0], 10)) + 30; // 30 px is padding\r
3981                         } else if (prop === 'offsetWidth') {\r
3982                             localVal = item.offsetWidth;\r
3983                         } else if (prop === 'height') {\r
3984                             localVal = item.offsetHeight;\r
3985                         }\r
3986 \r
3987                         if (localVal >= max) {\r
3988                             max = localVal;\r
3989                         }\r
3990                     }\r
3991                     \r
3992                     return max;\r
3993                 }\r
3994 \r
3995                 function init() {\r
3996                     // Reset this from a previous execution\r
3997                     tableColumns = [];\r
3998                     collectiveColumnWidth = [];\r
3999                     collectiveRowHeight = [];\r
4000                     maxWidth = 0;\r
4001                     maxHeight = 0;\r
4002                     lastVisibleColumn = 0;\r
4003                     columnSets = [];\r
4004                     setIndex = 0; \r
4005                     visibleColumns = [];\r
4006                     stickyPixels = 0;\r
4007 \r
4008                     tableElement = element.find('table');\r
4009                     thElements = element.find('th');\r
4010                     innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));\r
4011                     outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));\r
4012                     totalWidth = element.children()[0].offsetWidth;\r
4013 \r
4014 \r
4015                     tableRows = element.find('tr');\r
4016                     totalWidth = element.children()[0].offsetWidth;\r
4017 \r
4018                     scope.disableLeft = true;\r
4019                     scope.disableRight = false;\r
4020 \r
4021                     if (scope.numOfStickyCols > b2bHorizontalTableConfig.maxStickyColumns) {\r
4022                         throw new Error("Table can only support 3 sticky columns.");\r
4023                     }                  \r
4024 \r
4025                     angular.forEach(tableRows, function(row, rowIndex) {\r
4026                         collectiveRowHeight.push(findMax(row.children, 'height'));\r
4027                         for(var j = 0; j < row.children.length; j++) {\r
4028                             if (tableColumns[j] === undefined) {\r
4029                                 tableColumns[j] = [];\r
4030                             }\r
4031                             tableColumns[j].push(row.children[j]);\r
4032                         }\r
4033                     });\r
4034 \r
4035                     // We need to reset all the displayNones from previous runs, if applicable\r
4036                     if (attrs.refresh !== undefined && attrs.refresh !== '')  {\r
4037                         for (var i = scope.numOfStickyCols+1; i < tableColumns.length; i++) {\r
4038                             angular.element(tableColumns[i]).css(displayBlockCSS);\r
4039                         }\r
4040                     }\r
4041 \r
4042                     for (var i = 0; i < tableColumns.length; i++) {\r
4043                         collectiveColumnWidth.push(findMax(tableColumns[i], 'width')); //offsetWidth doesn't take into account custom css inside\r
4044                     }\r
4045                     for(var i = 0; i < scope.numOfStickyCols; i++) {\r
4046                         maxWidth += collectiveColumnWidth[i];\r
4047                     }\r
4048       \r
4049                     stickyPixels = totalWidth-maxWidth;\r
4050 \r
4051 \r
4052                     // At this point, for each tr, I need to set the properties (height) and each numOfStickyCols children\r
4053                     // should be set with sticky properties (margin-left and width)\r
4054                     var width = maxWidth;\r
4055                     for(var i = 0; i < scope.numOfStickyCols; i++) {\r
4056                         for (var j = 0; j < tableRows.length; j++) {\r
4057                             trObject = angular.element(tableRows[j].children[i]);\r
4058                             \r
4059                             angular.element(trObject).css({\r
4060                                 'margin-left': -(width + 2) + 'px', \r
4061                                 'width': (collectiveColumnWidth[i] + 3) + 'px', // instead of taking the max width, grab max width for that column\r
4062                                 'height': collectiveRowHeight[j] + 'px',\r
4063                                 'position': 'absolute',\r
4064                                 'background-color': 'lightgrey'\r
4065                             });\r
4066                         }\r
4067                         \r
4068 \r
4069                         width -= collectiveColumnWidth[i];\r
4070                     }\r
4071 \r
4072                     innerContainer.css({\r
4073                         'padding-left': (maxWidth + 2) + 'px'\r
4074                     });\r
4075 \r
4076 \r
4077                     // Let's precompute all the (set) combinations beforehand\r
4078                     columnSets = []; \r
4079                     for (var i = scope.numOfStickyCols; i < tableColumns.length;) {\r
4080                         visibleColumns = calculateVisibleColumns(i);\r
4081                         columnSets.push([i, visibleColumns]);\r
4082                         i = visibleColumns + 1;\r
4083                     }\r
4084                     \r
4085                     updateCellDisplay(columnSets[setIndex]);\r
4086                     checkScrollArrows();\r
4087 \r
4088                     scope.numOfCols = tableColumns.length;\r
4089 \r
4090                     console.log('Bulk Mode is ' + (attrs.bulkMode ? 'enabled': 'disabled'));\r
4091                     console.log('tableColumns', tableColumns);\r
4092                     console.log('collectiveColumnWidth: ', collectiveColumnWidth);\r
4093                     console.log('maxWidth: ', maxWidth);\r
4094                 }\r
4095 \r
4096                 function checkScrollArrows() {\r
4097                     scope.disableLeft = (setIndex === 0);\r
4098                     scope.disableRight = !(setIndex < columnSets.length-1);\r
4099                 }\r
4100 \r
4101 \r
4102                 scope.moveViewportLeft = function () {\r
4103                     setIndex--;\r
4104                     updateCellDisplay(columnSets[setIndex]);\r
4105                     checkScrollArrows();\r
4106 \r
4107                     if (scope.disableLeft) {\r
4108                         element.find('span')[0].focus();\r
4109                     }\r
4110                 };\r
4111                 \r
4112                 scope.moveViewportRight = function () {\r
4113                     setIndex++;\r
4114                     updateCellDisplay(columnSets[setIndex]);\r
4115                     checkScrollArrows();\r
4116                     \r
4117                     if (scope.disableRight) {\r
4118                         element.find('span')[0].focus();\r
4119                     }\r
4120                 };\r
4121 \r
4122                 scope.getColumnSet = function () {\r
4123                     return columnSets[setIndex];\r
4124                 };\r
4125 \r
4126                 innerContainer.bind('scroll', function () {\r
4127                     $timeout(function () {\r
4128                         checkScrollArrows();\r
4129                     }, 1);\r
4130                 });\r
4131 \r
4132             }\r
4133         };\r
4134     }]);\r
4135 /**\r
4136  * @ngdoc directive\r
4137  * @name Forms.att:hourPicker\r
4138  *\r
4139  * @description\r
4140  *  <file src="src/hourPicker/docs/readme.md" />\r
4141  *\r
4142  * @usage\r
4143  * <div b2b-hourpicker ng-model="hourpickerValue.value"></div>\r
4144     \r
4145  * @example\r
4146  *  <section id="code">\r
4147         <example module="b2b.att">\r
4148             <file src="src/hourPicker/docs/demo.html" />\r
4149             <file src="src/hourPicker/docs/demo.js" />\r
4150         </example>\r
4151     </section>\r
4152  *\r
4153  */\r
4154 angular.module('b2b.att.hourPicker', ['b2b.att.utilities'])\r
4155 \r
4156 .constant('b2bHourpickerConfig', {\r
4157     dayOptions: [{\r
4158         title: 'sunday',\r
4159         caption: 'Sun',\r
4160         label: 'S',\r
4161         disabled: false\r
4162     }, {\r
4163         title: 'monday',\r
4164         caption: 'Mon',\r
4165         label: 'M',\r
4166         disabled: false\r
4167     }, {\r
4168         title: 'tuesday',\r
4169         caption: 'Tues',\r
4170         label: 'T',\r
4171         disabled: false\r
4172     }, {\r
4173         title: 'wednesday',\r
4174         caption: 'Wed',\r
4175         label: 'W',\r
4176         disabled: false\r
4177     }, {\r
4178         title: 'thursday',\r
4179         caption: 'Thu',\r
4180         label: 'T',\r
4181         disabled: false\r
4182     }, {\r
4183         title: 'friday',\r
4184         caption: 'Fri',\r
4185         label: 'F',\r
4186         disabled: false\r
4187     }, {\r
4188         title: 'saturday',\r
4189         caption: 'Sat',\r
4190         label: 'S',\r
4191         disabled: false\r
4192     }],\r
4193     startTimeOptions: ['1:00', '2:00', '3:00', '4:00', '5:00', '6:00', '7:00', '8:00', '9:00', '10:00', '11:00', '12:00'],\r
4194     startTimeDefaultOptionIndex: -1,\r
4195     startTimeDefaultMeridiem: "am",\r
4196     endTimeOptions: ['1:00', '2:00', '3:00', '4:00', '5:00', '6:00', '7:00', '8:00', '9:00', '10:00', '11:00', '12:00'],\r
4197     endTimeDefaultOptionIndex: -1,\r
4198     endTimeDefaultMeridiem: "pm",\r
4199     sameDayOption: true\r
4200 })\r
4201 \r
4202 .factory('b2bNormalizeHourpickerValues', [function () {\r
4203     var _normalize = function (hourpickerValues) {\r
4204         if (angular.isDefined(hourpickerValues) && hourpickerValues != null) {\r
4205             var finalHourpickerValues = [];\r
4206             var hourpickerValue = {};\r
4207             var days = {};\r
4208             for (var i = 0; i < hourpickerValues.length; i++) {\r
4209                 days = hourpickerValues[i].days ? hourpickerValues[i].days : {};\r
4210                 hourpickerValue.startTime = hourpickerValues[i].startTime ? hourpickerValues[i].startTime : '';\r
4211                 hourpickerValue.startMeridiem = hourpickerValues[i].startMeridiem ? hourpickerValues[i].startMeridiem : '';\r
4212                 hourpickerValue.endTime = hourpickerValues[i].endTime ? hourpickerValues[i].endTime : '';\r
4213                 hourpickerValue.endMeridiem = hourpickerValues[i].endMeridiem ? hourpickerValues[i].endMeridiem : '';\r
4214                 hourpickerValue.days = [];\r
4215 \r
4216                 var retrieveDaysText = function (daysDetails) {\r
4217                     var daysTexts = [];\r
4218                     var first = -1;\r
4219                     var last = -1;\r
4220                     var index = -1;\r
4221                     for (var i in days) {\r
4222                         if (days[i].value) {\r
4223                             daysTexts.push(i);\r
4224                         }\r
4225                     }\r
4226 \r
4227                     first = daysTexts[0];\r
4228                     last = daysTexts[0];\r
4229                     index = 0;\r
4230                     hourpickerValue.days[index] = days[first].caption;\r
4231                     if (daysTexts.length > 1) {\r
4232                         for (var i = 1; i < daysTexts.length; i++) {\r
4233                             if (daysTexts[i] - last === 1) {\r
4234                                 last = daysTexts[i];\r
4235                                 hourpickerValue.days[index] = days[first].caption + ' - ' + days[last].caption;\r
4236                             } else {\r
4237                                 index++;\r
4238                                 first = last = daysTexts[i];\r
4239                                 hourpickerValue.days[index] = days[first].caption;\r
4240                             }\r
4241                         }\r
4242                     }\r
4243                 };\r
4244                 retrieveDaysText();\r
4245 \r
4246                 finalHourpickerValues.push(angular.copy(hourpickerValue));\r
4247             }\r
4248 \r
4249             return angular.copy(finalHourpickerValues);\r
4250         }\r
4251     };\r
4252 \r
4253     return {\r
4254         normalize: _normalize\r
4255     };\r
4256 }])\r
4257 \r
4258 .directive('b2bHourpicker', ['b2bHourpickerConfig', 'b2bNormalizeHourpickerValues', function (b2bHourpickerConfig, b2bNormalizeHourpickerValues) {\r
4259     return {\r
4260         restrict: 'EA',\r
4261         replace: false,\r
4262         scope: true,\r
4263         require: 'ngModel',\r
4264         templateUrl: 'b2bTemplate/hourPicker/b2bHourpicker.html',\r
4265         controller: ['$scope', function (scope) {\r
4266 \r
4267         }],\r
4268         link: function (scope, elem, attr, ctrl) {\r
4269             scope.hourpicker = {};\r
4270             scope.hourpicker.dayOptions = attr.dayOptions ? scope.$parent.$eval(attr.dayOptions) : b2bHourpickerConfig.dayOptions;\r
4271             scope.hourpicker.startTimeOptions = attr.startTimeOptions ? scope.$parent.$eval(attr.startTimeOptions) : b2bHourpickerConfig.startTimeOptions;\r
4272             scope.hourpicker.endTimeOptions = attr.endTimeOptions ? scope.$parent.$eval(attr.endTimeOptions) : b2bHourpickerConfig.endTimeOptions;\r
4273             scope.hourpicker.startTimeDefaultOptionIndex = attr.startTimeDefaultOptionIndex ? scope.$parent.$eval(attr.startTimeDefaultOptionIndex) : b2bHourpickerConfig.startTimeDefaultOptionIndex;\r
4274             scope.hourpicker.endTimeDefaultOptionIndex = attr.endTimeDefaultOptionIndex ? scope.$parent.$eval(attr.endTimeDefaultOptionIndex) : b2bHourpickerConfig.endTimeDefaultOptionIndex;\r
4275             scope.hourpicker.startTimeDefaultMeridiem = attr.startTimeDefaultMeridiem ? scope.$parent.$eval(attr.startTimeDefaultMeridiem) : b2bHourpickerConfig.startTimeDefaultMeridiem;\r
4276             scope.hourpicker.endTimeDefaultMeridiem = attr.endTimeDefaultMeridiem ? scope.$parent.$eval(attr.endTimeDefaultMeridiem) : b2bHourpickerConfig.endTimeDefaultMeridiem;\r
4277             scope.hourpicker.sameDayOption = attr.sameDayOption ? scope.$parent.$eval(attr.sameDayOption) : b2bHourpickerConfig.sameDayOption;\r
4278             scope.hourpicker.editMode = -1;\r
4279 \r
4280             scope.hourpickerValues = [];\r
4281             scope.finalHourpickerValues = [];\r
4282             scope.addHourpickerValue = function (hourpickerPanelValue) {\r
4283                 if (hourpickerPanelValue) {\r
4284                     if (scope.hourpicker.editMode > -1) {\r
4285                         scope.hourpickerValues[scope.hourpicker.editMode] = hourpickerPanelValue;\r
4286                         scope.hourpicker.editMode = -1;\r
4287                     } else {\r
4288                         scope.hourpickerValues.push(hourpickerPanelValue);\r
4289                     }\r
4290                 }\r
4291                 scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));\r
4292                 ctrl.$setViewValue(angular.copy(scope.hourpickerValues));\r
4293             };\r
4294             ctrl.$render = function () {\r
4295                 if (angular.isDefined(ctrl.$modelValue)) {\r
4296                     scope.hourpickerValues = angular.copy(ctrl.$modelValue);\r
4297                     scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));\r
4298                 }\r
4299             };\r
4300             scope.editHourpickerValue = function (index) {\r
4301                 scope.hourpickerPanelValue = angular.copy(scope.hourpickerValues[index]);\r
4302                 scope.hourpicker.editMode = index;\r
4303             };\r
4304             scope.deleteHourpickerValue = function (index) {\r
4305                 scope.hourpickerValues.splice(index, 1);\r
4306                 scope.resetHourpickerPanelValue();\r
4307                 scope.addHourpickerValue();\r
4308             };\r
4309 \r
4310             scope.setValidity = function (errorType, errorValue) {\r
4311                 ctrl.$setValidity(errorType, errorValue);\r
4312             }\r
4313         }\r
4314     }\r
4315 }])\r
4316 \r
4317 .directive('b2bHourpickerPanel', [function () {\r
4318     return {\r
4319         restrict: 'EA',\r
4320         replace: false,\r
4321         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerPanel.html',\r
4322         controller: ['$scope', function (scope) {\r
4323 \r
4324         }],\r
4325         link: function (scope, elem, attr, ctrl) {\r
4326             var hourpickerPanelValueTemplate = {\r
4327                 days: {},\r
4328                 startTime: '',\r
4329                 startMeridiem: 'am',\r
4330                 endTime: '',\r
4331                 endMeridiem: 'pm'\r
4332             };\r
4333             for (var i = 0; i < scope.hourpicker.dayOptions.length; i++) {\r
4334                 hourpickerPanelValueTemplate.days[i] = {\r
4335                     value: false,\r
4336                     title: scope.hourpicker.dayOptions[i].title,\r
4337                     caption: scope.hourpicker.dayOptions[i].caption\r
4338                 };\r
4339             }\r
4340             scope.hourpickerPanelValue = {};\r
4341             scope.disableAddBtn = true;\r
4342 \r
4343             scope.$watch('hourpickerPanelValue.days', function(){\r
4344                 for(var i in scope.hourpickerPanelValue.days)\r
4345                 {\r
4346                     if(scope.hourpickerPanelValue.days[i].value)\r
4347                     {\r
4348                         scope.disableAddBtn = false;\r
4349                         break;\r
4350                     }\r
4351                     scope.disableAddBtn = true;\r
4352                 }\r
4353             }, true);\r
4354 \r
4355             scope.resetHourpickerPanelValue = function () {\r
4356                 scope.hourpickerPanelValue = angular.copy(hourpickerPanelValueTemplate);\r
4357                 if (scope.hourpicker.startTimeDefaultOptionIndex > -1) {\r
4358                     scope.hourpickerPanelValue.startTime = scope.hourpicker.startTimeOptions[scope.hourpicker.startTimeDefaultOptionIndex];\r
4359                 }\r
4360                 if (scope.hourpicker.endTimeDefaultOptionIndex > -1) {\r
4361                     scope.hourpickerPanelValue.endTime = scope.hourpicker.endTimeOptions[scope.hourpicker.endTimeDefaultOptionIndex];\r
4362                 }\r
4363                 scope.hourpickerPanelValue.startMeridiem = scope.hourpicker.startTimeDefaultMeridiem;\r
4364                 scope.hourpickerPanelValue.endMeridiem = scope.hourpicker.endTimeDefaultMeridiem;\r
4365                 scope.hourpicker.editMode = -1;\r
4366                 scope.setValidity('invalidHourpickerData', true);\r
4367                 scope.setValidity('invalidHourpickerTimeRange', true);\r
4368             };\r
4369             scope.resetHourpickerPanelValue();\r
4370             scope.updateHourpickerValue = function () {\r
4371                 if (scope.isFormValid() && !scope.isTimeOverlap()) {\r
4372                     scope.addHourpickerValue(angular.copy(scope.hourpickerPanelValue));\r
4373                     scope.resetHourpickerPanelValue();\r
4374                 }\r
4375             };\r
4376 \r
4377             scope.isFormValid = function () {\r
4378                 var isStartTimeAvailable = scope.hourpickerPanelValue.startTime ? true : false;\r
4379                 var isStartMeridiemAvailable = scope.hourpickerPanelValue.startMeridiem ? true : false;\r
4380                 var isEndTimeAvailable = scope.hourpickerPanelValue.endTime ? true : false;\r
4381                 var isEndMeridiemAvailable = scope.hourpickerPanelValue.endMeridiem ? true : false;\r
4382                 var currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);\r
4383                 var currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);\r
4384                 var isTimeInProperSequence = currentEndTime > currentStartTime;\r
4385                 var isDayChecked = false;\r
4386                 for (var i in scope.hourpickerPanelValue.days) {\r
4387                     if (scope.hourpickerPanelValue.days[i].value) {\r
4388                         isDayChecked = true;\r
4389                         break;\r
4390                     }\r
4391                 }\r
4392 \r
4393                 if (isStartTimeAvailable && isStartMeridiemAvailable && isEndTimeAvailable && isEndMeridiemAvailable && isTimeInProperSequence && isDayChecked) {\r
4394                     scope.setValidity('invalidHourpickerData', true);\r
4395                     return true;\r
4396                 } else {\r
4397                     scope.setValidity('invalidHourpickerData', false);\r
4398                     return false;\r
4399                 }\r
4400             };\r
4401             scope.isTimeOverlap = function () {\r
4402                 var selectedDays = [];\r
4403                 for (var i in scope.hourpickerPanelValue.days) {\r
4404                     if (scope.hourpickerPanelValue.days[i].value) {\r
4405                         selectedDays.push(i);\r
4406                     }\r
4407                 }\r
4408 \r
4409                 var currentStartTime, currentEndTime, existingStartTime, existingEndTime;\r
4410                 currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);\r
4411                 currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);\r
4412                 for (var i = 0; i < scope.hourpickerValues.length; i++) {\r
4413                     \r
4414                     if (i === scope.hourpicker.editMode) {\r
4415                         continue;\r
4416                     }\r
4417 \r
4418                     for (var j = 0; j < selectedDays.length; j++) {\r
4419                         existingStartTime = getTime(scope.hourpickerValues[i].startTime, scope.hourpickerValues[i].startMeridiem);\r
4420                         existingEndTime = getTime(scope.hourpickerValues[i].endTime, scope.hourpickerValues[i].endMeridiem);\r
4421                         if (scope.hourpickerValues[i].days[selectedDays[j]].value) {\r
4422                             if(!scope.hourpicker.sameDayOption){\r
4423                                 scope.setValidity('dayAlreadySelected', false);\r
4424                                 return true;\r
4425                             } else if ((currentStartTime > existingStartTime && currentStartTime < existingEndTime) || (currentEndTime > existingStartTime && currentEndTime < existingEndTime)) {\r
4426                                 scope.setValidity('invalidHourpickerTimeRange', false);\r
4427                                 return true;\r
4428                             } else if ((existingStartTime > currentStartTime && existingStartTime < currentEndTime) || (existingEndTime > currentStartTime && existingEndTime < currentEndTime)) {\r
4429                                 scope.setValidity('invalidHourpickerTimeRange', false);\r
4430                                 return true;\r
4431                             } else if ((currentStartTime === existingStartTime) && (currentEndTime === existingEndTime)) {\r
4432                                 scope.setValidity('invalidHourpickerTimeRange', false);\r
4433                                 return true;\r
4434                             }\r
4435                         }\r
4436                     }\r
4437                 }\r
4438 \r
4439                 scope.setValidity('dayAlreadySelected', true);\r
4440                 scope.setValidity('invalidHourpickerTimeRange', true);\r
4441                 return false;\r
4442             };\r
4443             var getTime = function (timeString, meridiem) {\r
4444                 var tempDate = new Date();\r
4445                 if (timeString && meridiem) {\r
4446                     var timeSplit = timeString.split(':');\r
4447                     var hour = ((meridiem === 'PM' || meridiem === 'pm') && timeSplit[0] !== '12') ? parseInt(timeSplit[0], 10) + 12 : parseInt(timeSplit[0], 10);\r
4448                     tempDate.setHours(hour, parseInt(timeSplit[1], 10), 0, 0);\r
4449                 }\r
4450 \r
4451                 return tempDate.getTime();\r
4452             };\r
4453         }\r
4454     }\r
4455 }])\r
4456 \r
4457 .directive('b2bHourpickerValue', [function () {\r
4458     return {\r
4459         restrict: 'EA',\r
4460         replace: false,\r
4461         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerValue.html',\r
4462         controller: ['$scope', function (scope) {\r
4463 \r
4464         }],\r
4465         link: function (scope, elem, attr, ctrl) {\r
4466             scope.hourpickerValue = {};\r
4467             scope.hourpickerValue.startTime = attr.startTime ? scope.$eval(attr.startTime) : '';\r
4468             scope.hourpickerValue.startMeridiem = attr.startMeridiem ? scope.$eval(attr.startMeridiem) : '';\r
4469             scope.hourpickerValue.endTime = attr.endTime ? scope.$eval(attr.endTime) : '';\r
4470             scope.hourpickerValue.endMeridiem = attr.endMeridiem ? scope.$eval(attr.endMeridiem) : '';\r
4471             scope.hourpickerValue.days = attr.days ? scope.$eval(attr.days).join(', ') : '';\r
4472             scope.hourpickerValue.index = attr.b2bHourpickerValue ? scope.$eval(attr.b2bHourpickerValue) : -1;\r
4473         }\r
4474     }\r
4475 }]);\r
4476 /**\r
4477  * @ngdoc directive\r
4478  * @name Template.att:inputTemplate\r
4479  *\r
4480  * @description\r
4481  *  <file src="src/inputTemplate/docs/readme.md" />\r
4482  *\r
4483  * @usage\r
4484  *  <input type="text" id="fieldId" placeholder="placholder text here" class="span12 input-enhanced" name="fieldName">\r
4485  *\r
4486  * @example\r
4487  <section id="code">\r
4488     <b>HTML + AngularJS</b>\r
4489     <example module="b2b.att">\r
4490         <file src="src/inputTemplate/docs/demo.html" />\r
4491         <file src="src/inputTemplate/docs/demo.js" />\r
4492     </example>\r
4493  </section>\r
4494  */\r
4495 angular.module('b2b.att.inputTemplate', []);\r
4496 \r
4497 /**\r
4498  * @ngdoc directive\r
4499  * @name Navigation.att:leftNavigation\r
4500  *\r
4501  * @description\r
4502  *  <file src="src/leftNavigation/docs/readme.md" />\r
4503  *\r
4504  * @usage\r
4505  *   <b2b-left-navigation data-menu="menuData"></b2b-left-navigation> \r
4506  *\r
4507  * @example\r
4508  *  <section id="code">\r
4509         <example module="b2b.att">\r
4510             <file src="src/leftNavigation/docs/demo.html" />\r
4511             <file src="src/leftNavigation/docs/demo.js" />\r
4512        </example>\r
4513     </section>\r
4514  *\r
4515  */\r
4516 angular.module('b2b.att.leftNavigation', [])\r
4517     .directive('b2bLeftNavigation', [function () {\r
4518         return {\r
4519             restrict: 'EA',\r
4520             templateUrl: 'b2bTemplate/leftNavigation/leftNavigation.html',\r
4521             scope: {\r
4522                 menuData: '='\r
4523             },\r
4524             link: function (scope, element, attrs, ctrl) {\r
4525                 scope.idx = -1;\r
4526                 scope.itemIdx = -1;\r
4527                 scope.navIdx = -1;\r
4528                 scope.toggleNav = function (val,link) {\r
4529                     if (val === scope.idx) {\r
4530                         scope.idx = -1;\r
4531                         return;\r
4532                     }\r
4533                     scope.idx = val;\r
4534                 };\r
4535                 /*New function for ECOMP sdk*/\r
4536                 scope.toggleDrawer = function(showmenu){\r
4537                         scope.idx=-1; /*hide the sunmenus*/\r
4538                         if(showmenu){\r
4539                                 document.getElementById('page-content').style.paddingLeft = "50px";\r
4540                         }\r
4541                         else\r
4542                                 document.getElementById('page-content').style.paddingLeft = "230px";            \r
4543                 };\r
4544                 scope.liveLink = function (evt, val1, val2) {\r
4545                     scope.itemIdx = val1;\r
4546                     scope.navIdx = val2;\r
4547                     evt.stopPropagation();\r
4548                 };\r
4549             }\r
4550         };\r
4551     }]);\r
4552 /**\r
4553  * @ngdoc directive\r
4554  * @name Buttons, links & UI controls.att:links\r
4555  *\r
4556  * @description\r
4557  *  <file src="src/links/docs/readme.md" />\r
4558  * @usage\r
4559  *      <!-- See below examples for link implementation -->\r
4560  *      \r
4561  * @example\r
4562        <section id="code">              \r
4563            <b>HTML + AngularJS</b>\r
4564            <example module="b2b.att">\r
4565            <file src="src/links/docs/demo.html" />\r
4566             <file src="src/links/docs/demo.js" />            \r
4567           </example>          \r
4568         </section>\r
4569  */\r
4570 angular.module('b2b.att.links', []);\r
4571 /**\r
4572  * @ngdoc directive\r
4573  * @name Misc.att:listbox\r
4574  *\r
4575  * @description\r
4576  *  <file src="src/listbox/docs/readme.md" />\r
4577  *\r
4578  * @param {int} currentIndex - Current index of selected listbox item. Is not supported on multiselect listbox\r
4579  * @param {Array} listboxData - Data of listbox items. Should include full data regardless if HTML will be filtered.\r
4580 \r
4581  * @example\r
4582  *  <section id="code">   \r
4583      <example module="b2b.att">\r
4584      <file src="src/listbox/docs/demo.html" />\r
4585      <file src="src/listbox/docs/demo.js" />\r
4586      </example>\r
4587     </section>\r
4588  *\r
4589  */\r
4590 angular.module('b2b.att.listbox', ['b2b.att.utilities'])\r
4591 .directive('b2bListBox', ['keymap', 'b2bDOMHelper', '$rootScope', function(keymap, b2bDOMHelper, $rootScope) {\r
4592                 return {\r
4593                     restrict: 'AE',\r
4594                     transclude: true,\r
4595                     replace: true,\r
4596                     scope: {\r
4597                         currentIndex: '=', \r
4598                         listboxData: '='\r
4599                     },\r
4600                     templateUrl: 'b2bTemplate/listbox/listbox.html',\r
4601                     link: function(scope, elem, attr) {\r
4602 \r
4603                         if (attr.ariaMultiselectable !== undefined || attr.ariaMultiselectable === 'true') {\r
4604                             scope.multiselectable = true;\r
4605                         } else {\r
4606                             scope.multiselectable = false;\r
4607                         }\r
4608 \r
4609                         var shiftKey = false;\r
4610                         var elements = [];\r
4611                         var prevDirection = undefined; // previous direction is used for an edge case when shifting\r
4612                         var shiftKeyPressed = false; // Used to handle shift clicking\r
4613                         var ctrlKeyPressed = false;\r
4614 \r
4615                         var currentIndexSet = {\r
4616                             'elementIndex': 0,\r
4617                             'listboxDataIndex': 0\r
4618                         };\r
4619 \r
4620                         /*scope.$watch('currentIndex', function(oldVal, newVal) {\r
4621                             if (angular.equals(oldVal, newVal)) return;\r
4622                             if (!scope.multiselectable) {\r
4623                                 // This doesn't garuntee anything. index will update on focus based on rules\r
4624                                 currentIndexSet.listboxDataIndex = scope.currentIndex;\r
4625                                 // Should this occur? \r
4626                                 //scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;\r
4627 \r
4628                                 // Update elementIndex\r
4629                                 elements = elem.children();\r
4630                                 var indecies = Array.prototype.map.call(elements, function(item) {\r
4631                                     return parseInt(angular.element(item).attr('data-index'), 10);\r
4632                                 }).filter(function(item) {\r
4633                                     return item === scope.currentIndex;\r
4634                                 });\r
4635                                 currentIndex.elementIndex = indecies[0];\r
4636                                 //focusOnElement(currentIndexSet.elementIndex); // This isn't shifting focus\r
4637                                 if (!scope.$$phase) {\r
4638                                     scope.$apply();\r
4639                                 }\r
4640                             }\r
4641                         });*/\r
4642 \r
4643                         function isTrue(item) {\r
4644                             if (item.selected === true) {\r
4645                                 return true;\r
4646                             }\r
4647                         }\r
4648 \r
4649                         function incrementIndex(elem) {\r
4650                             $rootScope.$apply();\r
4651 \r
4652                             var nextElem = elem.next();\r
4653                             if (!angular.isDefined(nextElem) || nextElem.length === 0) {\r
4654                                 return;\r
4655                             }\r
4656 \r
4657                             currentIndexSet.elementIndex += 1;\r
4658                             currentIndexSet.listboxDataIndex = parseInt(nextElem.attr('data-index'), 10);\r
4659                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4660 \r
4661                             if (currentIndexSet.elementIndex >= elements.length - 1) {\r
4662                                 currentIndexSet.elementIndex = elements.length-1;\r
4663                             }\r
4664                         }\r
4665 \r
4666                         function decrementIndex(elem) {\r
4667                             $rootScope.$apply();\r
4668                             var prevElem = angular.element(b2bDOMHelper.previousElement(elem));\r
4669                             if (!angular.isDefined(prevElem) || prevElem.length === 0) {\r
4670                                 return;\r
4671                             }\r
4672 \r
4673                             currentIndexSet.elementIndex -= 1;\r
4674                             currentIndexSet.listboxDataIndex = parseInt(prevElem.attr('data-index'), 10);\r
4675                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4676 \r
4677                             if (currentIndexSet.elementIndex <= 0) {\r
4678                                 currentIndexSet.elementIndex = 0;\r
4679                             }\r
4680                         }\r
4681 \r
4682                         var focusOnElement = function(index) {\r
4683                             try {\r
4684                                 elements[index].focus();\r
4685                             } catch (e) {};\r
4686                         }\r
4687 \r
4688                         function selectItems(startIndex, endIndex, forceValue) {\r
4689                             for (var i = startIndex; i < endIndex; i++) {\r
4690                                 if (forceValue === undefined) {\r
4691                                     // We will flip the value\r
4692                                     scope.listboxData[i].selected = !scope.listboxData[i].selected;\r
4693                                 } else {\r
4694                                     scope.listboxData[i].selected = forceValue;\r
4695                                 }\r
4696                             }\r
4697 \r
4698                             if (!scope.$$phase) {\r
4699                                 scope.$apply();\r
4700                             }\r
4701                         }\r
4702 \r
4703                         elem.bind('focus', function(evt) { \r
4704                             // If multiselectable or not and nothing is selected, put focus on first element \r
4705                             // If multiselectable and a range is set, put focus on first element of range \r
4706                             // If not multiselectable and something selected, put focus on element \r
4707                             elements = elem.children(); \r
4708                              var selectedItems = scope.listboxData.filter(isTrue); \r
4709                              var elementsIndies = Array.prototype.map.call(elements, function(item) {\r
4710                                 return parseInt(angular.element(item).attr('data-index'), 10);\r
4711                             });\r
4712  \r
4713                             if (selectedItems.length == 0) { \r
4714                                 focusOnElement(0); \r
4715                                 currentIndexSet.listboxDataIndex = 0;\r
4716                             } else if (attr.ariaMultiselectable) { \r
4717                                 var index = scope.listboxData.indexOf(selectedItems[0]); \r
4718                                 var indies = elementsIndies.filter(function(item) {\r
4719                                     return (item === index);\r
4720                                 });\r
4721 \r
4722                                 if (indies.length === 0 || indies[0] != index) {\r
4723                                     // Set focused on 0\r
4724                                     currentIndexSet.elementIndex = elementsIndies[0]; \r
4725                                     currentIndexSet.listboxDataIndex = 0;\r
4726                                     focusOnElement(currentIndexSet.elementIndex);\r
4727                                 } else {\r
4728                                     focusOnElement(indies[0]); \r
4729                                     currentIndexSet.elementIndex = indies[0];\r
4730                                     currentIndexSet.listboxDataIndex = index;\r
4731                                 }\r
4732                             } else { \r
4733                                 focusOnElement(currentIndexSet.elementIndex);  \r
4734                             }\r
4735                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4736 \r
4737                             if (!scope.$$phase) {\r
4738                                 scope.$apply();\r
4739                             }\r
4740                         });\r
4741                         elem.bind('keyup', function(evt) {\r
4742                             if (evt.keyCode === keymap.KEY.SHIFT) {\r
4743                                 shiftKeyPressed = false;\r
4744                             } else if (evt.keyCode === keymap.KEY.CTRL) {\r
4745                                 ctrlKeyPressed = false;\r
4746                             }\r
4747                         });\r
4748         \r
4749                         elem.bind('keydown', function(evt) {\r
4750                             var keyCode = evt.keyCode;\r
4751                             elements = elem.children();\r
4752                             if (keyCode === keymap.KEY.SHIFT) {\r
4753                                 shiftKeyPressed = true;\r
4754                             } else if (evt.keyCode === keymap.KEY.CTRL) {\r
4755                                 ctrlKeyPressed = true;\r
4756                             }\r
4757 \r
4758                             switch(keyCode) {\r
4759                                 case 65: // A key\r
4760                                 {\r
4761                                     if (scope.multiselectable && evt.ctrlKey) {\r
4762                                         var arr = scope.listboxData.filter(isTrue);\r
4763                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {\r
4764                                             return parseInt(angular.element(item).attr('data-index'), 10);\r
4765                                         });\r
4766                                         var val = !(arr.length === scope.listboxData.length);\r
4767                                         for (var i = 0; i < elementsIndies.length; i++) {\r
4768                                             scope.listboxData[elementsIndies[i]].selected = val;\r
4769                                         }\r
4770 \r
4771                                         if (!scope.$$phase) {\r
4772                                             scope.$apply();\r
4773                                         }\r
4774                                         \r
4775                                         evt.preventDefault();\r
4776                                         evt.stopPropagation();\r
4777                                     }\r
4778                                     break;\r
4779                                 }\r
4780                                 case keymap.KEY.END:\r
4781                                 {\r
4782                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {\r
4783                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {\r
4784                                             return parseInt(angular.element(item).attr('data-index'), 10);\r
4785                                         }).filter(function(item) {\r
4786                                             return (item >= currentIndexSet.listboxDataIndex);\r
4787                                         });\r
4788                                         for (var i = 0; i < elementsIndies.length; i++) {\r
4789                                             scope.listboxData[elementsIndies[i]].selected = true;\r
4790                                         }\r
4791                                         evt.preventDefault();\r
4792                                         evt.stopPropagation();\r
4793 \r
4794                                         if (!scope.$$phase) {\r
4795                                             scope.$apply();\r
4796                                         }\r
4797                                     }\r
4798                                     break;\r
4799                                 }\r
4800                                 case keymap.KEY.HOME: \r
4801                                 {\r
4802                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {\r
4803                                         selectItems(0, currentIndexSet.listboxDataIndex+1, true); // currentIndex+1 is what is being focused on\r
4804                                         evt.preventDefault();\r
4805                                         evt.stopPropagation();\r
4806                                     }\r
4807                                     break;\r
4808                                 }\r
4809                                 case keymap.KEY.LEFT:\r
4810                                 case keymap.KEY.UP:\r
4811                                 {\r
4812                                     if (currentIndexSet.listboxDataIndex === 0) {\r
4813                                         evt.preventDefault();\r
4814                                         evt.stopPropagation();\r
4815                                         return;\r
4816                                     }\r
4817 \r
4818                                     decrementIndex(elements.eq(currentIndexSet.elementIndex));\r
4819                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {\r
4820                                         if (evt.shiftKey) {\r
4821                                             if (prevDirection === 'DOWN') {\r
4822                                                 scope.listboxData[currentIndexSet.listboxDataIndex+1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex+1].selected;\r
4823                                             }\r
4824                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;\r
4825                                         }\r
4826                                         prevDirection = 'UP';\r
4827                                     } else {\r
4828                                         // If no modifier keys are selected, all other items need to be unselected.\r
4829                                         prevDirection = undefined;\r
4830                                         selectItems(0, scope.listboxData.length, false);\r
4831                                         scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;\r
4832                                     }\r
4833                                     focusOnElement(currentIndexSet.elementIndex);\r
4834                                     if(!scope.$$phase) {\r
4835                                         scope.$apply();\r
4836                                     }\r
4837                                     evt.preventDefault();\r
4838                                     evt.stopPropagation();\r
4839                                     break;\r
4840                                 }\r
4841                                 case keymap.KEY.RIGHT:\r
4842                                 case keymap.KEY.DOWN:\r
4843                                 {\r
4844                                     if (currentIndexSet.listboxDataIndex === scope.listboxData.length-1) {\r
4845                                         evt.preventDefault();\r
4846                                         evt.stopPropagation();\r
4847                                         return;\r
4848                                     }\r
4849 \r
4850                                     incrementIndex(elements.eq(currentIndexSet.elementIndex));\r
4851                                     \r
4852                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {\r
4853                                         if (evt.shiftKey) {\r
4854                                             if (prevDirection === 'UP') {\r
4855                                                 scope.listboxData[currentIndexSet.listboxDataIndex-1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex-1].selected;\r
4856                                             }\r
4857                                             \r
4858                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;    \r
4859                                         }\r
4860                                         prevDirection = 'DOWN';\r
4861                                     } else {\r
4862                                         // If no modifier keys are selected, all other items need to be unselected.\r
4863                                         prevDirection = undefined;\r
4864                                         selectItems(0, scope.listboxData.length, false);\r
4865                                         scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;\r
4866                                     }\r
4867 \r
4868                                     focusOnElement(currentIndexSet.elementIndex);\r
4869                                     if(!scope.$$phase) {\r
4870                                         scope.$apply();\r
4871                                     }\r
4872                                     evt.preventDefault();\r
4873                                     evt.stopPropagation();\r
4874                                     break;\r
4875                                 }\r
4876                                 case keymap.KEY.TAB:\r
4877                                     if(evt.shiftKey) {\r
4878                                         var previousElement = b2bDOMHelper.previousElement(elem.parent().parent(), true);\r
4879                                         evt.preventDefault();\r
4880                                         previousElement.focus();\r
4881                                     }\r
4882                                     break;\r
4883                                 default:\r
4884                                     break;\r
4885                             }\r
4886                         });\r
4887 \r
4888                         elem.bind('click', function(evt) {\r
4889                             var index = parseInt(evt.target.dataset.index, 10);\r
4890                             if (index === undefined || isNaN(index)) {\r
4891                                 return;\r
4892                             }\r
4893                             if (scope.multiselectable && currentIndexSet.listboxDataIndex !== undefined) {\r
4894                                 if (shiftKeyPressed) {\r
4895                                     var min = Math.min(index, currentIndexSet.listboxDataIndex);\r
4896                                     var max = Math.max(index, currentIndexSet.listboxDataIndex);\r
4897 \r
4898                                     if (index === min) { // clicking up\r
4899                                         var firstIndex = scope.listboxData.findIndex(function(item) { return item.selected === true;});\r
4900                                         // Given the firstIndex, let's find the matching element to get proper element match\r
4901                                         elements = elem.children();\r
4902                                         elements.eq(firstIndex)\r
4903                                         var elementsThatMatch = Array.prototype.filter.call(elements, function(item) {\r
4904                                             if (parseInt(angular.element(item).attr('data-index'), 10) === firstIndex) {\r
4905                                                 return true;\r
4906                                             }\r
4907                                         });\r
4908                                         firstIndex = parseInt(angular.element(elementsThatMatch).attr('data-index'), 10);\r
4909                                         \r
4910                                         if (index <= firstIndex && scope.listboxData.filter(isTrue).length > 1) {\r
4911                                             // Break the selection into 2\r
4912                                             selectItems(firstIndex + 1, max + 1, undefined); // + 1 needed because selectItems only selects up to MAX\r
4913                                             selectItems(min, firstIndex, undefined); \r
4914                                         } else if (scope.listboxData.filter(isTrue).length == 1){\r
4915                                             selectItems(min, max, undefined); \r
4916                                         } else {\r
4917                                             selectItems(min + 1, max + 1, undefined);\r
4918                                         }\r
4919                                     } else { // clicking down\r
4920                                         selectItems(min + 1, max + 1, scope.listboxData[min].selected);\r
4921                                     }\r
4922                                 } else if (ctrlKeyPressed) {\r
4923                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;\r
4924                                 } else {\r
4925                                     selectItems(0, scope.listboxData.length, false);\r
4926                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;\r
4927                                 }\r
4928                             } else {\r
4929                                 selectItems(0, scope.listboxData.length, false);\r
4930                                 scope.listboxData[index].selected = !scope.listboxData[index].selected;\r
4931                             }\r
4932                             currentIndexSet.elementIndex = index;\r
4933                             currentIndexSet.listboxDataIndex = index;\r
4934                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4935                             if (!scope.$$phase) {\r
4936                                 scope.$apply();\r
4937                             }\r
4938                             focusOnElement(index);\r
4939                         });\r
4940                     }\r
4941                 };\r
4942             }]);\r
4943 /**\r
4944  * @ngdoc directive\r
4945  * @name Videos, audio & animation.att:loaderAnimation\r
4946  *\r
4947  * @description\r
4948  *  <file src="src/loaderAnimation/docs/readme.md" />\r
4949  *\r
4950  * @usage\r
4951  *   <!-- Below demo js shows-->\r
4952  *   Angular library uses Global.css's icon-primary-spinner.\r
4953  *\r
4954  * @example\r
4955  *  <section id="code">\r
4956         <example module="b2b.att">\r
4957             <file src="src/loaderAnimation/docs/demo.html" />\r
4958             <file src="src/loaderAnimation/docs/demo.js" />\r
4959        </example>\r
4960     </section>\r
4961  *\r
4962  */\r
4963 angular.module('b2b.att.loaderAnimation', [])\r
4964     .constant('b2bSpinnerConfig', {\r
4965         loadingText: 'Loading...',\r
4966         startEvent: 'startButtonSpinner',\r
4967         stopEvent: 'stopButtonSpinner'\r
4968     })\r
4969     .constant("progressTrackerConfig", {\r
4970         loadingText: 'Loading...',\r
4971         minDuration: "",\r
4972         activationDelay: "",\r
4973         minDurationPromise: "",\r
4974         activationDelayPromise: ""\r
4975     })\r
4976 \r
4977 .provider('progressTracker', function () {\r
4978     this.$get = ['$q', '$timeout', function ($q, $timeout) {\r
4979         function cancelTimeout(promise) {\r
4980             if (promise) {\r
4981                 $timeout.cancel(promise);\r
4982             }\r
4983         }\r
4984         return function ProgressTracker(options) {\r
4985             //do new if user doesn't\r
4986             if (!(this instanceof ProgressTracker)) {\r
4987                 return new ProgressTracker(options);\r
4988             }\r
4989 \r
4990             options = options || {};\r
4991             //Array of promises being tracked\r
4992             var tracked = [];\r
4993             var self = this;\r
4994             //Allow an optional "minimum duration" that the tracker has to stay active for.\r
4995             var minDuration = options.minDuration;\r
4996             //Allow a delay that will stop the tracker from activating until that time is reached\r
4997             var activationDelay = options.activationDelay;\r
4998             var minDurationPromise;\r
4999             var activationDelayPromise;\r
5000             self.active = function () {\r
5001                 //Even if we have a promise in our tracker, we aren't active until delay is elapsed\r
5002                 if (activationDelayPromise) {\r
5003                     return false;\r
5004                 }\r
5005                 return tracked.length > 0;\r
5006             };\r
5007             self.tracking = function () {\r
5008                 //Even if we aren't active, we could still have a promise in our tracker\r
5009                 return tracked.length > 0;\r
5010             };\r
5011             self.destroy = self.cancel = function () {\r
5012                 minDurationPromise = cancelTimeout(minDurationPromise);\r
5013                 activationDelayPromise = cancelTimeout(activationDelayPromise);\r
5014                 for (var i = tracked.length - 1; i >= 0; i--) {\r
5015                     tracked[i].resolve();\r
5016                 }\r
5017                 tracked.length = 0;\r
5018             };\r
5019             //Create a promise that will make our tracker active until it is resolved.\r
5020             // @return deferred - our deferred object that is being tracked\r
5021             self.createPromise = function () {\r
5022                 var deferred = $q.defer();\r
5023                 tracked.push(deferred);\r
5024                 //If the tracker was just inactive and this the first in the list of promises, we reset our delay and minDuration again.\r
5025                 if (tracked.length === 1) {\r
5026                     if (activationDelay) {\r
5027                         activationDelayPromise = $timeout(function () {\r
5028                             activationDelayPromise = cancelTimeout(activationDelayPromise);\r
5029                             startMinDuration();\r
5030                         }, activationDelay);\r
5031                     } else {\r
5032                         startMinDuration();\r
5033                     }\r
5034                 }\r
5035                 deferred.promise.then(onDone(false), onDone(true));\r
5036                 return deferred;\r
5037 \r
5038                 function startMinDuration() {\r
5039                     if (minDuration) {\r
5040                         minDurationPromise = $timeout(angular.noop, minDuration);\r
5041                     }\r
5042                 }\r
5043                 //Create a callback for when this promise is done. It will remove our tracked promise from the array if once minDuration is complete\r
5044                 function onDone() {\r
5045                     return function () {\r
5046                         (minDurationPromise || $q.when()).then(function () {\r
5047                             var index = tracked.indexOf(deferred);\r
5048                             tracked.splice(index, 1);\r
5049                             //If this is the last promise, cleanup the timeouts for activationDelay\r
5050                             if (tracked.length === 0) {\r
5051                                 activationDelayPromise = cancelTimeout(activationDelayPromise);\r
5052                             }\r
5053                         });\r
5054                     };\r
5055                 }\r
5056             };\r
5057             self.addPromise = function (promise) {\r
5058                 \r
5059 //                we cannot assign then function in other var and then add the resolve and reject \r
5060                 var thenFxn = promise && (promise.then || promise.$then || (promise.$promise && promise.$promise.then));                \r
5061                 if (!thenFxn) {\r
5062                     throw new Error("progressTracker expects a promise object :: Not found");\r
5063                 }\r
5064                 var deferred = self.createPromise();\r
5065                 //When given promise is done, resolve our created promise\r
5066                 //Allow $then for angular-resource objects\r
5067 \r
5068                 promise.then(function (value) {\r
5069                         deferred.resolve(value);\r
5070                         return value;\r
5071                     }, function (value) {\r
5072                         deferred.reject(value);\r
5073                         return $q.reject(value);\r
5074                     }\r
5075                 );\r
5076                 return deferred;\r
5077             };\r
5078         };\r
5079     }];\r
5080 })\r
5081 \r
5082 .config(['$httpProvider', function ($httpProvider) {\r
5083     $httpProvider.interceptors.push(['$q', 'progressTracker', function ($q) {\r
5084         return {\r
5085             request: function (config) {\r
5086                 if (config.tracker) {\r
5087                     if (!angular.isArray(config.tracker)) {\r
5088                         config.tracker = [config.tracker];\r
5089                     }\r
5090                     config.$promiseTrackerDeferred = config.$promiseTrackerDeferred || [];\r
5091 \r
5092                     angular.forEach(config.tracker, function (tracker) {\r
5093                         var deferred = tracker.createPromise();\r
5094                         config.$promiseTrackerDeferred.push(deferred);\r
5095                     });\r
5096                 }\r
5097                 return $q.when(config);\r
5098             },\r
5099             response: function (response) {\r
5100                 if (response.config && response.config.$promiseTrackerDeferred) {\r
5101                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {\r
5102                         deferred.resolve(response);\r
5103                     });\r
5104                 }\r
5105                 return $q.when(response);\r
5106             },\r
5107             responseError: function (response) {\r
5108                 if (response.config && response.config.$promiseTrackerDeferred) {\r
5109                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {\r
5110                         deferred.reject(response);\r
5111                     });\r
5112                 }\r
5113                 return $q.reject(response);\r
5114             }\r
5115         };\r
5116     }]);\r
5117 }])\r
5118 \r
5119 .directive('b2bClickSpin', ['$timeout', '$parse', '$rootScope', 'progressTracker', function ($timeout, $parse, $rootScope, progressTracker) {\r
5120     return {\r
5121         restrict: 'A',\r
5122         link: function (scope, elm, attrs) {\r
5123             var fn = $parse(attrs.b2bClickSpin);\r
5124             elm.on('click', function (event) {\r
5125                 var promise = $timeout(function () {console.log("inside Promise")}, 5000);\r
5126                 scope.$apply(function () {\r
5127                     fn(scope, {\r
5128                         $event: event\r
5129                     });\r
5130                 });\r
5131                 //comment this line if not running unit test\r
5132                 $rootScope.loadingTracker = progressTracker({\r
5133                     minDuration: 750\r
5134                 });\r
5135                 $rootScope.loadingTracker.addPromise(promise);\r
5136                 angular.forEach("$routeChangeSuccess $viewContentLoaded $locationChangeSuccess".split(" "), function (event) {\r
5137                     $rootScope.$on(event, function () {\r
5138 \r
5139                         $timeout.cancel(promise);\r
5140                     });\r
5141                 });\r
5142             });\r
5143         }\r
5144     };\r
5145 }])\r
5146 \r
5147 .directive('b2bProgressTracker', ['progressTrackerConfig', function (ptc) {\r
5148     return {\r
5149         restrict: 'EA',\r
5150         replace: true,\r
5151         template: '<div><div ng-show="loadingTracker.active()" style="width:100%; text-align:center"><i class=\"icon-primary-spinner\"></i></div><div ng-show="loadingTracker.active()" style="width:100%;margin-top:10px; text-align:center">'+ ptc.loadingText+'</div></div>'\r
5152     };\r
5153 }])\r
5154 \r
5155 .directive('b2bLoadButton', ['b2bSpinnerConfig', '$timeout', function (spinnerConfig, $timeout) {\r
5156     var spinButton = function (state, element, data) {\r
5157         \r
5158         var attr = element.html() ? 'html' : 'val';\r
5159         state = state + 'Text';\r
5160         if (state === 'loadingText') {\r
5161             element[attr](data[state]);\r
5162             element.attr("disabled",'disabled');\r
5163             element.addClass('disabled');\r
5164         } else if (state === 'resetText') {\r
5165             element[attr](data[state]);\r
5166             element.removeAttr("disabled");\r
5167             element.removeClass('disabled');\r
5168         }\r
5169     };\r
5170 \r
5171     return {\r
5172         restrict: 'A',\r
5173         replace: false,\r
5174         scope: {\r
5175             promise: '=promise',\r
5176             startEvent: '@startEvent',\r
5177             stopEvent: '@stopEvent'\r
5178         },\r
5179         link: function (scope, element, attr) {\r
5180             var validAttr = element.html() ? 'html' : 'val';\r
5181             var data = {\r
5182                 loadingText: '',\r
5183                 resetText: ''\r
5184             };\r
5185 \r
5186             var updateLoadingText = function (val) {\r
5187                 var loadingText = val;\r
5188                 if (!angular.isDefined(loadingText) || loadingText === "") {\r
5189                     loadingText = spinnerConfig.loadingText;\r
5190                 }\r
5191                 data.loadingText = validAttr === 'html' ? "<i class=\"icon-primary-spinner small\"></i>" + loadingText : loadingText;\r
5192             };\r
5193             var updateResetText = function (val) {\r
5194                 data.resetText = val;\r
5195             };\r
5196 \r
5197             attr.$observe('b2bLoadButton', function (val) {\r
5198                 updateLoadingText(val);\r
5199             });\r
5200             $timeout(function () {\r
5201                 updateResetText(element[validAttr]());\r
5202             }, 500);\r
5203 \r
5204             if (!angular.isDefined(scope.startEvent) || scope.startEvent === "") {\r
5205                 scope.startEvent = spinnerConfig.startEvent;\r
5206             }\r
5207 \r
5208             if (!angular.isDefined(scope.stopEvent) || scope.stopEvent === "") {\r
5209                 scope.stopEvent = spinnerConfig.stopEvent;\r
5210             }\r
5211 \r
5212             scope.$watch('promise', function () {\r
5213                 if (angular.isDefined(scope.promise) && angular.isFunction(scope.promise.then)) {\r
5214                     spinButton('loading', element, data);\r
5215                     scope.promise.then(function () {\r
5216                         spinButton('reset', element, data);\r
5217                     }, function () {\r
5218                         spinButton('reset', element, data);\r
5219                     });\r
5220                 }\r
5221             });\r
5222 \r
5223             scope.$on(scope.startEvent, function () {\r
5224                 spinButton('loading', element, data);\r
5225                 scope.$on(scope.stopEvent, function () {\r
5226                     spinButton('reset', element, data);\r
5227                 });\r
5228             });\r
5229         }\r
5230     };\r
5231 }])\r
5232 \r
5233 \r
5234 ;\r
5235  /**\r
5236  * @ngdoc directive\r
5237  * @name Misc.att:messageWrapper\r
5238  * @scope\r
5239  * @param {boolean} trigger - A boolean that triggers directive to switch focus\r
5240  * @param {integer} delay  - Extra delay added to trigger code to allow for DOM to be ready. Default is 10ms.\r
5241  * @param {string} noFocus - Attribute-based API to trigger whether first focusable element receives focus on trigger or whole message (assumes tabindex="-1" set on first child)\r
5242  * @param {string} trapFocus - Attribute-based API to trap focus within the message. This should be enabled by default on all toast messages.\r
5243  * @description\r
5244  *  <file src="src/messageWrapper/docs/readme.md" />\r
5245  * @usage\r
5246  * <b2b-message-wrapper>Code that contains at least one focusable element and will be shown/hidden on some logic. This must have tabindex="-1".</b2b-message-wrapper>\r
5247  *\r
5248  * @example\r
5249  *  <section id="code">   \r
5250  <b>HTML + AngularJS</b>\r
5251  <example module="b2b.att">\r
5252  <file src="src/messageWrapper/docs/demo.html" />\r
5253  <file src="src/messageWrapper/docs/demo.js" />\r
5254  </example>\r
5255  </section>\r
5256  *\r
5257  */\r
5258 angular.module('b2b.att.messageWrapper', ['b2b.att.utilities'])\r
5259 .directive('b2bMessageWrapper', ['b2bDOMHelper', '$compile', '$timeout', '$log', function(b2bDOMHelper, $compile, $timeout, $log) {\r
5260   return {\r
5261     restrict: 'AE',\r
5262     scope: {\r
5263       trigger: '=',\r
5264       delay: '=?'\r
5265     },\r
5266     transclude: true,\r
5267     replace: true,\r
5268     template: '<div ng-transclude></div>',\r
5269     link: function(scope, elem, attrs) {\r
5270       scope.delay = scope.delay || 10;\r
5271 \r
5272       if (attrs.trapFocus != undefined && !elem.children().eq(0).attr('b2b-trap-focus-inside-element')) {\r
5273         // Append b2bTrapFocusInsideElement onto first child and recompile\r
5274         elem.children().eq(0).attr('b2b-trap-focus-inside-element', 'false');\r
5275         elem.children().eq(0).attr('trigger', scope.trigger);\r
5276         $compile(elem.contents())(scope);\r
5277       }\r
5278 \r
5279       var firstElement = undefined,\r
5280           launchingElement = undefined;\r
5281       \r
5282       scope.$watch('trigger', function(oldVal, newVal) {\r
5283         if (oldVal === newVal) return;\r
5284         if (!angular.isDefined(launchingElement)) {\r
5285           launchingElement = document.activeElement;\r
5286         }\r
5287         $timeout(function() {\r
5288           if (scope.trigger) {\r
5289 \r
5290             if (attrs.noFocus === true || attrs.noFocus === "") {\r
5291               elem.children()[0].focus();\r
5292             } else {\r
5293               firstElement = b2bDOMHelper.firstTabableElement(elem);\r
5294 \r
5295               if (angular.isDefined(firstElement)) {\r
5296                 firstElement.focus();\r
5297               }\r
5298             }\r
5299             \r
5300           } else {\r
5301             if (angular.isDefined(launchingElement) && launchingElement.nodeName !== 'BODY') {\r
5302               if (launchingElement === document.activeElement) {\r
5303                 return;\r
5304               }\r
5305 \r
5306               if (b2bDOMHelper.isInDOM(launchingElement) && b2bDOMHelper.isTabable(launchingElement)) {\r
5307                   // At this point, launchingElement is still a valid element, but focus will fail and \r
5308                   // activeElement will become body, hence we want to apply custom logic and find previousElement\r
5309                   var prevLaunchingElement = launchingElement;\r
5310                   launchingElement.focus();\r
5311 \r
5312                   if (document.activeElement !== launchingElement || document.activeElement.nodeName === 'BODY') {\r
5313                     launchingElement = b2bDOMHelper.previousElement(angular.element(prevLaunchingElement), true);\r
5314                     launchingElement.focus();\r
5315                   }\r
5316               } else {\r
5317                 launchingElement = b2bDOMHelper.previousElement(launchingElement, true);\r
5318                 launchingElement.focus();\r
5319               }\r
5320             }\r
5321           }\r
5322         }, scope.delay); \r
5323       });\r
5324     }\r
5325   };\r
5326 }]);\r
5327 /**\r
5328  * @ngdoc directive\r
5329  * @name Messages, modals & alerts.att:modalsAndAlerts\r
5330  *\r
5331  * @description\r
5332  *  <file src="src/modalsAndAlerts/docs/readme.md" />\r
5333  *\r
5334  * @usage\r
5335  *  <button class="btn" b2b-modal="b2bTemplate/modalsAndAlerts/demo_modal.html" modal-ok="ok()" modal-cancel="cancel()">Launch demo modal</button>\r
5336  *\r
5337  * @example\r
5338  *  <section id="code">\r
5339      <example module="b2b.att">\r
5340       <file src="src/modalsAndAlerts/docs/demo.html" />\r
5341       <file src="src/modalsAndAlerts/docs/demo.js" />\r
5342      </example>\r
5343     </section>\r
5344  *\r
5345  */\r
5346 angular.module('b2b.att.modalsAndAlerts', ['b2b.att.position', 'b2b.att.transition', 'b2b.att.utilities'])\r
5347 \r
5348 /**\r
5349  * A helper, internal data structure that acts as a map but also allows getting / removing\r
5350  * elements in the LIFO order\r
5351  */\r
5352 .factory('$$stackedMap', function () {\r
5353     return {\r
5354         createNew: function () {\r
5355             var stack = [];\r
5356 \r
5357             return {\r
5358                 add: function (key, value) {\r
5359                     stack.push({\r
5360                         key: key,\r
5361                         value: value\r
5362                     });\r
5363                 },\r
5364                 get: function (key) {\r
5365                     for (var i = 0; i < stack.length; i++) {\r
5366                         if (key === stack[i].key) {\r
5367                             return stack[i];\r
5368                         }\r
5369                     }\r
5370                 },\r
5371                 keys: function () {\r
5372                     var keys = [];\r
5373                     for (var i = 0; i < stack.length; i++) {\r
5374                         keys.push(stack[i].key);\r
5375                     }\r
5376                     return keys;\r
5377                 },\r
5378                 top: function () {\r
5379                     return stack[stack.length - 1];\r
5380                 },\r
5381                 remove: function (key) {\r
5382                     var idx = -1;\r
5383                     for (var i = 0; i < stack.length; i++) {\r
5384                         if (key === stack[i].key) {\r
5385                             idx = i;\r
5386                             break;\r
5387                         }\r
5388                     }\r
5389                     return stack.splice(idx, 1)[0];\r
5390                 },\r
5391                 removeTop: function () {\r
5392                     return stack.splice(stack.length - 1, 1)[0];\r
5393                 },\r
5394                 length: function () {\r
5395                     return stack.length;\r
5396                 }\r
5397             };\r
5398         }\r
5399     };\r
5400 }).factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', function ($document, $isElement, DOMHelper, keymap) {\r
5401     var elementStack = [];\r
5402     var stackHead = undefined;\r
5403     var firstTabableElement, lastTabableElement;\r
5404 \r
5405     var trapKeyboardFocusInFirstElement = function (e) {\r
5406         if (!e.keyCode) {\r
5407             e.keyCode = e.which;\r
5408         }\r
5409 \r
5410         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {\r
5411             lastTabableElement[0].focus();\r
5412             e.preventDefault(e);\r
5413             e.stopPropagation(e);\r
5414         }\r
5415 \r
5416     };\r
5417 \r
5418     var trapKeyboardFocusInLastElement = function (e) {\r
5419         if (!e.keyCode) {\r
5420             e.keyCode = e.which;\r
5421         }\r
5422 \r
5423         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {\r
5424             firstTabableElement[0].focus();\r
5425             e.preventDefault(e);\r
5426             e.stopPropagation(e);\r
5427         }\r
5428     };\r
5429     \r
5430     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {\r
5431         var bodyElements = $document.find('body').children();\r
5432 \r
5433         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(DOMHelper.firstTabableElement(stackHead));\r
5434         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(DOMHelper.lastTabableElement(stackHead));\r
5435 \r
5436         if (flag) {\r
5437             for (var i = 0; i < bodyElements.length; i++) {\r
5438                 if (bodyElements[i] !== stackHead[0]) {\r
5439                     bodyElements.eq(i).attr('aria-hidden', true);\r
5440                 }\r
5441             }\r
5442             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);\r
5443             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);\r
5444         } else {\r
5445             for (var j = 0; j < bodyElements.length; j++) {\r
5446                 if (bodyElements[j] !== stackHead[0]) {\r
5447                     bodyElements.eq(j).removeAttr('aria-hidden');\r
5448                 }\r
5449             }\r
5450             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);\r
5451             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);\r
5452         }\r
5453     };\r
5454     var toggleTrapFocusInElement = function (flag, element) {\r
5455         if (angular.isDefined(flag) && angular.isDefined(element)) {\r
5456             if (angular.isUndefined(stackHead)) {\r
5457                 stackHead = element;\r
5458                 trapFocusInElement(flag);\r
5459             } else {\r
5460                 if (flag) {\r
5461                     trapFocusInElement(false);\r
5462                     elementStack.push(stackHead);\r
5463                     stackHead = element;\r
5464                     trapFocusInElement(true);\r
5465                 } else {\r
5466                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {\r
5467                         trapFocusInElement(false);\r
5468                         stackHead = elementStack.pop();\r
5469                         if (angular.isDefined(stackHead)) {\r
5470                             trapFocusInElement(true);\r
5471                         }\r
5472                     }\r
5473                 }\r
5474             }\r
5475         }else {\r
5476             if (angular.isDefined(stackHead)) {\r
5477                 trapFocusInElement(false, firstTabableElement, lastTabableElement);\r
5478                 trapFocusInElement(true);\r
5479             }\r
5480         }\r
5481     };\r
5482 \r
5483     return toggleTrapFocusInElement;\r
5484 }])\r
5485 \r
5486 /**\r
5487  * A helper directive for the $modal service. It creates a backdrop element.\r
5488  */\r
5489 .directive('b2bModalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) {\r
5490     return {\r
5491         restrict: 'EA',\r
5492         replace: true,\r
5493         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-backdrop.html',\r
5494         link: function (scope, element, attrs) {\r
5495             scope.close = function (evt) {\r
5496                 var modal = $modalStack.getTop();\r
5497                 if (modal && modal.value.backdrop && modal.value.backdrop !== 'static') {\r
5498                     evt.preventDefault();\r
5499                     evt.stopPropagation();\r
5500                     $modalStack.dismiss(modal.key, 'backdrop click');\r
5501                 }\r
5502             };\r
5503         }\r
5504     };\r
5505 }])\r
5506 \r
5507 .directive('b2bModalWindow', ['$timeout', 'windowOrientation', '$window', function ($timeout, windowOrientation, $window) {\r
5508     return {\r
5509         restrict: 'EA',\r
5510         scope: {\r
5511             index: '@'\r
5512         },\r
5513         replace: true,\r
5514         transclude: true,\r
5515         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-window.html',\r
5516         controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {\r
5517             scope.windowClass = attrs.windowClass || '';\r
5518             scope.sizeClass = attrs.sizeClass || '';\r
5519             scope.isNotifDialog = false;\r
5520 \r
5521             this.setTitle = function (title) {\r
5522                 scope.title = title;\r
5523             };\r
5524             this.setContent = function (content) {\r
5525                 scope.content = content;\r
5526                 scope.isNotifDialog = true;\r
5527             };\r
5528             this.isDockedModal = scope.windowClass.indexOf('modal-docked') > -1;\r
5529         }],\r
5530         link: function (scope, element, attrs, ctrl) {\r
5531             if (ctrl.isDockedModal) {\r
5532                 scope.isModalLandscape = false;\r
5533 \r
5534                 var window = angular.element($window);\r
5535                 scope.updateCss = function () {\r
5536                     if (windowOrientation.isPotrait()) { // Potrait Mode\r
5537                         scope.isModalLandscape = false;\r
5538                     } else if (windowOrientation.isLandscape()) { // Landscape Mode\r
5539                         scope.isModalLandscape = true;\r
5540                     }\r
5541                 };\r
5542 \r
5543                 $timeout(function () {\r
5544                     scope.updateCss();\r
5545                     scope.$apply();\r
5546                 }, 100);\r
5547                 window.bind('orientationchange', function () {\r
5548                     scope.updateCss();\r
5549                     scope.$apply();\r
5550                 });\r
5551                 window.bind('resize', function () {\r
5552                     scope.updateCss();\r
5553                     scope.$apply();\r
5554                 });\r
5555             }else {\r
5556                 angular.element(element[0].querySelectorAll(".awd-select-list")).css({\r
5557                     "max-height": "200px"\r
5558                 });\r
5559             }\r
5560 \r
5561             var isIE = /msie|trident/i.test(navigator.userAgent);\r
5562             if (isIE) {\r
5563                 if(angular.element(element[0].querySelector('.corner-button button.close')).length > 0){\r
5564                     angular.element(element[0].querySelector('.corner-button button.close')).bind('focus', function () {\r
5565                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollLeft = 0;\r
5566                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollTop = 0;\r
5567                     });\r
5568                 }\r
5569             }\r
5570             \r
5571         }\r
5572     };\r
5573 }])\r
5574 \r
5575 .directive('b2bModalTitle', [function () {\r
5576     return {\r
5577         restrict: 'A',\r
5578         require: '^b2bModalWindow',\r
5579         link: function (scope, elem, attr, ctrl) {\r
5580             ctrl.setTitle(attr.id);\r
5581         }\r
5582     };\r
5583 }])\r
5584 \r
5585 .directive('b2bModalContent', [function () {\r
5586     return {\r
5587         restrict: 'A',\r
5588         require: '^b2bModalWindow',\r
5589         link: function (scope, elem, attr, ctrl) {\r
5590             ctrl.setContent(attr.id);\r
5591         }\r
5592     };\r
5593 }])\r
5594 \r
5595 \r
5596 .directive('b2bModalBody', ['$timeout', '$position', '$document', '$window', 'windowOrientation', 'b2bAwdBreakpoints', function ($timeout, $position, $document, $window, windowOrientation, b2bAwdBreakpoints) {\r
5597     return {\r
5598         restrict: 'AC',\r
5599         scope: {\r
5600             index: '@'\r
5601         },\r
5602         require: '^b2bModalWindow',\r
5603         link: function (scope, element, attrs, ctrl) {\r
5604             var window = angular.element($window);\r
5605             var body = $document.find('body').eq(0);\r
5606             scope.setModalHeight = function () {\r
5607                 var modalHeaderHeight, modalFooterHeight, modalBodyHeight, windowHeight, windowWidth, modalHeight;\r
5608                 modalHeaderHeight = 0;\r
5609                 modalFooterHeight = 0;\r
5610                 windowHeight = $window.innerHeight;\r
5611                 windowWidth = $window.innerWidth;\r
5612                 body.css({\r
5613                     'height': windowHeight + 'px'\r
5614                 });\r
5615 \r
5616                 if (ctrl.isDockedModal) {\r
5617                     var modalElements = element.parent().children();\r
5618                     for (var i = 0; i < modalElements.length; i++) {\r
5619                         if (modalElements.eq(i).hasClass('b2b-modal-header')) {\r
5620                             modalHeaderHeight = $position.position(modalElements.eq(i)).height;\r
5621                         } else if (modalElements.eq(i).hasClass('b2b-modal-footer')) {\r
5622                             modalFooterHeight = $position.position(modalElements.eq(i)).height;\r
5623                         }\r
5624                     }\r
5625 \r
5626                     modalHeight = $position.position(element.parent()).height;\r
5627 \r
5628                     modalBodyHeight = modalHeight - (modalHeaderHeight + modalFooterHeight) + 'px';\r
5629 \r
5630                     if (windowOrientation.isPotrait()) { // Potrait Mode\r
5631                         element.removeAttr('style').css({\r
5632                             height: modalBodyHeight\r
5633                         });\r
5634                     } else if (windowOrientation.isLandscape() && windowWidth < b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Mobile\r
5635                         element.removeAttr('style');\r
5636                     } else if (windowOrientation.isLandscape() && windowWidth >= b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Non-Mobile\r
5637                         element.removeAttr('style').css({\r
5638                             height: modalBodyHeight\r
5639                         });\r
5640                     }\r
5641                 }\r
5642             };\r
5643 \r
5644             $timeout(function () {\r
5645                 scope.setModalHeight();\r
5646                 scope.$apply();\r
5647             }, 100);\r
5648             window.bind('orientationchange', function () {\r
5649                 scope.setModalHeight();\r
5650                 scope.$apply();\r
5651             });\r
5652             window.bind('resize', function () {\r
5653                 scope.setModalHeight();\r
5654                 scope.$apply();\r
5655             });\r
5656         }\r
5657     };\r
5658 }])\r
5659 \r
5660 .directive('b2bModalFooter', ['windowOrientation', '$window', function (windowOrientation, $window) {\r
5661     return {\r
5662         restrict: 'AC',\r
5663         scope: {\r
5664             index: '@'\r
5665         },\r
5666         link: function (scope, element, attrs) {\r
5667 \r
5668         }\r
5669     };\r
5670 }])\r
5671 \r
5672 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', '$log', '$timeout', 'trapFocusInElement', function ($document, $compile, $rootScope, $$stackedMap, $log, $timeout, trapFocusInElement) {\r
5673     var backdropjqLiteEl, backdropDomEl;\r
5674     var backdropScope = $rootScope.$new(true);\r
5675     var body = $document.find('body').eq(0);\r
5676     var html = $document.find('html').eq(0);\r
5677     var openedWindows = $$stackedMap.createNew();\r
5678     var $modalStack = {};\r
5679 \r
5680     function backdropIndex() {\r
5681         var topBackdropIndex = -1;\r
5682         var opened = openedWindows.keys();\r
5683         for (var i = 0; i < opened.length; i++) {\r
5684             if (openedWindows.get(opened[i]).value.backdrop) {\r
5685                 topBackdropIndex = i;\r
5686             }\r
5687         }\r
5688         return topBackdropIndex;\r
5689     }\r
5690 \r
5691     $rootScope.$watch(backdropIndex, function (newBackdropIndex) {\r
5692         backdropScope.index = newBackdropIndex;\r
5693     });\r
5694 \r
5695     function removeModalWindow(modalInstance) {\r
5696         //background scroll fix\r
5697         html.removeAttr('style');\r
5698         body.removeAttr('style');\r
5699         body.removeClass('styled-by-modal');\r
5700 \r
5701         var modalWindow = openedWindows.get(modalInstance).value;\r
5702         trapFocusInElement(false, modalWindow.modalDomEl);\r
5703 \r
5704         //clean up the stack\r
5705         openedWindows.remove(modalInstance);\r
5706 \r
5707         //remove window DOM element\r
5708         modalWindow.modalDomEl.remove();\r
5709 \r
5710         //remove backdrop if no longer needed\r
5711         if (backdropDomEl && backdropIndex() === -1) {\r
5712             backdropDomEl.remove();\r
5713             backdropDomEl = undefined;\r
5714         }\r
5715 \r
5716         //destroy scope\r
5717         modalWindow.modalScope.$destroy();\r
5718     }\r
5719 \r
5720     $document.bind('keydown', function (evt) {\r
5721         var modal;\r
5722 \r
5723         if (evt.which === 27) {\r
5724             modal = openedWindows.top();\r
5725             if (modal && modal.value.keyboard) {\r
5726                 $rootScope.$apply(function () {\r
5727                     $modalStack.dismiss(modal.key);\r
5728                 });\r
5729             }\r
5730         }\r
5731     });\r
5732 \r
5733     $modalStack.open = function (modalInstance, modal) {\r
5734 \r
5735         openedWindows.add(modalInstance, {\r
5736             deferred: modal.deferred,\r
5737             modalScope: modal.scope,\r
5738             backdrop: modal.backdrop,\r
5739             keyboard: modal.keyboard\r
5740         });\r
5741 \r
5742         var angularDomEl = angular.element('<div b2b-modal-window></div>');\r
5743         angularDomEl.attr('window-class', modal.windowClass);\r
5744         angularDomEl.attr('size-class', modal.sizeClass);\r
5745         angularDomEl.attr('index', openedWindows.length() - 1);\r
5746         angularDomEl.html(modal.content);\r
5747 \r
5748         var modalDomEl = $compile(angularDomEl)(modal.scope);\r
5749         openedWindows.top().value.modalDomEl = modalDomEl;\r
5750         //background page scroll fix\r
5751         html.css({\r
5752             'overflow-y': 'hidden'\r
5753         });\r
5754         body.css({\r
5755             'overflow-y': 'hidden',\r
5756             'width': '100%',\r
5757             'height': window.innerHeight + 'px'\r
5758         });\r
5759         body.addClass('styled-by-modal');\r
5760         body.append(modalDomEl);\r
5761 \r
5762         if (backdropIndex() >= 0 && !backdropDomEl) {\r
5763             backdropjqLiteEl = angular.element('<div b2b-modal-backdrop></div>');\r
5764             backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);\r
5765             body.append(backdropDomEl);\r
5766         }\r
5767 \r
5768         $timeout(function () {\r
5769 \r
5770             if (modal.scope.$$childHead.isNotifDialog) {\r
5771                 angular.element(modalDomEl).find('button')[0].focus();\r
5772             } else {\r
5773                 angular.element(modalDomEl)[0].focus();\r
5774             }\r
5775             trapFocusInElement(true, angular.element(modalDomEl).eq(0));\r
5776         }, 200);\r
5777     };\r
5778 \r
5779     $modalStack.close = function (modalInstance, result) {\r
5780         var modal = openedWindows.get(modalInstance);\r
5781         if (modal) {\r
5782             modal.value.deferred.resolve(result);\r
5783             removeModalWindow(modalInstance);\r
5784         }\r
5785     };\r
5786 \r
5787     $modalStack.dismiss = function (modalInstance, reason) {\r
5788         var modalWindow = openedWindows.get(modalInstance).value;\r
5789         if (modalWindow) {\r
5790             modalWindow.deferred.reject(reason);\r
5791             removeModalWindow(modalInstance);\r
5792         }\r
5793     };\r
5794 \r
5795     $modalStack.getTop = function () {\r
5796         return openedWindows.top();\r
5797     };\r
5798 \r
5799     return $modalStack;\r
5800 }])\r
5801 \r
5802 .provider('$modal', function () {\r
5803     var $modalProvider = {\r
5804         options: {\r
5805             backdrop: true, //can be also false or 'static'\r
5806             keyboard: true\r
5807         },\r
5808         $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {\r
5809             var $modal = {};\r
5810 \r
5811             function getTemplatePromise(options) {\r
5812                 return options.template ? $q.when(options.template) :\r
5813                     $http.get(options.templateUrl, {\r
5814                         cache: $templateCache\r
5815                     }).then(function (result) {\r
5816                         return result.data;\r
5817                     });\r
5818             }\r
5819 \r
5820             function getResolvePromises(resolves) {\r
5821                 var promisesArr = [];\r
5822                 angular.forEach(resolves, function (value, key) {\r
5823                     if (angular.isFunction(value) || angular.isArray(value)) {\r
5824                         promisesArr.push($q.when($injector.invoke(value)));\r
5825                     }\r
5826                 });\r
5827                 return promisesArr;\r
5828             }\r
5829 \r
5830             $modal.open = function (modalOptions) {\r
5831 \r
5832                 var modalResultDeferred = $q.defer();\r
5833                 var modalOpenedDeferred = $q.defer();\r
5834                 //prepare an instance of a modal to be injected into controllers and returned to a caller\r
5835                 var modalInstance = {\r
5836                     result: modalResultDeferred.promise,\r
5837                     opened: modalOpenedDeferred.promise,\r
5838                     close: function (result) {\r
5839                         $modalStack.close(modalInstance, result);\r
5840                     },\r
5841                     dismiss: function (reason) {\r
5842                         $modalStack.dismiss(modalInstance, reason);\r
5843                     }\r
5844                 };\r
5845 \r
5846                 //merge and clean up options\r
5847                 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);\r
5848                 modalOptions.resolve = modalOptions.resolve || {};\r
5849 \r
5850                 //verify options\r
5851                 if (!modalOptions.template && !modalOptions.templateUrl) {\r
5852                     throw new Error('One of template or templateUrl options is required.');\r
5853                 }\r
5854 \r
5855                 var templateAndResolvePromise =\r
5856                     $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));\r
5857 \r
5858 \r
5859                 templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {\r
5860 \r
5861                     var modalScope = (modalOptions.scope || $rootScope).$new();\r
5862                     modalScope.$close = modalInstance.close;\r
5863                     modalScope.$dismiss = modalInstance.dismiss;\r
5864 \r
5865                     var ctrlInstance, ctrlLocals = {};\r
5866                     var resolveIter = 1;\r
5867 \r
5868                     //controllers\r
5869                     if (modalOptions.controller) {\r
5870                         ctrlLocals.$scope = modalScope;\r
5871                         ctrlLocals.$modalInstance = modalInstance;\r
5872                         angular.forEach(modalOptions.resolve, function (value, key) {\r
5873                             ctrlLocals[key] = tplAndVars[resolveIter++];\r
5874                         });\r
5875 \r
5876                         ctrlInstance = $controller(modalOptions.controller, ctrlLocals);\r
5877                     }\r
5878 \r
5879                     $modalStack.open(modalInstance, {\r
5880                         scope: modalScope,\r
5881                         deferred: modalResultDeferred,\r
5882                         content: tplAndVars[0],\r
5883                         backdrop: modalOptions.backdrop,\r
5884                         keyboard: modalOptions.keyboard,\r
5885                         windowClass: modalOptions.windowClass,\r
5886                         sizeClass: modalOptions.sizeClass\r
5887                     });\r
5888 \r
5889                 }, function resolveError(reason) {\r
5890                     modalResultDeferred.reject(reason);\r
5891                 });\r
5892 \r
5893                 templateAndResolvePromise.then(function () {\r
5894                     modalOpenedDeferred.resolve(true);\r
5895                 }, function () {\r
5896                     modalOpenedDeferred.reject(false);\r
5897                 });\r
5898 \r
5899                 return modalInstance;\r
5900             };\r
5901 \r
5902             return $modal;\r
5903         }]\r
5904     };\r
5905 \r
5906     return $modalProvider;\r
5907 })\r
5908 \r
5909 .directive("b2bModal", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {\r
5910     return {\r
5911         restrict: 'A',\r
5912         scope: {\r
5913             b2bModal: '@',\r
5914             modalController: '@',\r
5915             modalOk: '&',\r
5916             modalCancel: '&',\r
5917             windowClass: '@',\r
5918             sizeClass: '@'\r
5919         },\r
5920         link: function (scope, elm, attr) {\r
5921             elm.bind('click', function (ev) {\r
5922                 var currentPosition = ev.pageY - ev.clientY;\r
5923                 ev.preventDefault();\r
5924                 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {\r
5925                     scope.b2bModal = elm.attr("href");\r
5926                 }\r
5927                 $modal.open({\r
5928                     templateUrl: scope.b2bModal,\r
5929                     controller: scope.modalController,\r
5930                     windowClass: scope.windowClass,\r
5931                     sizeClass: scope.sizeClass\r
5932                 }).result.then(function (value) {\r
5933                     scope.modalOk({\r
5934                         value: value\r
5935                     });\r
5936                     elm[0].focus();\r
5937                 }, function (value) {\r
5938                     scope.modalCancel({\r
5939                         value: value\r
5940                     });\r
5941                     elm[0].focus();\r
5942                 });\r
5943             });\r
5944         }\r
5945     };\r
5946 }])\r
5947 \r
5948 .directive("utilityFilter", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {\r
5949     return {\r
5950         restrict: 'EA',\r
5951         scope: {\r
5952             utilityFilter: '@'\r
5953         },\r
5954         require: 'ngModel',\r
5955         templateUrl: 'b2bTemplate/modal/u-filter.html',\r
5956         link: function (scope, element, attribute, ctrl) {\r
5957             //controller to be passed to $modal service\r
5958             scope.options = angular.copy(scope.$parent.$eval(attribute.ngModel));\r
5959             scope.$parent.$watch(attribute.ngModel, function (newVal, oldVal) {\r
5960                 if (newVal !== oldVal) {\r
5961                     scope.options = newVal;\r
5962                 }\r
5963             });\r
5964             var modalCtrl = function ($scope, options) {\r
5965                 $scope.options = angular.copy(options);\r
5966             };\r
5967 \r
5968             if (angular.isDefined(scope.utilityFilter)) {\r
5969                 scope.templateUrl = scope.utilityFilter;\r
5970             } else {\r
5971                 scope.templateUrl = 'b2bTemplate/modal/u-filter-window.html';\r
5972             }\r
5973             element.bind('click', function (ev) {\r
5974                 var currentPosition = ev.pageY - ev.clientY;\r
5975                 $modal.open({\r
5976                     templateUrl: scope.templateUrl,\r
5977                     controller: modalCtrl,\r
5978                     resolve: {\r
5979                         options: function () {\r
5980                             return scope.options;\r
5981                         }\r
5982                     }\r
5983                 }).result.then(function (value) {\r
5984                     ctrl.$setViewValue(value);\r
5985                     element[0].focus();\r
5986                     $scrollTo(0, currentPosition, 0);\r
5987                 }, function () {\r
5988                     element[0].focus();\r
5989                     $scrollTo(0, currentPosition, 0);\r
5990                 });\r
5991             });\r
5992         }\r
5993     };\r
5994 }]);\r
5995 /**\r
5996  * @ngdoc directive\r
5997  * @name Forms.att:monthSelector\r
5998  *\r
5999  * @description\r
6000  *  <file src="src/monthSelector/docs/readme.md" />\r
6001  *\r
6002  * @usage\r
6003  * <div b2b-monthpicker ng-model="dt" min="minDate" max="maxDate" mode="monthpicker"></div>\r
6004     \r
6005  * @example\r
6006  *  <section id="code">\r
6007         <example module="b2b.att">\r
6008             <file src="src/monthSelector/docs/demo.html" />\r
6009             <file src="src/monthSelector/docs/demo.js" />\r
6010         </example>\r
6011     </section>\r
6012  *\r
6013  */\r
6014 angular.module('b2b.att.monthSelector', ['b2b.att.position', 'b2b.att.utilities'])\r
6015 \r
6016 .constant('b2bMonthpickerConfig', {\r
6017     dateFormat: 'MM/dd/yyyy',\r
6018     dayFormat: 'd',\r
6019     monthFormat: 'MMMM',\r
6020     yearFormat: 'yyyy',\r
6021     dayHeaderFormat: 'EEEE',\r
6022     dayTitleFormat: 'MMMM yyyy',\r
6023     disableWeekend: false,\r
6024     disableSunday: false,\r
6025     disableDates: null,\r
6026     onSelectClose: null,\r
6027     startingDay: 0,\r
6028     minDate: null,\r
6029     maxDate: null,\r
6030     dueDate: null,\r
6031     fromDate: null,\r
6032     legendIcon: null,\r
6033     legendMessage: null,\r
6034     calendarDisabled: false,\r
6035     collapseWait: 0,\r
6036     orientation: 'left',\r
6037     inline: false,\r
6038     mode:0,\r
6039     helperText: 'The date you selected is $date. Double tap to open calendar. Select a date to close the calendar.',\r
6040     descriptionText: 'Use tab to navigate between previous button, next button and month. Use arrow keys to navigate between months. Use space or enter to select a month.',\r
6041     MonthpickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation','mode','id'],\r
6042     MonthpickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],\r
6043     MonthpickerFunctionAttributes: ['disableDates', 'onSelectClose']\r
6044 })\r
6045 \r
6046 .factory('b2bMonthpickerService', ['b2bMonthpickerConfig', 'dateFilter', function (b2bMonthpickerConfig, dateFilter) {\r
6047     var setAttributes = function (attr, elem) {\r
6048         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {\r
6049             var attributes = b2bMonthpickerConfig.MonthpickerEvalAttributes.concat(b2bMonthpickerConfig.MonthpickerWatchAttributes, b2bMonthpickerConfig.MonthpickerFunctionAttributes);\r
6050             for (var key in attr) {\r
6051                 var val = attr[key];\r
6052                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
6053                     elem.attr(key.toSnakeCase(), key);\r
6054                 }\r
6055             }\r
6056         }\r
6057     };\r
6058 \r
6059     var bindScope = function (attr, scope) {\r
6060         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {\r
6061             var evalFunction = function (key, val) {\r
6062                 scope[key] = scope.$parent.$eval(val);\r
6063             };\r
6064 \r
6065             var watchFunction = function (key, val) {\r
6066                 scope.$parent.$watch(val, function (value) {\r
6067                     scope[key] = value;\r
6068                 });\r
6069                 scope.$watch(key, function (value) {\r
6070                     scope.$parent[val] = value;\r
6071                 });\r
6072             };\r
6073 \r
6074             var evalAttributes = b2bMonthpickerConfig.MonthpickerEvalAttributes;\r
6075             var watchAttributes = b2bMonthpickerConfig.MonthpickerWatchAttributes;\r
6076             for (var key in attr) {\r
6077                 var val = attr[key];\r
6078                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
6079                     evalFunction(key, val);\r
6080                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
6081                     watchFunction(key, val);\r
6082                 }\r
6083             }\r
6084         }\r
6085     };\r
6086 \r
6087     return {\r
6088         setAttributes: setAttributes,\r
6089         bindScope: bindScope\r
6090     };\r
6091 }])\r
6092 \r
6093 .controller('b2bMonthpickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bMonthpickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {\r
6094     var format = {\r
6095             date: getValue($attrs.dateFormat, dtConfig.dateFormat),\r
6096             day: getValue($attrs.dayFormat, dtConfig.dayFormat),\r
6097             month: getValue($attrs.monthFormat, dtConfig.monthFormat),\r
6098             year: getValue($attrs.yearFormat, dtConfig.yearFormat),\r
6099             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),\r
6100             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),\r
6101             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),\r
6102             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday),\r
6103             disableDates: getValue($attrs.disableDates, dtConfig.disableDates)\r
6104         },\r
6105         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);\r
6106 \r
6107     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;\r
6108     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;\r
6109     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;\r
6110     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;\r
6111     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;\r
6112     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;\r
6113     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;\r
6114     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);\r
6115     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);\r
6116     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);\r
6117     $scope.mode = getValue($attrs.mode, dtConfig.mode);\r
6118     \r
6119     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;\r
6120 \r
6121     function getValue(value, defaultValue) {\r
6122         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;\r
6123     }\r
6124 \r
6125     function getDaysInMonth(year, month) {\r
6126         return new Date(year, month, 0).getDate();\r
6127     }\r
6128 \r
6129     function getDates(startDate, n) {\r
6130         var dates = new Array(n);\r
6131         var current = startDate,\r
6132             i = 0;\r
6133         while (i < n) {\r
6134             dates[i++] = new Date(current);\r
6135             current.setDate(current.getDate() + 1);\r
6136         }\r
6137         return dates;\r
6138     }\r
6139 \r
6140     this.updatePosition = function (b2bMonthpickerPopupTemplate) {\r
6141         $scope.position = $position.offset($element);\r
6142         if($element.find('input').length > 0 ){\r
6143             $scope.position.top += $element.find('input').prop('offsetHeight');\r
6144         }else{\r
6145             $scope.position.top += $element.find('a').prop('offsetHeight');\r
6146         }\r
6147         \r
6148         if ($scope.orientation === 'right') {\r
6149             $scope.position.left -= (((b2bMonthpickerPopupTemplate && b2bMonthpickerPopupTemplate.prop('offsetWidth')) || 290) - $element.find('input').prop('offsetWidth'));\r
6150         }\r
6151     };\r
6152 \r
6153     function isSelected(dt) { \r
6154         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {\r
6155             return true;\r
6156         }\r
6157         return false;\r
6158     }\r
6159 \r
6160     function isFromDate(dt) {\r
6161         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {\r
6162             return true;\r
6163         }\r
6164         return false;\r
6165     }\r
6166 \r
6167     function isDateRange(dt) {\r
6168         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {\r
6169             return true;\r
6170         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {\r
6171             return true;\r
6172         }\r
6173         return false;\r
6174     }\r
6175 \r
6176     function isOld(date, currentMonthDate) {\r
6177         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() < new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {\r
6178             return true;\r
6179         } else {\r
6180             return false;\r
6181         }\r
6182     }\r
6183 \r
6184     function isNew(date, currentMonthDate) {\r
6185         if (date && currentMonthDate && (new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0).getTime() > new Date(currentMonthDate.getFullYear(), currentMonthDate.getMonth(), 1, 0, 0, 0).getTime())) {\r
6186             return true;\r
6187         } else {\r
6188             return false;\r
6189         }\r
6190     }\r
6191 \r
6192     function isPastDue(dt) {\r
6193         if ($scope.dueDate) {\r
6194             return (dt > $scope.dueDate);\r
6195         }\r
6196         return false;\r
6197     }\r
6198 \r
6199     function isDueDate(dt) {\r
6200         if ($scope.dueDate) {\r
6201             return (dt.getTime() === $scope.dueDate.getTime());\r
6202         }\r
6203         return false;\r
6204     }\r
6205 \r
6206     var isDisabled = function (date, currentMonthDate) {\r
6207         if ($attrs.from && !angular.isDate($scope.fromDate)) {\r
6208             return true;\r
6209         }\r
6210         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {\r
6211             return true;\r
6212         }\r
6213         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {\r
6214             return true;\r
6215         }\r
6216         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {\r
6217             return true;\r
6218         }\r
6219         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({\r
6220             date: date\r
6221         })));\r
6222     };\r
6223     \r
6224     var isDisabledMonth = function (date, currentMonthDate) {\r
6225         if ($attrs.from && !angular.isDate($scope.fromDate)) {\r
6226             return true;\r
6227         }\r
6228         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {\r
6229             return true;\r
6230         }\r
6231         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {\r
6232             return true;\r
6233         }\r
6234         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({\r
6235             date: date\r
6236         })));\r
6237     };    \r
6238          \r
6239     var compare = function (date1, date2) {\r
6240         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));\r
6241     };\r
6242 \r
6243     function isMinDateAvailable(startDate, endDate) {\r
6244         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {\r
6245             $scope.disablePrev = true;\r
6246             $scope.visibilityPrev = "hidden";\r
6247         } else {\r
6248             $scope.disablePrev = false;\r
6249             $scope.visibilityPrev = "visible";\r
6250         }\r
6251     }\r
6252     \r
6253     function isMaxDateAvailable(startDate, endDate) {\r
6254         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {\r
6255             $scope.disableNext = true;\r
6256             $scope.visibilityNext = "hidden";\r
6257         } else {\r
6258             $scope.disableNext = false;\r
6259             $scope.visibilityNext = "visible";\r
6260         }\r
6261     }    \r
6262     \r
6263     function isYearInRange(currentYear) {\r
6264             \r
6265         if ($scope.minDate && currentYear === $scope.minDate.getFullYear()) {\r
6266             $scope.disablePrev = true;\r
6267             $scope.visibilityPrev = "hidden";\r
6268         } else {\r
6269             $scope.disablePrev = false;\r
6270             $scope.visibilityPrev = "visible";\r
6271         }\r
6272         \r
6273         if ($scope.maxDate && currentYear === $scope.maxDate.getFullYear()) {\r
6274             $scope.disableNext = true;\r
6275             $scope.visibilityNext = "hidden";\r
6276         } else {\r
6277             $scope.disableNext = false;\r
6278             $scope.visibilityNext = "visible";\r
6279         }\r
6280         \r
6281     }    \r
6282 \r
6283     this.focusNextPrev = function(b2bMonthpickerPopupTemplate,init){\r
6284         if(init){\r
6285             if (!$scope.disablePrev){\r
6286                 b2bMonthpickerPopupTemplate[0].querySelector('th.prev').focus();\r
6287             }else if (!$scope.disableNext){\r
6288                 b2bMonthpickerPopupTemplate[0].querySelector('th.next').focus();\r
6289             }else{\r
6290                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();\r
6291             }\r
6292         }else{\r
6293             if ($scope.disableNext || $scope.disablePrev){\r
6294                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();\r
6295             }       \r
6296         }    \r
6297     };\r
6298 \r
6299     function getLabel(label) {\r
6300         if (label) {\r
6301             var labelObj = {\r
6302                 pre: label.substr(0, 1).toUpperCase(),\r
6303                 post: label\r
6304             };\r
6305             return labelObj;\r
6306         }\r
6307         return;\r
6308     }\r
6309 \r
6310     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {\r
6311         return {\r
6312             date: date,\r
6313             label: dateFilter(date, dayFormat),\r
6314             header: dateFilter(date, dayHeaderFormat),\r
6315             selected: !!isSelected,\r
6316             fromDate: !!isFromDate,\r
6317             dateRange: !!isDateRange,\r
6318             oldMonth: !!isOld,\r
6319             nextMonth: !!isNew,\r
6320             disabled: !!isDisabled,\r
6321             dueDate: !!dueDate,\r
6322             pastDue: !!pastDue,\r
6323             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))\r
6324         };\r
6325     }\r
6326     \r
6327     this.modes = [\r
6328         {\r
6329             name: 'day',\r
6330             getVisibleDates: function (date) {\r
6331                 var year = date.getFullYear(),\r
6332                     month = date.getMonth(),\r
6333                     firstDayOfMonth = new Date(year, month, 1),\r
6334                     lastDayOfMonth = new Date(year, month + 1, 0);\r
6335                 var difference = startingDay - firstDayOfMonth.getDay(),\r
6336                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,\r
6337                     firstDate = new Date(firstDayOfMonth),\r
6338                     numDates = 0;\r
6339 \r
6340                 if (numDisplayedFromPreviousMonth > 0) {\r
6341                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);\r
6342                     numDates += numDisplayedFromPreviousMonth; // Previous\r
6343                 }\r
6344                 numDates += getDaysInMonth(year, month + 1); // Current\r
6345                 numDates += (7 - numDates % 7) % 7; // Next\r
6346 \r
6347                 var days = getDates(firstDate, numDates),\r
6348                     labels = new Array(7);\r
6349                 for (var i = 0; i < numDates; i++) {\r
6350                     var dt = new Date(days[i]);\r
6351                     days[i] = makeDate(dt,\r
6352                         format.day,\r
6353                         format.dayHeader,\r
6354                         isSelected(dt),\r
6355                         isFromDate(dt),\r
6356                         isDateRange(dt),\r
6357                         isOld(dt, date),\r
6358                         isNew(dt, date),\r
6359                         isDisabled(dt, date),\r
6360                         isDueDate(dt),\r
6361                         isPastDue(dt));\r
6362                 }\r
6363                 for (var j = 0; j < 7; j++) {\r
6364                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));\r
6365                 }\r
6366                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);\r
6367                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);\r
6368                 return {\r
6369                     objects: days,\r
6370                     title: dateFilter(date, format.dayTitle),\r
6371                     labels: labels\r
6372                 };\r
6373             },\r
6374             split: 7,\r
6375             step: {\r
6376                 months: 1\r
6377             }\r
6378         },\r
6379         {\r
6380             name: 'month',\r
6381             getVisibleDates: function(date) {\r
6382                 var months = [], \r
6383                     labels = [], \r
6384                     year = date.getFullYear();\r
6385                     for (var i = 0; i < 12; i++) {\r
6386                         var dt = new Date(year,i,1);                \r
6387                         months[i] = makeDate(dt,\r
6388                                     format.month,\r
6389                                     format.dayHeader,\r
6390                                     isSelected(dt), \r
6391                                     isFromDate(dt),\r
6392                                     isDateRange(dt),\r
6393                                     false,\r
6394                                     false,\r
6395                                     isDisabledMonth(dt, date),\r
6396                                     isDueDate(dt),                                       \r
6397                                     isPastDue(dt));                                                                                                                                                         \r
6398                     }\r
6399                 isYearInRange(year);  \r
6400                 return {objects: months, title: dateFilter(date, format.year), labels: labels};\r
6401             },\r
6402             split:4,\r
6403             step: {years: 1}\r
6404         }\r
6405     ];\r
6406 }])\r
6407 \r
6408 .directive('b2bMonthpickerPopup', ['$parse', '$log', '$timeout', '$document', '$documentBind', '$isElement', '$templateCache', '$compile','$interval', 'trapFocusInElement', 'keymap', function ($parse, $log, $timeout, $document, $documentBind, $isElement, $templateCache, $compile, $interval,trapFocusInElement, keymap) {\r
6409     return {\r
6410         restrict: 'EA',\r
6411         scope: {\r
6412           trigger: '='\r
6413         },\r
6414         replace: true,\r
6415         transclude: true,\r
6416         templateUrl: function (elem, attr) {\r
6417             if (attr.inline === 'true') {\r
6418                 return 'b2bTemplate/monthSelector/monthSelector-popup.html';\r
6419             }else if (attr.link === 'true') {\r
6420                 return 'b2bTemplate/monthSelector/monthSelectorLink.html';\r
6421             }else {\r
6422                 return 'b2bTemplate/monthSelector/monthSelector.html';\r
6423             }\r
6424         },\r
6425         scope: {},\r
6426         require: ['b2bMonthpickerPopup', 'ngModel', '?^b2bMonthpickerGroup'],\r
6427         controller: 'b2bMonthpickerController',\r
6428         link: function (scope, element, attrs, ctrls) {\r
6429             var MonthpickerCtrl = ctrls[0],\r
6430                 ngModel = ctrls[1],\r
6431                 b2bMonthpickerGroupCtrl = ctrls[2];\r
6432             var b2bMonthpickerPopupTemplate;\r
6433 \r
6434             if (!ngModel) {\r
6435                 $log.error("ng-model is required.");\r
6436                 return; // do nothing if no ng-model\r
6437             }\r
6438 \r
6439             // Configuration parameters\r
6440             var mode = scope.mode,\r
6441                 selected;\r
6442             scope.isOpen = false;\r
6443 \r
6444             scope.headers = [];\r
6445             scope.footers = [];\r
6446             scope.triggerInterval=undefined;\r
6447 \r
6448 \r
6449             if (b2bMonthpickerGroupCtrl) {\r
6450                 b2bMonthpickerGroupCtrl.registerMonthpickerScope(scope);\r
6451             }\r
6452 \r
6453             element.bind('keydown', function (ev) {                   \r
6454                 if (!ev.keyCode) {\r
6455                     if (ev.which) {\r
6456                         ev.keyCode = ev.which;\r
6457                     } else if (ev.charCode) {\r
6458                         ev.keyCode = ev.charCode;\r
6459                     }\r
6460                 }                                \r
6461                 if(ev.keyCode === keymap.KEY.ESC)\r
6462                 {\r
6463                     scope.isOpen = false;\r
6464                     toggleCalendar(scope.isOpen);\r
6465                     scope.$apply();\r
6466                 }\r
6467             });\r
6468             \r
6469             element.find('button').bind('click', function () {\r
6470                 onClicked();                \r
6471             });\r
6472 \r
6473             element.find('a').bind('click', function () {\r
6474                 onClicked();                \r
6475             });\r
6476 \r
6477             \r
6478             element.find('input').bind('click', function () {\r
6479                 onClicked();\r
6480             });\r
6481 \r
6482             var onClicked = function() {        \r
6483                 if (!scope.ngDisabled) {\r
6484                     scope.isOpen = !scope.isOpen;\r
6485                     toggleCalendar(scope.isOpen);                    \r
6486                     MonthpickerCtrl.updatePosition(b2bMonthpickerPopupTemplate);\r
6487                     scope.$apply();\r
6488                 }\r
6489             };\r
6490         \r
6491             var toggleCalendar = function (flag) {\r
6492                 if (!scope.inline) {\r
6493                     if (flag) {\r
6494                         b2bMonthpickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/monthSelector/monthSelector-popup.html'));\r
6495                         b2bMonthpickerPopupTemplate.attr('b2b-trap-focus-inside-element', 'false');\r
6496                         b2bMonthpickerPopupTemplate.attr('trigger', 'true');\r
6497                         b2bMonthpickerPopupTemplate = $compile(b2bMonthpickerPopupTemplate)(scope);\r
6498                         $document.find('body').append(b2bMonthpickerPopupTemplate);\r
6499                         b2bMonthpickerPopupTemplate.bind('keydown', escPress);\r
6500                         $timeout(function () {\r
6501                             scope.getFocus = true;\r
6502                             scope.trigger=0;\r
6503                             scope.$apply();\r
6504                             $timeout(function () {\r
6505                                 scope.getFocus = false;\r
6506                                 scope.$apply();\r
6507                                 MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,true);\r
6508                             }, 100);\r
6509                         });\r
6510                         scope.triggerInterval = $interval(function () {\r
6511                             //This value is updated to trigger init() function of directive on year change.\r
6512                             scope.trigger=(scope.trigger === 0 ? 1 : 0);\r
6513                         }, 200);\r
6514 \r
6515                     } else {\r
6516                         b2bMonthpickerPopupTemplate.unbind('keydown', escPress);\r
6517                         if(scope.triggerInterval)\r
6518                         {\r
6519                             $interval.cancel(scope.triggerInterval);\r
6520                             scope.triggerInterval=undefined;\r
6521                         }\r
6522                         b2bMonthpickerPopupTemplate.remove();\r
6523                         if(element.find('button').length > 0){\r
6524                             element.find('button')[0].focus();\r
6525                         }else{\r
6526                             element.find('a')[0].focus();\r
6527                         }\r
6528                         \r
6529                         scope.getFocus = false;\r
6530                     }\r
6531                 }\r
6532             };\r
6533 \r
6534             var outsideClick = function (e) {\r
6535                 var isElement = $isElement(angular.element(e.target), element, $document);\r
6536                 var isb2bMonthpickerPopupTemplate = $isElement(angular.element(e.target), b2bMonthpickerPopupTemplate, $document);\r
6537                 if (!(isElement || isb2bMonthpickerPopupTemplate)) {\r
6538                     scope.isOpen = false;\r
6539                     toggleCalendar(scope.isOpen);\r
6540                     scope.$apply();\r
6541                 }\r
6542             };\r
6543 \r
6544             var escPress = function (ev) {\r
6545                 if (!ev.keyCode) {\r
6546                     if (ev.which) {\r
6547                         ev.keyCode = ev.which;\r
6548                     } else if (ev.charCode) {\r
6549                         ev.keyCode = ev.charCode;\r
6550                     }\r
6551                 }\r
6552                 if (ev.keyCode) {\r
6553                     if (ev.keyCode === keymap.KEY.ESC) {\r
6554                         scope.isOpen = false;\r
6555                         toggleCalendar(scope.isOpen);\r
6556                         ev.preventDefault();\r
6557                         ev.stopPropagation();\r
6558                     } else if (ev.keyCode === 33) {\r
6559                         !scope.disablePrev && scope.move(-1);\r
6560                         $timeout(function () {\r
6561                             scope.getFocus = true;\r
6562                             scope.$apply();\r
6563                             $timeout(function () {\r
6564                                 scope.getFocus = false;\r
6565                                 scope.$apply();\r
6566                             }, 100);\r
6567                         });\r
6568                         ev.preventDefault();\r
6569                         ev.stopPropagation();\r
6570                     } else if (ev.keyCode === 34) {\r
6571                         !scope.disableNext && scope.move(1);\r
6572                         $timeout(function () {\r
6573                             scope.getFocus = true;\r
6574                             scope.$apply();\r
6575                             $timeout(function () {\r
6576                                 scope.getFocus = false;\r
6577                                 scope.$apply();\r
6578                             }, 100);\r
6579                         });\r
6580                         ev.preventDefault();\r
6581                         ev.stopPropagation();\r
6582                     }\r
6583                     scope.$apply();\r
6584                 }\r
6585             };              \r
6586                     \r
6587             $documentBind.click('isOpen', outsideClick, scope);\r
6588 \r
6589             scope.$on('$destroy', function () {\r
6590                 if (scope.isOpen) {\r
6591                     scope.isOpen = false;\r
6592                     toggleCalendar(scope.isOpen);\r
6593                 }\r
6594             });\r
6595 \r
6596             scope.resetTime = function (date) {\r
6597                 if (typeof date === 'string') {\r
6598                     date = date + 'T12:00:00';\r
6599                 }\r
6600                 var dt;\r
6601                 if (!isNaN(new Date(date))) {\r
6602                     dt = new Date(date);\r
6603                     if(scope.mode === 1){\r
6604                         dt = new Date(dt.getFullYear(), dt.getMonth());\r
6605                     }else{\r
6606                         dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());\r
6607                     }                                                            \r
6608                 } else {\r
6609                     return null;\r
6610                 }\r
6611                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());\r
6612             };\r
6613             \r
6614             if (attrs.min) {\r
6615                 scope.$parent.$watch($parse(attrs.min), function (value) {\r
6616                     scope.minDate = value ? scope.resetTime(value) : null;\r
6617                     refill();\r
6618                 });\r
6619             }\r
6620             if (attrs.max) {\r
6621                 scope.$parent.$watch($parse(attrs.max), function (value) {\r
6622                     scope.maxDate = value ? scope.resetTime(value) : null;\r
6623                     refill();\r
6624                 });\r
6625             }\r
6626             if (attrs.due) {\r
6627                 scope.$parent.$watch($parse(attrs.due), function (value) {\r
6628                     scope.dueDate = value ? scope.resetTime(value) : null;\r
6629                     refill();\r
6630                 });\r
6631             }\r
6632             if (attrs.from) {\r
6633                 scope.$parent.$watch($parse(attrs.from), function (value) {\r
6634                     scope.fromDate = value ? scope.resetTime(value) : null;\r
6635                     refill();\r
6636                 });\r
6637             }\r
6638 \r
6639             if (attrs.legendIcon) {\r
6640                 scope.$parent.$watch(attrs.legendIcon, function (value) {\r
6641                     scope.legendIcon = value ? value : null;\r
6642                     refill();\r
6643                 });\r
6644             }\r
6645             if (attrs.legendMessage) {\r
6646                 scope.$parent.$watch(attrs.legendMessage, function (value) {\r
6647                     scope.legendMessage = value ? value : null;\r
6648                     refill();\r
6649                 });\r
6650             }\r
6651             if (attrs.ngDisabled) {\r
6652                 scope.$parent.$watch(attrs.ngDisabled, function (value) {\r
6653                     scope.ngDisabled = value ? value : null;\r
6654                 });\r
6655             }      \r
6656             \r
6657 \r
6658             // Split array into smaller arrays\r
6659             function split(arr, size) {\r
6660                 var arrays = [];\r
6661                 while (arr.length > 0) {\r
6662                     arrays.push(arr.splice(0, size));\r
6663                 }\r
6664                 return arrays;\r
6665             }\r
6666             \r
6667             var moveMonth = function(selectedDate, direction) {\r
6668                 var step = MonthpickerCtrl.modes[scope.mode].step;\r
6669                 selectedDate.setDate(1);\r
6670                 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));\r
6671                 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));\r
6672 \r
6673                 return selectedDate;\r
6674             };            \r
6675 \r
6676             function refill(date) {\r
6677                 if (angular.isDate(date) && !isNaN(date)) {\r
6678                     selected = new Date(date);\r
6679                 } else {\r
6680                     if (!selected) {\r
6681                         selected = new Date();\r
6682                     }\r
6683                 }\r
6684 \r
6685                 if (selected) {                    \r
6686                     var selectedCalendar;\r
6687                     if(scope.mode === 1){\r
6688                         if(!angular.isDate(selected))\r
6689                            {                           \r
6690                                 selected = new Date();\r
6691                            }\r
6692                         selectedCalendar = moveMonth(angular.copy(selected), -1);\r
6693                     } else {\r
6694                         selectedCalendar = angular.copy(selected);\r
6695                     }\r
6696                     \r
6697                     var currentMode = MonthpickerCtrl.modes[mode],\r
6698                         data = currentMode.getVisibleDates(selected);\r
6699 \r
6700                     scope.rows = split(data.objects, currentMode.split);\r
6701             \r
6702                     var flag=false;\r
6703                     var startFlag=false;\r
6704                     var firstSelected = false;\r
6705                     for(var i=0; i<scope.rows.length; i++)\r
6706                     {\r
6707                         for(var j=0; j<scope.rows[i].length; j++)\r
6708                         {\r
6709                             if(!scope.rows[i][j].disabled && !firstSelected)\r
6710                             {\r
6711                                 firstSelected=true;\r
6712                                 var firstDay = scope.rows[i][j];\r
6713                             }\r
6714 \r
6715                             if(scope.rows[i][j].selected)\r
6716                             {\r
6717                                 flag=true;\r
6718                                 break;\r
6719                             }                  \r
6720                         }\r
6721                         if(flag)\r
6722                         {\r
6723                             break;\r
6724                         }\r
6725                     }\r
6726                     if(!flag && firstSelected)\r
6727                     {\r
6728                        firstDay.firstFocus=true;\r
6729                     }\r
6730 \r
6731                     scope.labels = data.labels || [];\r
6732                     scope.title = data.title;                    \r
6733                 }\r
6734             }\r
6735 \r
6736             scope.select = function (date,$event) {\r
6737                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());\r
6738                 scope.currentDate = dt;\r
6739                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({\r
6740                         date: dt\r
6741                     }) !== false)) {\r
6742                     if (angular.isNumber(scope.collapseWait)) {\r
6743                         $timeout(function () {\r
6744                             scope.isOpen = false;\r
6745                             toggleCalendar(scope.isOpen);\r
6746                         }, scope.collapseWait);\r
6747                     } else {\r
6748                         scope.isOpen = false;\r
6749                         toggleCalendar(scope.isOpen);\r
6750                     }\r
6751                 }\r
6752             };\r
6753 \r
6754             scope.move = function (direction,$event) {\r
6755                 var step = MonthpickerCtrl.modes[mode].step;\r
6756                 selected.setDate(1);\r
6757                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));\r
6758                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));\r
6759                 refill();\r
6760                 scope.getFocus = true;\r
6761                 $timeout(function () {\r
6762                     if (attrs.inline === 'true') {\r
6763                         MonthpickerCtrl.focusNextPrev(element,false); \r
6764                     }else{\r
6765                         MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,false);\r
6766                     }\r
6767                 },100);\r
6768                 $event.preventDefault();\r
6769                 $event.stopPropagation();\r
6770             };\r
6771 \r
6772             scope.$watch('currentDate', function (value) {\r
6773                 if (angular.isDefined(value) && value !== null) {\r
6774                     refill(value);\r
6775                 } else {\r
6776                     refill();\r
6777                 }\r
6778                 ngModel.$setViewValue(value);\r
6779             });\r
6780 \r
6781             ngModel.$render = function () {\r
6782                 scope.currentDate = ngModel.$viewValue;\r
6783             };\r
6784 \r
6785             var stringToDate = function (value) {\r
6786                 if (!isNaN(new Date(value))) {\r
6787                     value = new Date(value);\r
6788                 }\r
6789                 return value;\r
6790             };\r
6791             ngModel.$formatters.unshift(stringToDate);\r
6792         }\r
6793     };\r
6794 }])\r
6795 \r
6796 .directive('b2bMonthpicker', ['$compile', '$log', 'b2bMonthpickerConfig', 'b2bMonthpickerService', function ($compile, $log, b2bMonthpickerConfig, b2bMonthpickerService) {\r
6797     return {\r
6798         restrict: 'A',\r
6799         scope: {\r
6800             disableDates: '&',\r
6801             onSelectClose: '&'\r
6802         },\r
6803         require: 'ngModel',\r
6804         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
6805             var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : b2bMonthpickerConfig.dateFormat;\r
6806             var helperText = angular.isDefined(attr.helperText) ? scope.$parent.$eval(attr.helperText) : b2bMonthpickerConfig.helperText; \r
6807             helperText = helperText.replace('$date', '{{dt | date : \'' + dateFormatString + '\'}}');\r
6808 \r
6809             var descriptionText = angular.isDefined(attr.descriptionText) ? scope.$parent.$eval(attr.descriptionText) : b2bMonthpickerConfig.descriptionText;  \r
6810 \r
6811 \r
6812             var inline = false;\r
6813             if (elem.prop('nodeName') !== 'INPUT' && elem.prop('nodeName') !== 'A') {\r
6814                 inline = true;\r
6815             }\r
6816 \r
6817             var selectedDateMessage = "";\r
6818             \r
6819             if (elem.prop('nodeName') !== 'A'){\r
6820                 selectedDateMessage = '<button type="button" class="span12 faux-input" ng-disabled="ngDisabled" aria-describedby="monthpicker-description'+scope.$id+'"><span class="hidden-spoken" aria-live="assertive" aria-atomic="false">' + helperText + '</span></button>';    \r
6821                 elem.attr('tabindex', '-1'); \r
6822                 elem.attr('aria-hidden', 'true');  \r
6823                 elem.attr('readonly', 'true'); \r
6824             }else{\r
6825                 selectedDateMessage = ''\r
6826                 elem.attr('aria-label', helperText);\r
6827             }\r
6828             \r
6829             var descriptionTextSpan = '<span class="offscreen-text" id="monthpicker-description'+scope.$id+'">'+descriptionText+'</span>';\r
6830             elem.removeAttr('b2b-Monthpicker');\r
6831             elem.removeAttr('ng-model');\r
6832             elem.removeAttr('ng-disabled');\r
6833             elem.addClass('Monthpicker-input');\r
6834             elem.attr('ng-model', 'dt');\r
6835             elem.attr('aria-describedby', 'monthpicker-description'+scope.$id);\r
6836             \r
6837             \r
6838             \r
6839             elem.attr('ng-disabled', 'ngDisabled');\r
6840             elem.attr('b2b-format-date', dateFormatString);\r
6841 \r
6842             var wrapperElement = angular.element('<div></div>');\r
6843             wrapperElement.attr('b2b-Monthpicker-popup', '');\r
6844             wrapperElement.attr('ng-model', 'dt');\r
6845             if (inline) {\r
6846                 wrapperElement.attr('inline', inline);\r
6847             }\r
6848             if (elem.prop('nodeName') === 'A'){\r
6849                 wrapperElement.attr('link', true);\r
6850             }\r
6851             b2bMonthpickerService.setAttributes(attr, wrapperElement);\r
6852             b2bMonthpickerService.bindScope(attr, scope);\r
6853 \r
6854             wrapperElement.html('');\r
6855             wrapperElement.append(selectedDateMessage);\r
6856             wrapperElement.append('');\r
6857             wrapperElement.append(descriptionTextSpan);\r
6858             wrapperElement.append('');\r
6859             wrapperElement.append(elem.prop('outerHTML'));\r
6860 \r
6861             var elm = wrapperElement.prop('outerHTML');\r
6862             elm = $compile(elm)(scope);\r
6863             elem.replaceWith(elm);\r
6864         }],\r
6865         link: function (scope, elem, attr, ctrl) {\r
6866             if (!ctrl) {\r
6867                 $log.error("ng-model is required.");\r
6868                 return; // do nothing if no ng-model\r
6869             }\r
6870             \r
6871             scope.$watch('dt', function (value) {\r
6872                 ctrl.$setViewValue(value);\r
6873             });\r
6874             ctrl.$render = function () {\r
6875                 scope.dt = ctrl.$viewValue;\r
6876             };\r
6877         }\r
6878     };\r
6879 }])\r
6880 \r
6881 .directive('b2bMonthpickerGroup', [function () {\r
6882     return {\r
6883         restrict: 'EA',\r
6884         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
6885             this.$$headers = [];\r
6886             this.$$footers = [];\r
6887             this.registerMonthpickerScope = function (MonthpickerScope) {\r
6888                 MonthpickerScope.headers = this.$$headers;\r
6889                 MonthpickerScope.footers = this.$$footers;\r
6890             };\r
6891         }],\r
6892         link: function (scope, elem, attr, ctrl) {}\r
6893     };\r
6894 }])\r
6895 \r
6896 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {\r
6897     return {\r
6898         restrict: 'A',\r
6899         require: 'ngModel',\r
6900         link: function (scope, elem, attr, ctrl) {\r
6901             var b2bFormatDate = "";\r
6902             attr.$observe('b2bFormatDate', function (value) {\r
6903                 b2bFormatDate = value;\r
6904             });\r
6905             var dateToString = function (value) {\r
6906                 if (!isNaN(new Date(value))) {\r
6907                     return dateFilter(new Date(value), b2bFormatDate);\r
6908                 }\r
6909                 return value;\r
6910             };\r
6911             ctrl.$formatters.unshift(dateToString);\r
6912         }\r
6913     };\r
6914 }])\r
6915 \r
6916 .directive('b2bMonthpickerHeader', [function () {\r
6917     return {\r
6918         restrict: 'EA',\r
6919         require: '^b2bMonthpickerGroup',\r
6920         transclude: true,\r
6921         replace: true,\r
6922         template: '',\r
6923         compile: function (elem, attr, transclude) {\r
6924             return function link(scope, elem, attr, ctrl) {\r
6925                 if (ctrl) {\r
6926                     ctrl.$$headers.push(transclude(scope, function () {}));\r
6927                 }\r
6928                 elem.remove();\r
6929             };\r
6930         }\r
6931     };\r
6932 }])\r
6933 \r
6934 .directive('b2bMonthpickerFooter', [function () {\r
6935     return {\r
6936         restrict: 'EA',\r
6937         require: '^b2bMonthpickerGroup',\r
6938         transclude: true,\r
6939         replace: true,\r
6940         template: '',\r
6941         compile: function (elem, attr, transclude) {\r
6942             return function link(scope, elem, attr, ctrl) {\r
6943                 if (ctrl) {\r
6944                     ctrl.$$footers.push(transclude(scope, function () {}));\r
6945                 }\r
6946                 elem.remove();\r
6947             };\r
6948         }\r
6949     };\r
6950 }]);\r
6951 /**\r
6952  * @ngdoc directive\r
6953  * @name Navigation.att:multiLevelNavigation\r
6954  *\r
6955  * @description\r
6956  *  <file src="src/multiLevelNavigation/docs/readme.md" />\r
6957  *\r
6958  * @usage\r
6959  *       <div class="b2b-ml-nav">\r
6960  *          <ul role="tree">\r
6961  *             <li aria-label="{{child.name}}" tabindex="-1" b2b-ml-nav="{{child.type}}" role="treeitem" ng-repeat="child in treeStructure">\r
6962  *                  <a tabindex="-1" href="javascript:void(0);" title="{{child.name}}">{{child.name}}<span><i class="{{child.type=='endNode'?'icon-primary-circle':'icon-primary-collapsed'}}"></i></span></a>\r
6963  *                      <!-- Below UL tag is RECURSIVE to generate n-childs -->\r
6964  *                      <ul role="group" ng-if="child.child">\r
6965  *                          <li aria-label="{{child.name}}" b2b-ml-nav="{{child.type}}" tabindex="-1" role="treeitem" ng-repeat="child in child.child">\r
6966  *                          <a tabindex="-1" href="javascript:void(0);" title="{{child.name}}">{{child.name}}<span><i class="{{child.type=='endNode'?'icon-primary-circle':'icon-primary-collapsed'}}"></i></span></a>\r
6967  *                               <!-- RECURSIVE UL tag goes here -->\r
6968  *                          </li>\r
6969  *                      </ul>\r
6970  *             </li>\r
6971  *           </ul>\r
6972  *        </div>\r
6973  *\r
6974  * @example\r
6975  *  <section id="code">\r
6976         <example module="b2b.att">\r
6977             <file src="src/multiLevelNavigation/docs/demo.html" />\r
6978             <file src="src/multiLevelNavigation/docs/demo.js" />\r
6979        </example>\r
6980     </section>\r
6981  *\r
6982  */\r
6983 angular.module('b2b.att.multiLevelNavigation', ['b2b.att.utilities'])\r
6984     //directive b2bMlNav Test coverage 100% on 5/13\r
6985     .directive('b2bMlNav', ['keymap', function (keymap) {\r
6986         return {\r
6987             restrict: 'EA',\r
6988             link: function (scope, element) {\r
6989                 var rootE, parentE, upE, downE, lastE, homeE, endE;\r
6990                 //default root tree element tabindex set zero\r
6991                 if (element.parent().parent().hasClass('b2b-ml-nav') && (element[0].previousElementSibling === null)) {\r
6992                     element.attr('tabindex', 0);\r
6993                 }\r
6994                 //check root via class\r
6995                 var isRoot = function (elem) {\r
6996                         if (elem.parent().parent().eq(0).hasClass('b2b-ml-nav')) {\r
6997                             return true;\r
6998                         } else {\r
6999                             return false;\r
7000                         }\r
7001 \r
7002                     }\r
7003                     //for any expandable tree item on click\r
7004                 var toggleState = function (e) {\r
7005                     if (angular.element(e.target).attr("b2b-ml-nav") !== "endNode") {\r
7006                         var eLink = element.find('a').eq(0);\r
7007                         if (eLink.hasClass('active')) {\r
7008                             eLink.removeClass('active');\r
7009                             eLink.parent().attr("aria-expanded", "false");\r
7010                             eLink.find('i').eq(0).removeClass('icon-primary-expanded');\r
7011                             eLink.find('i').eq(0).addClass('icon-primary-collapsed');\r
7012                         } else {\r
7013                             eLink.addClass('active');\r
7014                             eLink.parent().attr("aria-expanded", "true");\r
7015                             eLink.find('i').eq(0).removeClass('icon-primary-collapsed');\r
7016                             eLink.find('i').eq(0).addClass('icon-primary-expanded');\r
7017                         }\r
7018                     }\r
7019                 };\r
7020                 //function finds the main root-item from particular tree-group\r
7021                 var findRoot = function (elem) {\r
7022                     if (isRoot(elem)) {\r
7023                         rootE = elem;\r
7024                         return;\r
7025                     }\r
7026                     if (elem.attr("b2b-ml-nav") === "middleNode" || elem.attr("b2b-ml-nav") === "endNode") {\r
7027                         parentE = elem.parent().parent();\r
7028                     } else {\r
7029                         parentE = elem;\r
7030                     }\r
7031                     if (parentE.attr("b2b-ml-nav") === "rootNode") {\r
7032                         rootE = parentE;\r
7033                     } else {\r
7034                         findRoot(parentE);\r
7035                     }\r
7036                 };\r
7037                 //finds the last visible node of the previous tree-group\r
7038                 var findPreActive = function (elem) {\r
7039                     if (!(elem.hasClass("active"))) {\r
7040                         return;\r
7041                     } else {\r
7042                         var childElems = angular.element(elem[0].nextElementSibling.children);\r
7043                         lastE = angular.element(childElems[childElems.length - 1]);\r
7044                         if (lastE.attr("b2b-ml-nav") === "middleNode" && lastE.find('a').eq(0).hasClass('active')) {\r
7045                             findPreActive(lastE.find('a').eq(0));\r
7046                         }\r
7047                         upE = lastE;\r
7048                     }\r
7049                 };\r
7050                 //find above visible link\r
7051                 var findUp = function (elem) {\r
7052                     if (elem[0].previousElementSibling !== null) {\r
7053                         upE = angular.element(elem[0].previousElementSibling);\r
7054                     } else {\r
7055                         upE = elem.parent().parent();\r
7056                     }\r
7057                     if (isRoot(elem) || (upE.attr('b2b-ml-nav') === "middleNode" && upE[0] !== elem.parent().parent()[0])) {\r
7058                         findPreActive(upE.find('a').eq(0)); \r
7059                     }\r
7060                 };\r
7061                 //find below visible link\r
7062                 var findDown = function (elem) {\r
7063                     if (elem.hasClass('active')) {\r
7064                         downE = elem.next().find('li').eq(0);\r
7065                     } else {\r
7066                         if (elem.parent().next().length !== 0) {\r
7067                             downE = elem.parent().next().eq(0);\r
7068                         } else {\r
7069                             if (elem.parent().parent().parent().next().length !== 0) {\r
7070                                 downE = elem.parent().parent().parent().next().eq(0);\r
7071                                 return;\r
7072                             }\r
7073                             downE = elem.parent().eq(0);\r
7074                         }\r
7075                     }\r
7076                 };\r
7077                 //finds last root-group element of the tree\r
7078                 var findEnd = function (elem) {\r
7079                     findRoot(elem);\r
7080                     endE = angular.element(rootE.parent()[0].children[rootE.parent()[0].children.length - 1]);\r
7081                 };\r
7082                 //finds first root element of tree\r
7083                 var findHome = function (elem) {\r
7084                     findRoot(elem);\r
7085                     homeE = angular.element(rootE.parent()[0].children[0]);\r
7086                 };\r
7087                 element.bind('click', function (e) {\r
7088                     if(element.attr("b2b-ml-nav") !== "endNode") { \r
7089                         toggleState(e); \r
7090                     }\r
7091                     e.stopPropagation();\r
7092                 });\r
7093                 element.bind('focus', function (e) {\r
7094                     if(element.attr("b2b-ml-nav") !== "endNode") {\r
7095                         if(element.find('a').eq(0).hasClass('active')) {\r
7096                             element.attr("aria-expanded", true);\r
7097                         }\r
7098                         else {\r
7099                             element.attr("aria-expanded", false);\r
7100                         }\r
7101                         \r
7102                     }\r
7103                 })\r
7104                 //Keyboard functionality approach:\r
7105                 //find keycode\r
7106                 //set set tabindex -1 on the current focus element\r
7107                 //find the next element to be focussed, set tabindex 0 and throw focus\r
7108                 element.bind('keydown', function (evt) {\r
7109                     switch (evt.keyCode) {\r
7110                     case keymap.KEY.ENTER:\r
7111                     case keymap.KEY.SPACE:\r
7112                         element.triggerHandler('click');\r
7113                         evt.stopPropagation();\r
7114                         evt.preventDefault();\r
7115                         break;\r
7116                     case keymap.KEY.END:\r
7117                         evt.preventDefault();\r
7118                         element.attr('tabindex', -1);\r
7119                         findEnd(element);\r
7120                         endE.eq(0).attr('tabindex', 0);\r
7121                         endE[0].focus();\r
7122                         evt.stopPropagation();\r
7123                         break;\r
7124                     case keymap.KEY.HOME:\r
7125                         evt.preventDefault();\r
7126                         element.attr('tabindex', -1);\r
7127                         findHome(element);\r
7128                         homeE.eq(0).attr('tabindex', 0);\r
7129                         homeE[0].focus();\r
7130                         evt.stopPropagation();\r
7131                         break;\r
7132                     case keymap.KEY.LEFT:\r
7133                         evt.preventDefault();\r
7134                         if (!isRoot(element)) {\r
7135                             element.attr('tabindex', -1);\r
7136                             parentE = element.parent().parent();\r
7137                             parentE.eq(0).attr('tabindex', 0);\r
7138                             parentE[0].focus();\r
7139                             parentE.eq(0).triggerHandler('click');\r
7140                         } else {\r
7141                             if (element.find('a').eq(0).hasClass('active')) {\r
7142                                 element.triggerHandler('click');\r
7143                             }\r
7144                         }\r
7145                         evt.stopPropagation();\r
7146                         break;\r
7147                     case keymap.KEY.UP:\r
7148                         evt.preventDefault();\r
7149                         if (!(isRoot(element) && element[0].previousElementSibling === null)) {\r
7150                             element.attr('tabindex', -1);\r
7151                             findUp(element);\r
7152                             upE.eq(0).attr('tabindex', 0);\r
7153                             upE[0].focus();\r
7154                         }\r
7155                         evt.stopPropagation();\r
7156                         break;\r
7157                     case keymap.KEY.RIGHT:\r
7158                         evt.preventDefault();\r
7159                         if (element.attr("b2b-ml-nav") !== "endNode") {\r
7160                             if (!element.find('a').eq(0).hasClass('active')) {\r
7161                                 element.triggerHandler('click');\r
7162                             }\r
7163                             element.attr('tabindex', -1);\r
7164                             findDown(element.find('a').eq(0));\r
7165                             downE.eq(0).attr('tabindex', 0);\r
7166                             downE[0].focus();\r
7167                         }\r
7168                         evt.stopPropagation();\r
7169                         break;\r
7170                     case keymap.KEY.DOWN:\r
7171                         evt.preventDefault();\r
7172                         element.attr('tabindex', -1);\r
7173                         if (!(element.attr("b2b-ml-nav") === "middleNode" && element.find('a').eq(0).hasClass('active')) && (element.next().length === 0)) {\r
7174                             if(element.parent().parent().attr("b2b-ml-nav") !== "rootNode" && element.parent().parent()[0].nextElementSibling !== null)\r
7175                             {\r
7176                                 findDown(element.find('a').eq(0));\r
7177                                 downE.eq(0).attr('tabindex', 0);\r
7178                                 downE[0].focus();\r
7179                                 evt.stopPropagation();\r
7180                                 break;\r
7181                             }\r
7182                             findRoot(element);\r
7183                             if (!(rootE.next().length === 0)) {\r
7184                                 rootE.next().eq(0).attr('tabindex', 0);\r
7185                                 rootE.next()[0].focus();\r
7186                             } else {\r
7187                                 rootE.eq(0).attr('tabindex', 0);\r
7188                                 rootE[0].focus();\r
7189                             }\r
7190                             evt.stopPropagation();\r
7191                             break;\r
7192                         }\r
7193                         findDown(element.find('a').eq(0));\r
7194                         downE.eq(0).attr('tabindex', 0);\r
7195                         downE[0].focus();\r
7196                         evt.stopPropagation();\r
7197                         break;\r
7198                     default:\r
7199                         break;\r
7200                     }\r
7201                 });\r
7202             }\r
7203         };\r
7204     }]);\r
7205 /**\r
7206  * @ngdoc directive\r
7207  * @name Tabs, tables & accordions.att:multipurposeExpander\r
7208  *\r
7209  * @description\r
7210  *  <file src="src/multipurposeExpander/docs/readme.md" />\r
7211  *\r
7212  * @usage\r
7213  * <!--With Close Other -->\r
7214  * <b2b-expander-group close-others="true">\r
7215  *  <b2b-expanders class="mpc-expanders" is-open="testmpc">            \r
7216  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc, 'b2b-toggle-header-inactive': testmpc } ">Heading content goes here</b2b-expander-heading>               \r
7217  *      <b2b-expander-body>\r
7218             <p>body content goes here</p>\r
7219         </b2b-expander-body>\r
7220  *  </b2b-expanders>\r
7221  *  </b2b-expander-group>\r
7222  *  \r
7223  * <!-- Without Close Other -->\r
7224  *  <b2b-expanders class="mpc-expanders" is-open="testmpc2">            \r
7225  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc2, 'b2b-toggle-header-inactive': testmpc2 } ">Heading content goes here</b2b-expander-heading>               \r
7226  *      <b2b-expander-body>\r
7227             <p>body content goes here</p>\r
7228         </b2b-expander-body>\r
7229  *  </b2b-expanders>\r
7230  *  \r
7231  * @example\r
7232  *  <section id="code">\r
7233         <example module="b2b.att.multipurposeExpander">\r
7234             <file src="src/multipurposeExpander/docs/demo.html" />\r
7235             <file src="src/multipurposeExpander/docs/demo.js" />\r
7236         </example>\r
7237     </section>\r
7238  *\r
7239  */\r
7240 \r
7241 angular.module('b2b.att.multipurposeExpander', ['b2b.att', 'b2b.att.collapse'])\r
7242 .directive('b2bExpanderGroup', function () {\r
7243     return {\r
7244         restrict: 'EA',\r
7245         transclude: true,\r
7246         template: "<ng-transclude></ng-transclude>",\r
7247         controller:['$scope','$attrs', function($scope,$attrs){\r
7248             this.groups = [];\r
7249             this.index = -1;            \r
7250             this.scope = $scope;\r
7251             \r
7252             this.addGroup = function (groupScope) {\r
7253                 var that = this;\r
7254                 groupScope.index = this.groups.length;\r
7255                 this.groups.push(groupScope);\r
7256                 if(this.groups.length > 0){\r
7257                     this.index = 0;\r
7258                 }\r
7259                 groupScope.$on('$destroy', function () {\r
7260                 that.removeGroup(groupScope);\r
7261             });\r
7262             };\r
7263 \r
7264             this.closeOthers = function (openGroup) {\r
7265                 var closeOthers = angular.isDefined($attrs.closeOthers);\r
7266                 if (closeOthers && !$scope.forceExpand) {\r
7267                     angular.forEach(this.groups, function (group) {\r
7268                         if (group !== openGroup) {\r
7269                             group.isOpen = false;\r
7270                         }\r
7271                     });\r
7272                 }\r
7273                 if (this.groups.indexOf(openGroup) === (this.groups.length - 1) && $scope.forceExpand) {\r
7274                     $scope.forceExpand = false;\r
7275                 }\r
7276             };\r
7277             this.removeGroup = function (group) {\r
7278             var index = this.groups.indexOf(group);\r
7279             if (index !== -1) {\r
7280                 this.groups.splice(this.groups.indexOf(group), 1);\r
7281             }\r
7282         };\r
7283         }]\r
7284        \r
7285     };\r
7286     \r
7287 })\r
7288 .directive('b2bExpanders', function () {\r
7289     return{\r
7290         restrict: 'EA',\r
7291         replace: true,\r
7292         require:['b2bExpanders','?^b2bExpanderGroup'],\r
7293         transclude: true,\r
7294         scope:{isOpen:'=?'},\r
7295         template: "<div ng-transclude></div>",\r
7296         controller: ['$scope', function ($scope){\r
7297                 var bodyScope = null;\r
7298                 var expanderScope = null;\r
7299                 this.isOpened = function(){                \r
7300                     if($scope.isOpen)\r
7301                     {\r
7302                         return  true;\r
7303                     }else\r
7304                     {\r
7305                         return false;\r
7306                     }\r
7307                 };                \r
7308                 this.setScope = function (scope) {\r
7309                     bodyScope = scope; \r
7310                     bodyScope.isOpen = $scope.isOpen;                   \r
7311                 };                \r
7312                 this.setExpanderScope = function (scope) {\r
7313                     expanderScope = scope;                                   \r
7314                 };\r
7315                 this.toggle = function () {\r
7316                     $scope.isOpen = bodyScope.isOpen = !bodyScope.isOpen;                    \r
7317                     return bodyScope.isOpen;\r
7318                     \r
7319                 };\r
7320                 this.watchToggle = function(io){ \r
7321                     bodyScope.isOpen = io;\r
7322                     expanderScope.updateIcons(io);\r
7323                 };  \r
7324             }],\r
7325         link: function (scope, elem, attr, myCtrl)\r
7326         {\r
7327             //scope.isOpen = false; \r
7328             if(myCtrl[1]){\r
7329                 myCtrl[1].addGroup(scope);\r
7330             }\r
7331             scope.$watch('isOpen', function(val){                               \r
7332                 myCtrl[0].watchToggle(scope.isOpen);\r
7333                 if(val && myCtrl[1]){\r
7334                     myCtrl[1].closeOthers(scope);\r
7335                 }\r
7336             });            \r
7337         }\r
7338     };\r
7339 })\r
7340 \r
7341 .directive('b2bExpanderHeading', function () {\r
7342     return{\r
7343         require: "^b2bExpanders",\r
7344         restrict: 'EA',\r
7345         replace: true,\r
7346         transclude: true,\r
7347         scope: true,\r
7348         template: "<div style='padding:10px 10px 10px 0 !important' ng-transclude></div>"\r
7349     };\r
7350 })\r
7351 \r
7352 .directive('b2bExpanderBody', function () {\r
7353     return{\r
7354         restrict: 'EA',\r
7355         require: "^b2bExpanders",\r
7356         replace: true,\r
7357         transclude: true,\r
7358         scope: {},\r
7359         template: "<div b2b-collapse='!isOpen' ><div ng-transclude></div></div>",\r
7360         link: function (scope, elem, attr, myCtrl) {\r
7361             scope.isOpen = false;\r
7362             myCtrl.setScope(scope);\r
7363         }\r
7364     };\r
7365 })\r
7366 \r
7367 .directive('b2bExpanderToggle', function () {\r
7368     return{\r
7369         restrict: 'EA',\r
7370         require: "^b2bExpanders",\r
7371         scope: {\r
7372             expandIcon: '@',\r
7373             collapseIcon: '@'\r
7374         },\r
7375         \r
7376         link: function (scope, element, attr, myCtrl)\r
7377         {\r
7378             myCtrl.setExpanderScope(scope);\r
7379             var isOpen = myCtrl.isOpened();   \r
7380 \r
7381             scope.setIcon = function () {\r
7382                 element.attr("role", "tab");\r
7383 \r
7384                 if (scope.expandIcon && scope.collapseIcon)\r
7385                 {\r
7386                     if (isOpen) {\r
7387                         element.removeClass(scope.expandIcon);\r
7388                         element.addClass(scope.collapseIcon);\r
7389 \r
7390                         element.attr("aria-expanded", "true");\r
7391                     }\r
7392                     else {\r
7393                         element.removeClass(scope.collapseIcon);\r
7394                         element.addClass(scope.expandIcon);\r
7395 \r
7396                         element.attr("aria-expanded", "false");\r
7397                     }\r
7398                 }                               \r
7399             };\r
7400             \r
7401             element.bind('click', function (){\r
7402                 scope.toggleit();\r
7403             });\r
7404             scope.updateIcons = function(nStat){\r
7405                 isOpen = nStat;\r
7406                 scope.setIcon();                \r
7407             };\r
7408             scope.toggleit = function (){\r
7409                 isOpen = myCtrl.toggle();\r
7410                 scope.setIcon();\r
7411                 scope.$apply();\r
7412             };                    \r
7413             scope.setIcon();\r
7414         }\r
7415     };\r
7416 });\r
7417 /**\r
7418  * @ngdoc directive\r
7419  * @name Messages, modals & alerts.att:notesMessagesAndErrors\r
7420  *\r
7421  * @description\r
7422  *  <file src="src/notesMessagesAndErrors/docs/readme.md" />\r
7423  *\r
7424  * @usage\r
7425  *  See Demo\r
7426  *\r
7427  * @example\r
7428  *  <section id="code">\r
7429         <example module="b2b.att">\r
7430             <file src="src/notesMessagesAndErrors/docs/demo.html" />\r
7431             <file src="src/notesMessagesAndErrors/docs/demo.js" />\r
7432        </example>\r
7433         </section>\r
7434  *\r
7435  */\r
7436 angular.module('b2b.att.notesMessagesAndErrors', []);\r
7437 /** \r
7438  * @ngdoc directive \r
7439  * @name Template.att:Notification Card\r
7440  * \r
7441  * @description \r
7442  *  <file src="src/notificationCardTemplate/docs/readme.md" /> \r
7443  * \r
7444  * @example \r
7445  *  <section id="code"> \r
7446         <b>HTML + AngularJS</b> \r
7447         <example module="b2b.att"> \r
7448             <file src="src/notificationCardTemplate/docs/demo.html" /> \r
7449             <file src="src/notificationCardTemplate/docs/demo.js" /> \r
7450        </example> \r
7451     </section>    \r
7452  * \r
7453  */\r
7454 angular.module('b2b.att.notificationCardTemplate', [])\r
7455   \r
7456 /** \r
7457  * @ngdoc directive \r
7458  * @name Template.att:Order Confirmation Template\r
7459  * \r
7460  * @description \r
7461  *  <file src="src/orderConfirmationTemplate/docs/readme.md" /> \r
7462  * \r
7463  * @example \r
7464  *  <section id="code"> \r
7465         <b>HTML + AngularJS</b> \r
7466         <example module="b2b.att"> \r
7467             <file src="src/orderConfirmationTemplate/docs/demo.html" /> \r
7468             <file src="src/orderConfirmationTemplate/docs/demo.js" /> \r
7469        </example> \r
7470     </section>    \r
7471  * \r
7472  */\r
7473 angular.module('b2b.att.orderConfirmationTemplate', []);\r
7474   \r
7475 /**\r
7476  * @ngdoc directive\r
7477  * @name Navigation.att:pagination\r
7478  *\r
7479  * @description\r
7480  *  <file src="src/pagination/docs/readme.md" />\r
7481  *\r
7482  * @usage\r
7483  *   <div b2b-pagination="" input-id="goto-page-2" total-pages="totalPages1" current-page="currentPage1" click-handler="customHandler" show-input="showInput"></div> \r
7484  *\r
7485  * @example\r
7486  *  <section id="code">\r
7487         <example module="b2b.att">\r
7488             <file src="src/pagination/docs/demo.html" />\r
7489             <file src="src/pagination/docs/demo.js" />\r
7490        </example>\r
7491         </section>\r
7492  *\r
7493  */\r
7494 angular.module('b2b.att.pagination', ['b2b.att.utilities', 'ngTouch'])\r
7495     .directive('b2bPagination', ['b2bUserAgent', 'keymap', '$window', '$timeout', function (b2bUserAgent, keymap, $window, $timeout) {\r
7496         return {\r
7497             restrict: 'A',\r
7498             scope: {\r
7499                 totalPages: '=',\r
7500                 currentPage: '=',\r
7501                 showInput: '=',\r
7502                 clickHandler: '=?',\r
7503                 inputId: '='\r
7504             },\r
7505             replace: true,\r
7506             templateUrl: 'b2bTemplate/pagination/b2b-pagination.html',\r
7507             link: function (scope, elem) {\r
7508                 scope.isMobile = b2bUserAgent.isMobile();\r
7509                 scope.notMobile = b2bUserAgent.notMobile();\r
7510                 scope.focusedPage;\r
7511                 scope.meanVal = 3;\r
7512                 scope.$watch('totalPages', function (value) {\r
7513                     if (angular.isDefined(value) && value !== null) {\r
7514                         scope.pages = [];\r
7515                         if (value < 1) {\r
7516                             scope.totalPages = 1;\r
7517                             return;\r
7518                         }\r
7519                         if (value <= 10) {\r
7520                             for (var i = 1; i <= value; i++) {\r
7521                                 scope.pages.push(i);\r
7522                             }\r
7523                         } else if (value > 10) {\r
7524                             var midVal = Math.ceil(value / 2);\r
7525                             scope.pages = [midVal - 2, midVal - 1, midVal, midVal + 1, midVal + 2];\r
7526                         }\r
7527                         if(scope.currentPage === undefined || scope.currentPage === 1)\r
7528                         {\r
7529                             currentPageChanged(1);\r
7530                         }\r
7531                     }\r
7532                 });\r
7533                 scope.$watch('currentPage', function (value) {\r
7534                     currentPageChanged(value);\r
7535                     callbackHandler(value);\r
7536                 });\r
7537                 var callbackHandler = function (num) {\r
7538                     if (angular.isFunction(scope.clickHandler)) {\r
7539                         scope.clickHandler(num);\r
7540                     }\r
7541                 };\r
7542 \r
7543                 function currentPageChanged(value) {\r
7544                     if (angular.isDefined(value) && value !== null) {\r
7545                         if (!value || value < 1) {\r
7546                             value = 1;\r
7547                         }\r
7548                         if (value > scope.totalPages) {\r
7549                             value = scope.totalPages;\r
7550                         }\r
7551                         if (scope.currentPage !== value) {\r
7552                             scope.currentPage = value;\r
7553                             callbackHandler(scope.currentPage);\r
7554                         }\r
7555                         if (scope.totalPages > 10) {\r
7556                             var val = parseInt(value);\r
7557                             if (val <= 6) {\r
7558                                 scope.pages = [1, 2, 3, 4, 5, 6, 7, 8];\r
7559                             } else if (val > 6 && val <= scope.totalPages - 5) {\r
7560                                 scope.pages = [val - 1, val, val + 1];\r
7561                             } else if (val >= scope.totalPages - 5) {\r
7562                                 scope.pages = [scope.totalPages - 7, scope.totalPages - 6, scope.totalPages - 5, scope.totalPages - 4, scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];\r
7563                             }\r
7564                         }\r
7565                         if (scope.isMobile) {\r
7566                             var inWidth = $window.innerWidth;\r
7567                             var viewLimit = 7;\r
7568                             if (inWidth <= 400) {\r
7569                                 viewLimit = 7;\r
7570                             } else if (inWidth > 400 && inWidth < 500) {\r
7571                                 viewLimit = 9;\r
7572                             } else if (inWidth >= 500 && inWidth < 600) {\r
7573                                 viewLimit = 11;\r
7574                             } else if (inWidth >= 600 && inWidth < 700) {\r
7575                                 viewLimit = 13;\r
7576                             } else if (inWidth >= 700 && inWidth < 800) {\r
7577                                 viewLimit = 15;\r
7578                             }\r
7579 \r
7580                             var val = parseInt(value);\r
7581 \r
7582                             scope.meanVal = Math.floor(viewLimit / 2);\r
7583                             var lowerLimit = (val - scope.meanVal) < 1 ? 1 : val - scope.meanVal;\r
7584                             var upperLimit = (lowerLimit + viewLimit - 1) > scope.totalPages ? scope.totalPages : lowerLimit + viewLimit - 1;\r
7585                             scope.pages = [];\r
7586                             for (var i = lowerLimit; i <= upperLimit; i++) {\r
7587                                 scope.pages.push(i);\r
7588                             }\r
7589                         }\r
7590                     }\r
7591                 }\r
7592                 scope.gotoKeyClick = function (keyEvent) {\r
7593                   if (keyEvent.which === keymap.KEY.ENTER) {\r
7594                     scope.gotoBtnClick()\r
7595                   }\r
7596                 }\r
7597                 scope.gotoBtnClick = function () {\r
7598                     currentPageChanged(parseInt(scope.gotoPage)); \r
7599                     callbackHandler(scope.currentPage);\r
7600                     var qResult = elem[0].querySelector('button');\r
7601                     angular.element(qResult).attr('disabled','true');\r
7602                     $timeout(function(){\r
7603                         elem[0].querySelector('.b2b-pager__item--active').focus();\r
7604                     }, 50); \r
7605                     scope.gotoPage = null;               \r
7606                 }\r
7607                 scope.onfocusIn = function(evt)\r
7608                 {\r
7609                     var qResult = elem[0].querySelector('button');\r
7610                     angular.element(qResult).removeAttr('disabled');\r
7611                 }\r
7612                 scope.onfocusOut = function(evt)\r
7613                 {\r
7614                     if(evt.target.value === "")\r
7615                     {\r
7616                         var qResult = elem[0].querySelector('button');\r
7617                         angular.element(qResult).attr('disabled','true');\r
7618                     }                    \r
7619                 }\r
7620                 scope.next = function (event) {\r
7621                     if (event != undefined) {\r
7622                         event.preventDefault();\r
7623                     }\r
7624                     if (scope.currentPage < scope.totalPages) {\r
7625                         scope.currentPage += 1;\r
7626                         callbackHandler(scope.currentPage);\r
7627                     }\r
7628                 };\r
7629                 scope.prev = function (event) {\r
7630                     if (event != undefined) {\r
7631                         event.preventDefault();\r
7632                     }\r
7633                     if (scope.currentPage > 1) {\r
7634                         scope.currentPage -= 1;\r
7635                         callbackHandler(scope.currentPage);\r
7636                     }\r
7637                 };\r
7638                 scope.selectPage = function (value, event) {\r
7639                     event.preventDefault();\r
7640                     scope.currentPage = value;\r
7641                     scope.focusedPage = value;\r
7642                     callbackHandler(scope.currentPage);\r
7643                 };\r
7644                 scope.checkSelectedPage = function (value) {\r
7645                     if (scope.currentPage === value) {\r
7646                         return true;\r
7647                     }\r
7648                     return false;\r
7649                 };\r
7650                 scope.isFocused = function (page) {\r
7651                     return scope.focusedPage === page;\r
7652                 };\r
7653             }\r
7654         };\r
7655     }]);\r
7656 /**\r
7657  * @ngdoc directive\r
7658  * @name Navigation.att:paneSelector\r
7659  *\r
7660  * @description\r
7661  *  <file src="src/paneSelector/docs/readme.md" />\r
7662  *\r
7663  * @usage\r
7664  *  Please refer demo.html tab in Example section below.\r
7665  *\r
7666  * @example\r
7667     <section id="code">\r
7668         <b>HTML + AngularJS</b>\r
7669         <example module="b2b.att">\r
7670             <file src="src/paneSelector/docs/demo.html" />\r
7671             <file src="src/paneSelector/docs/demo.js" />\r
7672         </example>\r
7673     </section>\r
7674  */\r
7675 \r
7676 angular.module('b2b.att.paneSelector', ['b2b.att.tabs', 'b2b.att.utilities'])\r
7677 \r
7678 .filter('paneSelectorSelectedItemsFilter', [function () {\r
7679     return function (listOfItemsArray) {\r
7680 \r
7681         if (!listOfItemsArray) {\r
7682             listOfItemsArray = [];\r
7683         }\r
7684 \r
7685         var returnArray = [];\r
7686 \r
7687         for (var i = 0; i < listOfItemsArray.length; i++) {\r
7688             if (listOfItemsArray[i].isSelected) {\r
7689                 returnArray.push(listOfItemsArray[i]);\r
7690             }\r
7691         }\r
7692 \r
7693         return returnArray;\r
7694     };\r
7695 }])\r
7696 \r
7697 .filter('paneSelectorFetchChildItemsFilter', [function () {\r
7698     return function (listOfItemsArray) {\r
7699 \r
7700         if (!listOfItemsArray) {\r
7701             listOfItemsArray = [];\r
7702         }\r
7703 \r
7704         var returnArray = [];\r
7705 \r
7706         for (var i = 0; i < listOfItemsArray.length; i++) {\r
7707             for (var j = 0; j < listOfItemsArray[i].childItems.length; j++) {\r
7708                 returnArray.push(listOfItemsArray[i].childItems[j]);\r
7709             }\r
7710         }\r
7711 \r
7712         return returnArray;\r
7713     };\r
7714 }])\r
7715 \r
7716 .directive('b2bPaneSelector', [function () {\r
7717     return {\r
7718         restrict: 'AE',\r
7719         replace: true,\r
7720         templateUrl: 'b2bTemplate/paneSelector/paneSelector.html',\r
7721         transclude: true,\r
7722         scope: {}\r
7723     };\r
7724 }])\r
7725 \r
7726 .directive('b2bPaneSelectorPane', [ function () {\r
7727     return {\r
7728         restrict: 'AE',\r
7729         replace: true,\r
7730         templateUrl: 'b2bTemplate/paneSelector/paneSelectorPane.html',\r
7731         transclude: true,\r
7732         scope: {}\r
7733     };\r
7734 }])\r
7735 \r
7736 .directive('b2bTabVertical', ['$timeout', 'keymap', function ($timeout, keymap) {\r
7737     return {\r
7738         restrict: 'A',\r
7739         require: '^b2bTab',\r
7740         link: function (scope, element, attr, b2bTabCtrl) {\r
7741 \r
7742             if (!b2bTabCtrl) {\r
7743                 return;\r
7744             }\r
7745 \r
7746             // retreive the isolateScope\r
7747             var iScope = angular.element(element).isolateScope();\r
7748 \r
7749             $timeout(function () {\r
7750                 angular.element(element[0].querySelector('a')).unbind('keydown');\r
7751                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {\r
7752 \r
7753                     if (!(evt.keyCode)) {\r
7754                         evt.keyCode = evt.which;\r
7755                     }\r
7756 \r
7757                     switch (evt.keyCode) {\r
7758                         case keymap.KEY.DOWN:\r
7759                             evt.preventDefault();\r
7760                             iScope.nextKey();\r
7761                             break;\r
7762 \r
7763                         case keymap.KEY.UP:\r
7764                             evt.preventDefault();\r
7765                             iScope.previousKey();\r
7766                             break;\r
7767 \r
7768                         default:;\r
7769                     }\r
7770                 });\r
7771             });\r
7772         }\r
7773     };\r
7774 }]);\r
7775 /**\r
7776  * @ngdoc directive\r
7777  * @name Forms.att:phoneNumberInput\r
7778  *\r
7779  * @description\r
7780  *  <file src="src/phoneNumberInput/docs/readme.md" />\r
7781  *\r
7782  * @usage\r
7783 <form name="userForm1">\r
7784     <div class="form-row" ng-class="{'error':!userForm1.text.$valid && userForm1.text.$dirty}">\r
7785         <label>Phone Mask<span style="color:red">*</span>: (npa) nxx-line &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Model Value: {{mask.text}}</label>\r
7786         <div>\r
7787             <input b2b-phone-mask="phoneMask" name="text" ng-model="mask.text" type="text" placeholder="e.g. (123) 456-7890" title="Phone Number" class="b2b-phone-mask-input" required />\r
7788             <div ng-messages="userForm1.text.$error" class="error-msg" aria-live="polite" aria-atomic="true">\r
7789                 <span ng-message="required" role="alert">This field is mandatory!</span>\r
7790                 <span ng-message="invalidPhoneNumber" role="alert">Please enter valid phone number!</span>\r
7791                 <span ng-message="mask" role="alert">Please enter valid phone number!</span>\r
7792             </div>\r
7793         </div>\r
7794     </div>\r
7795 </form>\r
7796  *\r
7797  * @example\r
7798  *  <section id="code">\r
7799         <example module="b2b.att">\r
7800             <file src="src/phoneNumberInput/docs/demo.html" />\r
7801             <file src="src/phoneNumberInput/docs/demo.js" />\r
7802        </example>\r
7803     </section>\r
7804  *\r
7805  */\r
7806 angular.module('b2b.att.phoneNumberInput', ['ngMessages', 'b2b.att.utilities'])\r
7807     .constant("CoreFormsUiConfig", {\r
7808         phoneMask: '(___) ___-____',\r
7809         phoneMaskDot: '___.___.____',\r
7810         phoneMaskHyphen: '___-___-____'\r
7811     })\r
7812     .directive('b2bPhoneMask', ['$parse', 'CoreFormsUiConfig', 'keymap', function ($parse, CoreFormsUiConfig, keymap) {\r
7813         return {\r
7814             require: 'ngModel',\r
7815             scope: {\r
7816                 ngModel: '='\r
7817             },\r
7818             link: function (scope, iElement, iAttrs, ctrl) {\r
7819                 var navigatorAgent = navigator.userAgent.toLowerCase(),\r
7820                     isAndroid = navigatorAgent.indexOf("android") > -1,\r
7821                     oldIE = navigatorAgent.indexOf('msie 8.0') !== -1;\r
7822                 var mask = '';\r
7823                 var validPhoneNumber = false;\r
7824                 var currentKey = '';\r
7825                 if (isAndroid) {\r
7826                     mask = "__________";\r
7827                 } else {\r
7828                     switch (iAttrs.b2bPhoneMask) {\r
7829                     case "phoneMask":\r
7830                         mask = CoreFormsUiConfig.phoneMask;\r
7831                         break;\r
7832                     case "phoneMaskDot":\r
7833                         mask = CoreFormsUiConfig.phoneMaskDot;\r
7834                         break;\r
7835                     case "phoneMaskHyphen":\r
7836                         mask = CoreFormsUiConfig.phoneMaskHyphen;\r
7837                         break;\r
7838                     default:\r
7839                         mask = CoreFormsUiConfig.phoneMask;\r
7840                     }\r
7841                 }\r
7842                 iElement.attr("maxlength", mask.length);\r
7843                 var checkValidity = function (unmaskedValue, rawValue) {\r
7844                     var valid = false;\r
7845                     if (angular.isUndefined(rawValue) || rawValue === '') {\r
7846                         valid = true;\r
7847                     } else if (unmaskedValue) {\r
7848                         valid = (unmaskedValue.length === 10);\r
7849                     }\r
7850                     ctrl.$setValidity('invalidPhoneNumber', validPhoneNumber);\r
7851                     ctrl.$setValidity('mask', valid);\r
7852                     return valid;\r
7853                 };\r
7854                 var handleKeyup = function (evt) {\r
7855 \r
7856                     if (evt && evt.keyCode === keymap.KEY.SHIFT) {\r
7857                         return;\r
7858                     }\r
7859 \r
7860                     var index, formattedNumber;\r
7861                     if (ctrl.$modelValue) {\r
7862                         formattedNumber = ctrl.$modelValue;\r
7863                     } else {\r
7864                         formattedNumber = iElement.val();\r
7865                     }\r
7866                     if (!formattedNumber.length && currentKey === '') {\r
7867                         return;\r
7868                     }\r
7869                     var maskLength, inputNumbers, maskArray, tempArray, maskArrayLength;\r
7870                     tempArray = [];\r
7871                     maskArray = mask.split("");\r
7872                     maskArrayLength = maskArray.length;\r
7873                     maskLength = formattedNumber.substring(0, mask.length);\r
7874                     inputNumbers = formattedNumber.replace(/[^0-9]/g, "").split("");\r
7875                     for (index = 0; index < maskArrayLength; index++) {\r
7876                         tempArray.push(maskArray[index] === "_" ? inputNumbers.shift() : maskArray[index]);\r
7877                         if (inputNumbers.length === 0) {\r
7878                             break;\r
7879                         }\r
7880                     }\r
7881                     formattedNumber = tempArray.join("");\r
7882                     if (formattedNumber === '(') {\r
7883                         formattedNumber = '';\r
7884                     }\r
7885 \r
7886                     if ( (angular.isDefined(evt) && evt.which) && currentKey !== '') {\r
7887                         if (maskArray[0] === currentKey && formattedNumber === '') {\r
7888                             formattedNumber = '(';\r
7889                         } else if (evt.which === keymap.KEY.SPACE && currentKey === ' ') {\r
7890                             formattedNumber = formattedNumber + ') ';\r
7891                         } else if (maskArray[0] === currentKey && formattedNumber === '') {\r
7892                             formattedNumber = formattedNumber + currentKey;\r
7893                         } else if (maskArray[formattedNumber.length] === currentKey) {\r
7894                             formattedNumber = formattedNumber + currentKey;\r
7895                         }\r
7896                         currentKey = '';\r
7897                     }\r
7898 \r
7899                     ctrl.$setViewValue(formattedNumber);\r
7900                     ctrl.$render();\r
7901                     return formattedNumber;\r
7902                 };\r
7903 \r
7904 \r
7905                 // since we are only allowing 0-9, why even let the keypress go forward?\r
7906                 // also added in delete... in case they want to delete :)\r
7907                 var handlePress = function (e) {\r
7908                     if (e.which) {\r
7909                         if ((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105)) {\r
7910                             if (e.which !== keymap.KEY.BACKSPACE && e.which !== keymap.KEY.TAB && e.which !== keymap.KEY.DELETE && e.which !== keymap.KEY.ENTER && e.which !== keymap.KEY.LEFT && e.which !== keymap.KEY.RIGHT &&\r
7911                                 // Allow: Ctrl+V/v\r
7912                                 (!(e.ctrlKey) && (e.which !== '118' || e.which !== '86')) &&\r
7913                                 // Allow: Ctrl+C/c\r
7914                                 (!(e.ctrlKey) && (e.which !== '99' || e.which !== '67')) &&\r
7915                                 // Allow: Ctrl+X/x\r
7916                                 (!(e.ctrlKey) && (e.which !== '120' || e.which !== '88'))) {\r
7917                                 e.preventDefault ? e.preventDefault() : e.returnValue = false;\r
7918                                 iElement.attr("aria-label", "Only numbers are allowed");\r
7919                                 validPhoneNumber = false;\r
7920                             }\r
7921                         } else {\r
7922                             iElement.removeAttr("aria-label");\r
7923                             validPhoneNumber = true;\r
7924                         }\r
7925 \r
7926                         setCurrentKey(e);\r
7927                     }\r
7928                     scope.$apply();\r
7929                 };\r
7930                 // i moved this out because i thought i might need focus as well..\r
7931                 // to handle setting the model as the view changes\r
7932                 var parser = function (fromViewValue) {\r
7933                     var letters = /^[A-Za-z]+$/;\r
7934                     var numbers = /^[0-9]+$/;\r
7935                     if (angular.isUndefined(fromViewValue) || fromViewValue === '') {\r
7936                         validPhoneNumber = true;\r
7937                     } else {\r
7938                         if (fromViewValue.match(letters)) {\r
7939                             validPhoneNumber = false;\r
7940                         }\r
7941                         if (fromViewValue.match(numbers)) {\r
7942                             validPhoneNumber = true;\r
7943                         }\r
7944                     }\r
7945                     var clean = "";\r
7946                     if (fromViewValue && fromViewValue.length > 0) {\r
7947                         clean = fromViewValue.replace(/[^0-9]/g, '');\r
7948                     }\r
7949                     checkValidity(clean, fromViewValue);\r
7950                     return clean;\r
7951                 };\r
7952 \r
7953                 //to handle reading the model and formatting it\r
7954                 var formatter = function (fromModelView) {\r
7955                     var input = '';\r
7956                     checkValidity(fromModelView);\r
7957                     if (fromModelView) {\r
7958                         input = handleKeyup();\r
7959                     }\r
7960                     return input;\r
7961                 };\r
7962 \r
7963                 var setCurrentKey = function (e) {\r
7964                     switch (e.which) {\r
7965                     case 189:\r
7966                     case 109:\r
7967                         currentKey = '-';\r
7968                         break;\r
7969                     case 190:\r
7970                     case 110:\r
7971                         currentKey = '.';\r
7972                         break;\r
7973                     case 57:\r
7974                         if (e.shiftKey === true) {\r
7975                             currentKey = '(';\r
7976                         }\r
7977                         break;\r
7978                     case 48:\r
7979                         if (e.shiftKey === true) {\r
7980                             currentKey = ')';\r
7981                         }\r
7982                         break;\r
7983                     case 32:\r
7984                         currentKey = ' ';\r
7985                         break;\r
7986                     }\r
7987                 };\r
7988 \r
7989                 if (angular.isDefined(scope.ngModel)) {\r
7990                     parser(scope.ngModel);\r
7991                 }\r
7992 \r
7993                 ctrl.$parsers.push(parser);\r
7994                 ctrl.$formatters.push(formatter);\r
7995                 iElement.bind('keyup', handleKeyup);\r
7996                 iElement.bind('keydown', handlePress);\r
7997             }\r
7998         };\r
7999 }]);\r
8000 /** \r
8001  * @ngdoc directive \r
8002  * @name Template.att:Profile Blocks \r
8003  * \r
8004  * @description \r
8005  *  <file src="src/profileBlockTemplate/docs/readme.md" /> \r
8006  * @example \r
8007  *  <section id="code">  \r
8008         <example module="b2b.att"> \r
8009             <file src="src/profileBlockTemplate/docs/demo.html" /> \r
8010             <file src="src/profileBlockTemplate/docs/demo.js" /> \r
8011        </example>  \r
8012     </section>  \r
8013  *  \r
8014  */   \r
8015 \r
8016 angular.module('b2b.att.profileBlockTemplate', [])\r
8017     \r
8018      \r
8019   \r
8020 /**\r
8021  * @ngdoc directive\r
8022  * @name Layouts.att:profileCard\r
8023  *\r
8024  * @description\r
8025  *  <file src="src/profileCard/docs/readme.md" />\r
8026  *\r
8027  * @usage\r
8028  *  <b2b-profile-card></b2b-profile-card>\r
8029  *\r
8030  * @example\r
8031     <section id="code">   \r
8032         <example module="b2b.att">\r
8033             <file src="src/profileCard/docs/demo.html" />\r
8034             <file src="src/profileCard/docs/demo.js" />\r
8035         </example>\r
8036     </section>\r
8037  */\r
8038 \r
8039 angular.module('b2b.att.profileCard', ['b2b.att'])\r
8040 .constant('profileStatus',{\r
8041     status: {\r
8042         ACTIVE: {\r
8043             status: "Active",\r
8044             color: "green"\r
8045         },\r
8046         DEACTIVATED: {\r
8047             status: "Deactivated",\r
8048             color: "red"\r
8049         },\r
8050         LOCKED: {\r
8051             status: "Locked",\r
8052             color: "red"\r
8053         },\r
8054         IDLE: {\r
8055             status: "Idle",\r
8056             color: "yellow"\r
8057         },\r
8058         PENDING: {\r
8059             status: "Pending",\r
8060             color: "blue"\r
8061         }\r
8062     },\r
8063     role: "COMPANY ADMINISTRATOR"\r
8064 \r
8065 })\r
8066 .directive('b2bProfileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {\r
8067    return {\r
8068         restrict: 'EA',\r
8069         replace: 'true',\r
8070         templateUrl: function(element, attrs){\r
8071             if(!attrs.addUser){\r
8072                 return 'b2bTemplate/profileCard/profileCard.html';\r
8073             }\r
8074             else{\r
8075                 return 'b2bTemplate/profileCard/profileCard-addUser.html';\r
8076             }\r
8077         },\r
8078         scope: {\r
8079             profile:'=',\r
8080             characterLimit: '@'\r
8081         },\r
8082         link: function(scope, elem, attr){\r
8083             scope.characterLimit = parseInt(attr.characterLimit, 10) || 25;\r
8084             scope.shouldClip = function(str) {\r
8085                 return str.length > scope.characterLimit;\r
8086             };\r
8087 \r
8088             scope.showEmailTooltip = false;\r
8089 \r
8090             scope.image=true;\r
8091             function isImage(src) {\r
8092                 var deferred = $q.defer();\r
8093                 var image = new Image();\r
8094                 image.onerror = function() {\r
8095                     deferred.reject(false);\r
8096                 };\r
8097                 image.onload = function() {\r
8098                     deferred.resolve(true);\r
8099                 };\r
8100                 if(src !== undefined && src.length>0 ){\r
8101                     image.src = src;\r
8102                 } else {\r
8103                      deferred.reject(false);\r
8104                 }\r
8105                 return deferred.promise;\r
8106             }\r
8107             if(!attr.addUser){\r
8108             scope.image=false;\r
8109             isImage(scope.profile.img).then(function(img) {\r
8110                 scope.image=img;\r
8111             });\r
8112             var splitName=(scope.profile.name).split(' ');\r
8113             scope.initials='';\r
8114             for(var i=0;i<splitName.length;i++){\r
8115                 scope.initials += splitName[i][0];\r
8116             }\r
8117             if(scope.profile.role.toUpperCase() === profileStatus.role){\r
8118                 scope.badge=true;\r
8119             }\r
8120             var profileState=profileStatus.status[scope.profile.state.toUpperCase()];\r
8121             if(profileState) {\r
8122                 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;\r
8123                 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;\r
8124                 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){\r
8125                         scope.profile.lastLogin=scope.profile.state;\r
8126                 }\r
8127             }\r
8128             var today=new Date().getTime();\r
8129             var lastlogin=new Date(scope.profile.lastLogin).getTime();\r
8130             var diff=(today-lastlogin)/(1000*60*60*24);\r
8131             if(diff<=1){\r
8132                 scope.profile.lastLogin="Today";\r
8133             }\r
8134             else if(diff<=2){\r
8135                 scope.profile.lastLogin="Yesterday";\r
8136             }\r
8137         }\r
8138     }\r
8139 };\r
8140 }]);\r
8141 /**\r
8142  * @ngdoc directive\r
8143  * @name Forms.att:radios\r
8144  *\r
8145  * @description\r
8146  *  <file src="src/radios/docs/readme.md" />\r
8147  *\r
8148  * @usage\r
8149  *  See demo section\r
8150  *\r
8151  * @param {boolean} refreshRadioGroup - A trigger that recalculates and updates the accessibility roles on radios in a group.\r
8152  * \r
8153  * @example\r
8154     <section id="code">\r
8155                <b>HTML + AngularJS</b>\r
8156                <example module="b2b.att">\r
8157                 <file src="src/radios/docs/demo.html" />\r
8158                 <file src="src/radios/docs/demo.js" />\r
8159                </example>\r
8160             </section>\r
8161  */\r
8162 angular.module('b2b.att.radios', ['b2b.att.utilities'])\r
8163 .directive('b2bRadioGroupAccessibility', ['$timeout', 'b2bUserAgent', function($timeout, b2bUserAgent) {\r
8164     return {\r
8165         restrict: "A",\r
8166         scope: {\r
8167             refreshRadioGroup: "=",\r
8168         },\r
8169         link: function(scope, ele, attr) {\r
8170 \r
8171             var roleRadioElement, radioProductSelectElement, radioInputTypeElement;\r
8172 \r
8173             $timeout(calculateNumberOfRadio);\r
8174 \r
8175             scope.$watch('refreshRadioGroup', function(value) {\r
8176                 if (value === true) {\r
8177                     addingRoleAttribute();\r
8178                     $timeout(calculateNumberOfRadio);\r
8179                     scope.refreshRadioGroup = false;\r
8180                 } else {\r
8181                     return;\r
8182                 }\r
8183             })\r
8184 \r
8185 \r
8186             function calculateNumberOfRadio() {\r
8187                 roleRadioElement = ele[0].querySelectorAll('[role="radio"]');\r
8188 \r
8189                 radioProductSelectElement = ele[0].querySelectorAll('[role="radiogroup"] li.radio-box');\r
8190 \r
8191                 radioInputTypeElement = ele[0].querySelectorAll('input[type="radio"]');\r
8192 \r
8193                 for (var i = 0; i < radioInputTypeElement.length; i++) {\r
8194                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';\r
8195                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';\r
8196                     var numOfx = i + 1 + ' of ' + radioInputTypeElement.length;\r
8197                     angular.element(roleRadioElement[i]).attr({\r
8198                         'aria-checked': isChecked,\r
8199                         'aria-disabled': isDisabled,\r
8200                         'data-opNum': numOfx\r
8201                     });\r
8202                     if (b2bUserAgent.notMobile()) {\r
8203                         angular.element(roleRadioElement[i]).removeAttr("role");\r
8204                     }\r
8205 \r
8206                     if (radioProductSelectElement.length) {\r
8207                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');\r
8208                     }\r
8209 \r
8210                     if (/Android/i.test(navigator.userAgent)) {\r
8211                         angular.element(roleRadioElement[i]).append('<span class="hidden-spoken">. ' + numOfx + '.</span>');\r
8212                     }\r
8213 \r
8214 \r
8215                     angular.element(radioInputTypeElement[i]).bind('click', radioStateChangeonClick);\r
8216 \r
8217                 }\r
8218             }\r
8219 \r
8220             function addingRoleAttribute() {\r
8221                 for (var i = 0; i < radioInputTypeElement.length; i++) {\r
8222                     if (b2bUserAgent.notMobile()) {\r
8223                         angular.element(roleRadioElement[i]).attr("role", "radio");\r
8224                     }\r
8225                 }\r
8226             }\r
8227 \r
8228             function radioStateChangeonClick() {\r
8229                 for (var i = 0; i < radioInputTypeElement.length; i++) {\r
8230                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';\r
8231                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';\r
8232                     if (radioProductSelectElement.length) {\r
8233                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');\r
8234                     }\r
8235                     angular.element(roleRadioElement[i]).attr({\r
8236                         'aria-checked': isChecked,\r
8237                         'aria-disabled': isDisabled\r
8238                     });\r
8239                 }\r
8240 \r
8241             }\r
8242         }\r
8243     }\r
8244 \r
8245 }]);\r
8246 \r
8247 /**\r
8248  * @ngdoc directive\r
8249  * @name Forms.att:searchField\r
8250  *\r
8251  * @description\r
8252  *  <file src="src/searchField/docs/readme.md" />\r
8253  *\r
8254  * @usage\r
8255  *  <div b2b-search-field dropdown-list="listdata" on-click-callback="clickFn(value)" class="span12" input-model='typedString' config-obj='keyConfigObj'></div>\r
8256  *\r
8257  * @example\r
8258  <section id="code">\r
8259     <example module="b2b.att">\r
8260     <file src="src/searchField/docs/demo.html" />\r
8261     <file src="src/searchField/docs/demo.js" />\r
8262     </example>\r
8263 </section>\r
8264  */\r
8265 \r
8266 angular.module('b2b.att.searchField', ['b2b.att.utilities', 'b2b.att.position'])\r
8267     .filter('b2bFilterInput', [function() {\r
8268         return function(list, str, keyArray, displayListKey, isContainsSearch, searchSeperator) {\r
8269             var res = [];\r
8270             var searchLabel;\r
8271             var searchCondition;\r
8272             var conditionCheck = function(searchSeperator, listItem, displayListKey, splitString) {\r
8273                 var displayTitle = null;\r
8274                 if (splitString) {\r
8275                     for (var i = 0; i < displayListKey.length; i++) {\r
8276                         if (i <= 0) {\r
8277                             displayTitle = listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase()) > -1;\r
8278                         } else {\r
8279                             displayTitle = (splitString[i]) ? displayTitle && listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase().trim()) > -1 : displayTitle;\r
8280                         }\r
8281                     }\r
8282                 } else {\r
8283                     angular.forEach(displayListKey, function(value) {\r
8284                         if (!displayTitle) {\r
8285                             displayTitle = listItem[value];\r
8286                         } else {\r
8287                             displayTitle = displayTitle + (listItem[value] ? searchSeperator + ' ' + listItem[value] : '');\r
8288                         }\r
8289                     });\r
8290                 }\r
8291                 return displayTitle;\r
8292             }\r
8293             angular.forEach(list, function(listItem) {\r
8294                 var splitString = str.indexOf(searchSeperator) > -1 ? str.split(searchSeperator) : false;\r
8295                 var displayList = conditionCheck(searchSeperator, listItem, displayListKey, splitString)\r
8296                 for (var i = 0; i < keyArray.length; i++) {\r
8297                     searchLabel = keyArray[i];\r
8298                     if (listItem[searchLabel]) {\r
8299                         if (isContainsSearch) {\r
8300                             var displaySearchList = listItem[searchLabel].toLowerCase().indexOf(str.toLowerCase()) > -1;\r
8301                             if (splitString.length > 1) {\r
8302                                 displaySearchList = (splitString.length <= keyArray.length) ? displayList : false;\r
8303                             }\r
8304                             searchCondition = displaySearchList;\r
8305                         } else {\r
8306                             searchCondition = listItem[searchLabel].match(new RegExp('^' + str, 'gi'));\r
8307                         }\r
8308                         if (searchCondition) {\r
8309                             res.push({\r
8310                                 'title': conditionCheck(searchSeperator, listItem, displayListKey),\r
8311                                 'valueObj': listItem\r
8312                             });\r
8313                             break;\r
8314                         }\r
8315                     }\r
8316                 }\r
8317             });\r
8318             return res;\r
8319         };\r
8320     }]).directive('b2bSearchField', ['$filter', 'b2bFilterInputFilter', 'keymap', '$documentBind', '$isElement', '$document', 'events', '$timeout', function($filter, b2bFilterInput, keymap, $documentBind, $isElement, $document, events, $timeout) {\r
8321         return {\r
8322             restrict: 'A',\r
8323             scope: {\r
8324                 dataList: '=dropdownList',\r
8325                 onClickCallback: '&',\r
8326                 inputModel: '=',\r
8327                 configObj: '=',\r
8328                 objModel: '=',\r
8329                 inputDeny: '=?',\r
8330                 disabled: '=?'\r
8331             },\r
8332             replace: true,\r
8333             templateUrl: 'b2bTemplate/searchField/searchField.html',\r
8334             controller: ['$scope', function($scope) {\r
8335                 this.searchKeyArray = [];\r
8336                 if ($scope.configObj.searchKeys) {\r
8337                     this.searchKeyArray = $scope.configObj.searchKeys;\r
8338                 }\r
8339                 if (angular.isUndefined($scope.disabled)) {\r
8340                     $scope.disabled = false;\r
8341                 }\r
8342                 this.triggerInput = function(searchString) {\r
8343                     $scope.originalInputModel = searchString;\r
8344                     if (searchString === '') {\r
8345                         $scope.currentIndex = -1;\r
8346                         $scope.filterList = [];\r
8347                         $scope.showListFlag = false;\r
8348                     } else if (searchString !== '' && !$scope.isFilterEnabled) {\r
8349                         $scope.filterList = $filter('b2bFilterInput')($scope.dataList, searchString, this.searchKeyArray, $scope.configObj.displayListDataKey, $scope.configObj.isContainsSearch, $scope.configObj.searchSeperator);\r
8350                         $scope.showListFlag = true;\r
8351                     }\r
8352                 };\r
8353                 this.denyRegex = function() {\r
8354                     return $scope.inputDeny;\r
8355                 };\r
8356             }],\r
8357             link: function(scope, elem) {\r
8358                 scope.isFilterEnabled = false;\r
8359                 scope.showListFlag = false;\r
8360                 scope.currentIndex = -1;\r
8361                 scope.setCurrentIdx = function(idx) {\r
8362                     scope.currentIndex = idx;\r
8363                     if (idx > -1) {\r
8364                         scope.inputModel = scope.filterList[idx].title;\r
8365                         scope.objModel = scope.filterList[idx];\r
8366                     }\r
8367                 };\r
8368                 scope.isActive = function(index, dropdownLength) {\r
8369                     scope.dropdownLength = dropdownLength;\r
8370                     return scope.currentIndex === index;\r
8371                 };\r
8372                 scope.selectItem = function(idx) {\r
8373                     scope.setCurrentIdx(idx);\r
8374                     scope.onClickCallback({\r
8375                         value: scope.inputModel,\r
8376                         objValue: scope.objModel\r
8377                     });\r
8378                     scope.showListFlag = false;\r
8379                     $timeout(function() {\r
8380                         elem.find('div').find('input')[0].focus();\r
8381                     }, 150);\r
8382                 };\r
8383                 scope.startSearch = function() {\r
8384                     scope.onClickCallback({\r
8385                         value: scope.inputModel,\r
8386                         objValue: scope.objModel\r
8387                     });\r
8388                 };\r
8389                 scope.selectPrev = function() {\r
8390                     if (scope.currentIndex > 0 && scope.filterList.length > 0) {\r
8391                         scope.currentIndex = scope.currentIndex - 1;\r
8392                         scope.setCurrentIdx(scope.currentIndex);\r
8393                     } else if (scope.currentIndex === 0) {\r
8394                         scope.currentIndex = scope.currentIndex - 1;\r
8395                         scope.inputModel = scope.originalInputModel;\r
8396                         scope.isFilterEnabled = true;\r
8397                     }\r
8398                 };\r
8399                 scope.selectNext = function() {\r
8400                     if (scope.currentIndex < scope.configObj.noOfItemsDisplay - 1) {\r
8401                         if (scope.currentIndex < scope.filterList.length - 1) {\r
8402                             scope.currentIndex = scope.currentIndex + 1;\r
8403                             scope.setCurrentIdx(scope.currentIndex);\r
8404                         }\r
8405                     }\r
8406                 };\r
8407                 scope.selectCurrent = function() {\r
8408                     scope.selectItem(scope.currentIndex);\r
8409                 };\r
8410                 scope.selectionIndex = function(e) {\r
8411                     switch (e.keyCode) {\r
8412                         case keymap.KEY.DOWN:\r
8413                             events.preventDefault(e);\r
8414                             scope.isFilterEnabled = true;\r
8415                             scope.selectNext();\r
8416                             break;\r
8417                         case keymap.KEY.UP:\r
8418                             events.preventDefault(e);\r
8419                             scope.isFilterEnabled = true;\r
8420                             scope.selectPrev();\r
8421                             break;\r
8422                         case keymap.KEY.ENTER:\r
8423                             events.preventDefault(e);\r
8424                             scope.isFilterEnabled = true;\r
8425                             scope.selectCurrent();\r
8426                             break;\r
8427                         case keymap.KEY.ESC:\r
8428                             events.preventDefault(e);\r
8429                             scope.isFilterEnabled = false;\r
8430                             scope.showListFlag = false;\r
8431                             scope.inputModel = '';\r
8432                             break;\r
8433                         default:\r
8434                             scope.isFilterEnabled = false;\r
8435                             break;\r
8436                     }\r
8437                     if (elem[0].querySelector('.filtercontainer')) {\r
8438                         elem[0].querySelector('.filtercontainer').scrollTop = (scope.currentIndex - 1) * 35;\r
8439                     }\r
8440                 };\r
8441                 scope.$watch('filterList', function(newVal, oldVal) {\r
8442                     if (newVal !== oldVal) {\r
8443                         scope.currentIndex = -1;\r
8444                     }\r
8445                 });\r
8446                 scope.blurInput = function() {\r
8447                     $timeout(function() {\r
8448                         scope.showListFlag = false;\r
8449                     }, 150);\r
8450                 };\r
8451                 var outsideClick = function(e) {\r
8452                     var isElement = $isElement(angular.element(e.target), elem.find('ul').eq(0), $document);\r
8453                     if (!isElement && document.activeElement.tagName.toLowerCase() !== 'input') {\r
8454                         scope.showListFlag = false;\r
8455                         scope.$apply();\r
8456                     }\r
8457                 };\r
8458                 $documentBind.click('showListFlag', outsideClick, scope);\r
8459             }\r
8460         };\r
8461     }])\r
8462     .directive('b2bSearchInput', [function() {\r
8463         return {\r
8464             restrict: 'A',\r
8465             require: ['ngModel', '^b2bSearchField'],\r
8466             link: function(scope, elem, attr, ctrl) {\r
8467                 var ngModelCtrl = ctrl[0];\r
8468                 var attSearchBarCtrl = ctrl[1];\r
8469                 var REGEX = ctrl[1].denyRegex();\r
8470                 var parser = function(viewValue) {\r
8471                     attSearchBarCtrl.triggerInput(viewValue);\r
8472                     return viewValue;\r
8473                 };\r
8474                 ngModelCtrl.$parsers.push(parser);\r
8475 \r
8476                 if (REGEX !== undefined || REGEX !== '') {\r
8477                     elem.bind('input', function() {\r
8478                         var inputString = ngModelCtrl.$viewValue && ngModelCtrl.$viewValue.replace(REGEX, '');\r
8479                         if (inputString !== ngModelCtrl.$viewValue) {\r
8480                             ngModelCtrl.$setViewValue(inputString);\r
8481                             ngModelCtrl.$render();\r
8482                             scope.$apply();\r
8483                         }\r
8484                     });\r
8485                 }\r
8486             }\r
8487         };\r
8488     }]);\r
8489 \r
8490 /**\r
8491  * @ngdoc directive\r
8492  * @name Buttons, links & UI controls.att:Seek bar\r
8493  *\r
8494  * @description\r
8495  *  <file src="src/seekBar/docs/readme.md" />\r
8496  *\r
8497  * @usage\r
8498  *  Horizontal Seek Bar\r
8499  *  <b2b-seek-bar min="0" max="400" step="1" skip-interval="1" data-ng-model="horizontalSeekBarVal" style="width:180px; margin: auto;" on-drag-end="onDragEnd()" on-drag-init="onDragStart()"></b2b-seek-bar>\r
8500 \r
8501  *  Vertical Seek Bar\r
8502  *  <b2b-seek-bar min="0" max="1" step="0.01" skip-interval="0.1" vertical data-ng-model="verticalSeekBarVal" style=" width: 6px; height: 180px; margin: auto;"></b2b-seek-bar>\r
8503  *\r
8504  * @example\r
8505     <section id="code">   \r
8506         <b>HTML + AngularJS</b>\r
8507         <example module="b2b.att">\r
8508             <file src="src/seekBar/docs/demo.html" />\r
8509             <file src="src/seekBar/docs/demo.js" />\r
8510         </example>\r
8511     </section>\r
8512  */\r
8513 \r
8514 angular.module('b2b.att.seekBar', ['b2b.att.utilities','b2b.att.position'])\r
8515         .constant('b2bSeekBarConfig', {\r
8516             'min': 0,\r
8517             'max': 100,\r
8518             'step': 1,\r
8519             'skipInterval': 1\r
8520         })\r
8521         .directive('b2bSeekBar', ['$documentBind', 'events', 'b2bSeekBarConfig', 'keymap', '$compile', function($documentBind, events, b2bSeekBarConfig, keymap, $compile) {\r
8522                 return {\r
8523                     restrict: 'AE',\r
8524                     replace: true,\r
8525                     require: 'ngModel',\r
8526                     templateUrl: 'b2bTemplate/seekBar/seekBar.html',\r
8527                     scope: {\r
8528                         onDragEnd: '&?',\r
8529                         onDragInit: '&?'\r
8530                     },\r
8531                     link: function(scope, elm, attr, ngModelCtrl) {\r
8532                         scope.isDragging = false;\r
8533                         scope.verticalSeekBar = false;\r
8534                         var min;\r
8535                         var max;\r
8536                         var step = b2bSeekBarConfig.step;\r
8537                         var skipInterval = b2bSeekBarConfig.skipInterval;\r
8538                         var knob = angular.element(elm[0].querySelector('.b2b-seek-bar-knob-container'));\r
8539                         var seekBarKnob = angular.element(knob[0].querySelector('.b2b-seek-bar-knob'));\r
8540                         var trackContainer = angular.element(elm[0].querySelector('.b2b-seek-bar-track-container'));\r
8541                         var trackFill = angular.element(elm[0].querySelector('.b2b-seek-bar-track-fill'));\r
8542                         var trackContainerRect = {};\r
8543                         var axisPosition;\r
8544                         var trackFillOrderPositioning;\r
8545 \r
8546                         if (angular.isDefined(attr.vertical)) {\r
8547                             scope.verticalSeekBar = true;\r
8548                             axisPosition = "clientY";\r
8549                         }\r
8550                         else {\r
8551                             scope.verticalSeekBar = false;\r
8552                             axisPosition = "clientX";\r
8553                         }\r
8554                         var getValidStep = function(val) {\r
8555                             val = parseFloat(val);\r
8556                             // in case $modelValue came in string number\r
8557                             if (angular.isNumber(val)) {\r
8558                                 val = Math.round((val - min) / step) * step + min;\r
8559                                 return Math.round(val * 1000) / 1000;\r
8560                             }\r
8561                         };\r
8562 \r
8563                         var getPositionToPercent = function(x) {\r
8564                             if (scope.verticalSeekBar) {\r
8565                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));\r
8566                             }\r
8567                             else {\r
8568                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));\r
8569                             }\r
8570                         };\r
8571 \r
8572                         var getPercentToValue = function(percent) {\r
8573                             return (min + percent * (max - min));\r
8574                         };\r
8575 \r
8576                         var getValueToPercent = function(val) {\r
8577                             return (val - min) / (max - min);\r
8578                         };\r
8579 \r
8580                         var getValidMinMax = function(val) {\r
8581                             return Math.max(min, Math.min(max, val));\r
8582                         };\r
8583 \r
8584                         var updateTrackContainerRect = function() {\r
8585                             trackContainerRect = trackContainer[0].getBoundingClientRect();\r
8586                             if (scope.verticalSeekBar) {\r
8587                                 if (!trackContainerRect.height) {\r
8588                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;\r
8589                                 } else {\r
8590                                     trackFillOrderPositioning = trackContainerRect.height;\r
8591                                 }\r
8592                             }\r
8593                             else {\r
8594                                 if (!trackContainerRect.width) {\r
8595                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;\r
8596                                 } else {\r
8597                                     trackFillOrderPositioning = trackContainerRect.width;\r
8598                                 }\r
8599 \r
8600                             }\r
8601 \r
8602                         };\r
8603 \r
8604                         var updateKnobPosition = function(percent) {\r
8605                             var percentStr = (percent * 100) + '%';\r
8606                             if (scope.verticalSeekBar) {\r
8607                                 knob.css('bottom', percentStr);\r
8608                                 trackFill.css('height', percentStr);\r
8609                             }\r
8610                             else {\r
8611                                 knob.css('left', percentStr);\r
8612                                 trackFill.css('width', percentStr);\r
8613                             }\r
8614                         };\r
8615 \r
8616                         var modelRenderer = function() {\r
8617                             if (isNaN(ngModelCtrl.$viewValue)) {\r
8618                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;\r
8619                             }\r
8620 \r
8621                             var viewVal = ngModelCtrl.$viewValue;\r
8622                             scope.currentModelValue = viewVal;\r
8623 \r
8624                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation\r
8625                             if ((min || min === 0) && max && step) {\r
8626                                 updateKnobPosition(getValueToPercent(viewVal));\r
8627                             }\r
8628                         };\r
8629 \r
8630                         var setModelValue = function(val) {\r
8631                             scope.currentModelValue = getValidMinMax(getValidStep(val));\r
8632                             ngModelCtrl.$setViewValue(scope.currentModelValue);\r
8633                         };\r
8634 \r
8635                         var updateMin = function(val) {\r
8636                             min = parseFloat(val);\r
8637                             if(isNaN(min)){\r
8638                                min = b2bSeekBarConfig.min; \r
8639                             }\r
8640                             modelRenderer();\r
8641                         };\r
8642 \r
8643                         var updateMax = function(val) {\r
8644                             max = parseFloat(val);\r
8645                             if(isNaN(max)){\r
8646                                max = b2bSeekBarConfig.max; \r
8647                             }\r
8648                             modelRenderer();\r
8649                         };\r
8650 \r
8651                         var updateStep = function(val) {\r
8652                             step = parseFloat(val);\r
8653                             if (!attr['skipInterval']) {\r
8654                                 skipInterval = step;\r
8655                             }\r
8656                         };\r
8657 \r
8658                         var updateSkipInterval = function(val) {\r
8659                             skipInterval = step * Math.ceil(val / (step!==0?step:1));\r
8660                         };\r
8661 \r
8662                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(b2bSeekBarConfig.min);\r
8663                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(b2bSeekBarConfig.max);\r
8664                         if (angular.isDefined(attr.step)) {\r
8665                             attr.$observe('step', updateStep);\r
8666                         }\r
8667                         if (angular.isDefined(attr.skipInterval)) {\r
8668                             attr.$observe('skipInterval', updateSkipInterval);\r
8669                         }\r
8670                         scope.currentModelValue = getValidMinMax(getValidStep(min));\r
8671                         var onMouseDown = function(e) {\r
8672                             switch (e.which) {\r
8673                                 case 1:\r
8674                                     // left mouse button\r
8675                                     break;\r
8676                                 case 2:\r
8677                                 case 3:\r
8678                                     // right or middle mouse button\r
8679                                     return;\r
8680                             }\r
8681                             ;\r
8682 \r
8683                             scope.isDragging = true;\r
8684                             seekBarKnob[0].focus();\r
8685                             updateTrackContainerRect();\r
8686                             if (attr['onDragInit']) {\r
8687                                 scope.onDragInit();\r
8688                             }\r
8689                             events.stopPropagation(e);\r
8690                             events.preventDefault(e);\r
8691                              scope.$apply(function() {\r
8692                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
8693                             });\r
8694                         };\r
8695 \r
8696                         var onMouseUp = function() {\r
8697 \r
8698                             if (attr['onDragEnd']) {\r
8699                                 scope.onDragEnd();\r
8700                             }\r
8701                             scope.isDragging = false;\r
8702                             scope.$digest();\r
8703                         };\r
8704 \r
8705                         var onMouseMove = function(e) {\r
8706                             if (scope.isDragging) {\r
8707                                 events.stopPropagation(e);\r
8708                                 events.preventDefault(e);\r
8709 \r
8710                                 scope.$apply(function() {\r
8711                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
8712                                 });\r
8713                             }\r
8714                         };\r
8715 \r
8716                         function onKeyDown(e) {\r
8717                             if (!(e.keyCode)) {\r
8718                                 e.keyCode = e.which;\r
8719                             }\r
8720                             var updateStep;\r
8721                             switch (e.keyCode) {\r
8722                                 case keymap.KEY.LEFT:\r
8723                                     if (!scope.verticalSeekBar) {\r
8724                                         updateStep = -skipInterval;\r
8725                                     }\r
8726                                     break;\r
8727                                 case keymap.KEY.RIGHT:\r
8728                                     if (!scope.verticalSeekBar) {\r
8729                                         updateStep = skipInterval;\r
8730                                     }\r
8731                                     break;\r
8732                                 case keymap.KEY.UP:\r
8733                                     if (scope.verticalSeekBar) {\r
8734                                         updateStep = skipInterval;\r
8735                                     }\r
8736                                     break;\r
8737                                 case keymap.KEY.DOWN:\r
8738                                     if (scope.verticalSeekBar) {\r
8739                                         updateStep = -skipInterval;\r
8740                                     }\r
8741                                     break;\r
8742                                 default:\r
8743                                     return;\r
8744                             }\r
8745 \r
8746                             if (updateStep) {\r
8747                                 events.stopPropagation(e);\r
8748                                 events.preventDefault(e);\r
8749                                 scope.$apply(function() {\r
8750                                     setModelValue(ngModelCtrl.$viewValue + updateStep);\r
8751                                 });\r
8752                                 if (attr['onDragEnd']) {\r
8753                                 scope.onDragEnd();\r
8754                             }\r
8755                             }\r
8756                         }\r
8757 \r
8758                         elm.on('keydown', onKeyDown);\r
8759                         elm.on('mousedown', onMouseDown);\r
8760 \r
8761                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);\r
8762                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);\r
8763 \r
8764                         ngModelCtrl.$render = function() {\r
8765                             if (!scope.isDragging) {\r
8766                                 modelRenderer();\r
8767                             }\r
8768                         };\r
8769                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);\r
8770                         ngModelCtrl.$formatters.push(getValidMinMax);\r
8771                         ngModelCtrl.$formatters.push(getValidStep);\r
8772                     }\r
8773                 };\r
8774             }]);\r
8775 /**\r
8776  * @ngdoc directive\r
8777  * @name Forms.att:selectorModule\r
8778  *\r
8779  * @description\r
8780  *  <file src="src/selectorModule/docs/readme.md" />\r
8781  *\r
8782  * @usage\r
8783  * <select name="myNameBig" type="large" b2b-dropdown ng-model="Controller Variable here">\r
8784  *   <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>\r
8785  * </select>\r
8786  *\r
8787  * <select name="myNameBig" type="large" b2b-dropdown ng-model="Controller Variable here">\r
8788  * <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>\r
8789  * </select>\r
8790  *\r
8791  * <select name="myNameBig" b2b-dropdown ng-model="Controller Variable here">\r
8792  *   <optgroup b2b-dropdown-group label="Group Label here">\r
8793  *     <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>\r
8794  *   </optgroup>\r
8795  * </select>\r
8796  *\r
8797  *  @example\r
8798  *  <section id="code">\r
8799         <example module="b2b.att">\r
8800             <file src="src/selectorModule/docs/demo.html" />\r
8801             <file src="src/selectorModule/docs/demo.js" />\r
8802        </example>\r
8803     </section>\r
8804  *\r
8805  */\r
8806 angular.module('b2b.att.selectorModule', ['b2b.att.dropdowns']);\r
8807 /**\r
8808  * @ngdoc directive\r
8809  * @name Layouts.att:separators\r
8810  *\r
8811  * @description\r
8812  *  <file src="src/separators/docs/readme.md" />\r
8813  *\r
8814  * @usage\r
8815 \r
8816  *\r
8817  * @example\r
8818  *  <section id="code">   \r
8819  <b>HTML + AngularJS</b>\r
8820  <example module="b2b.att">\r
8821  <file src="src/separators/docs/demo.html" />\r
8822  <file src="src/separators/docs/demo.js" />\r
8823  </example>\r
8824  </section>\r
8825  *\r
8826  */\r
8827 \r
8828 angular.module('b2b.att.separators', []);\r
8829 /**\r
8830  * @ngdoc directive\r
8831  * @name Buttons, links & UI controls.att:slider\r
8832  *\r
8833  * @description\r
8834  *  <file src="src/slider/docs/readme.md" />\r
8835  *\r
8836  * @usage\r
8837  *  <b2b-slider min="0" max="400" step="1" no-aria-label skip-interval="1" ng-model="horizontalSliderVal" style="width:180px; margin: auto;" on-drag-end="onDragEnd()" on-drag-init="onDragStart()" label-id="slider-label" post-aria-label="postAriaLabel"></b2b-slider>\r
8838  *\r
8839  * @example\r
8840     <section id="code">   \r
8841         <b>HTML + AngularJS</b>\r
8842         <example module="b2b.att">\r
8843             <file src="src/slider/docs/demo.html" />\r
8844             <file src="src/slider/docs/demo.js" />\r
8845         </example>\r
8846     </section>\r
8847  */\r
8848 \r
8849 angular.module('b2b.att.slider', ['b2b.att.utilities'])\r
8850         .constant('SliderConfig', {\r
8851             'min': 0,\r
8852             'max': 100,\r
8853             'step': 1,\r
8854             'skipInterval': 1\r
8855         })\r
8856         .directive('b2bSlider', ['$documentBind', 'SliderConfig', 'keymap', '$compile', '$log', function($documentBind, SliderConfig, keymap, $compile, $log) {\r
8857                 return {\r
8858                     restrict: 'AE',\r
8859                     replace: true,\r
8860                     require: 'ngModel',\r
8861                     templateUrl: 'b2bTemplate/slider/slider.html',\r
8862                     scope: {\r
8863                         onDragEnd: '&?',\r
8864                         onDragInit: '&?',\r
8865                         trackFillColor: '=?',\r
8866                         preAriaLabel: '=?',\r
8867                         postAriaLabel: '=?',\r
8868                         onRenderEnd: '&?',\r
8869                         sliderSnapPoints: '=?',\r
8870                         customAriaLabel: '=?',\r
8871                         labelId: '@?'\r
8872                     },\r
8873                     link: function(scope, elm, attr, ngModelCtrl) {\r
8874                         scope.isDragging = false;\r
8875                         scope.verticalSlider = false;\r
8876                         var min;\r
8877                         var max;\r
8878                         var step = SliderConfig.step;\r
8879                         var skipInterval = SliderConfig.skipInterval;\r
8880                         var knob = angular.element(elm[0].querySelector('.slider-knob-container'));\r
8881                         var sliderKnob = angular.element(knob[0].querySelector('.slider-knob'));\r
8882                         var trackContainer = angular.element(elm[0].querySelector('.slider-track-container'));\r
8883                         var trackFill = angular.element(elm[0].querySelector('.slider-track-fill'));\r
8884                         var trackContainerRect = {};\r
8885                         var axisPosition = "clientX";\r
8886                         var trackFillOrderPositioning;\r
8887 \r
8888                         //Forcefully disabling the vertical Slider code.\r
8889                         if (angular.isDefined(attr.vertical)) {\r
8890                             scope.verticalSlider = true;\r
8891                             axisPosition = "clientY";\r
8892                         }\r
8893 \r
8894                         if (angular.isDefined(scope.noAriaLabel) && scope.noAriaLabel !== '') {\r
8895                             $log.warn('no-aria-label has been deprecated. This will be removed in v0.6.0.');\r
8896                         }\r
8897                         if (angular.isDefined(scope.preAriaLabel) && scope.preAriaLabel !== '') {\r
8898                             $log.warn('pre-aria-label has been deprecated. Please use label-id instead. This will be removed in v0.6.0.');\r
8899                         }\r
8900                         if (angular.isDefined(scope.customAriaLabel) && scope.customAriaLabel !== '') {\r
8901                             $log.warn('custom-aria-label has been deprecated. Please use label-id and post-aria-label instead. This will be removed in v0.6.0.');\r
8902                         }\r
8903 \r
8904                         var binarySearchNearest = function (num, arr) {\r
8905                             var mid;\r
8906                             var lo = 0;\r
8907                             var hi = arr.length - 1;\r
8908                             \r
8909                             while (hi - lo > 1) {\r
8910                                 mid = Math.floor((lo + hi) / 2);\r
8911                                 if (arr[mid] < num) {\r
8912                                     lo = mid;\r
8913                                 } else {\r
8914                                     hi = mid;\r
8915                                 }\r
8916                             }\r
8917                             if (num - arr[lo] < arr[hi] - num) {\r
8918                                 return arr[lo];\r
8919                             }\r
8920                             return arr[hi];\r
8921                         };\r
8922                         \r
8923                         var getValidStep = function(val) {\r
8924                             val = parseFloat(val);\r
8925                             // in case $modelValue came in string number\r
8926                             if (!isNaN(val)) {\r
8927                                 \r
8928                                 if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
8929                                     val = binarySearchNearest(val, scope.sliderSnapPoints);\r
8930                                 }\r
8931                                 else {\r
8932                                     val = Math.round((val - min) / step) * step + min;\r
8933                                 }\r
8934                                 \r
8935                                 return Math.round(val * 1000) / 1000;\r
8936                             }\r
8937                         };\r
8938 \r
8939                         var getPositionToPercent = function(x) {\r
8940                             if (scope.verticalSlider) {\r
8941                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));\r
8942                             }\r
8943                             else {\r
8944                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));\r
8945                             }\r
8946                         };\r
8947 \r
8948                         var getPercentToValue = function(percent) {\r
8949                             return (min + percent * (max - min));\r
8950                         };\r
8951 \r
8952                         var getValueToPercent = function(val) {\r
8953                             return (val - min) / (max - min);\r
8954                         };\r
8955 \r
8956                         var getValidMinMax = function(val) {\r
8957                             return Math.max(min, Math.min(max, val));\r
8958                         };\r
8959 \r
8960                         var updateTrackContainerRect = function() {\r
8961                             trackContainerRect = trackContainer[0].getBoundingClientRect();\r
8962                             if (scope.verticalSlider) {\r
8963                                 if (!trackContainerRect.height) {\r
8964                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;\r
8965                                 } else {\r
8966                                     trackFillOrderPositioning = trackContainerRect.height;\r
8967                                 }\r
8968                             }\r
8969                             else {\r
8970                                 if (!trackContainerRect.width) {\r
8971                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;\r
8972                                 } else {\r
8973                                     trackFillOrderPositioning = trackContainerRect.width;\r
8974                                 }\r
8975 \r
8976                             }\r
8977 \r
8978                         };\r
8979 \r
8980                         var updateKnobPosition = function(percent) {\r
8981                             var percentStr = (percent * 100) + '%';\r
8982                             if (scope.verticalSlider) {\r
8983                                 knob.css('bottom', percentStr);\r
8984                                 trackFill.css('height', percentStr);\r
8985                             }\r
8986                             else {\r
8987                                 knob.css('left', percentStr);\r
8988                                 trackFill.css('width', percentStr);\r
8989                             }\r
8990                         };\r
8991 \r
8992                         var modelRenderer = function() {\r
8993 \r
8994                             if(attr['disabled']){\r
8995                                 return;\r
8996                             }\r
8997 \r
8998                             if (isNaN(ngModelCtrl.$viewValue)) {\r
8999                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;\r
9000                             }\r
9001 \r
9002                             var viewVal = ngModelCtrl.$viewValue;\r
9003                             scope.currentModelValue = viewVal;\r
9004 \r
9005                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation\r
9006                             if ((min || min === 0) && max && step) {\r
9007                                 updateKnobPosition(getValueToPercent(viewVal));\r
9008                             }\r
9009                         };\r
9010 \r
9011                         var setModelValue = function(val) {\r
9012                             scope.currentModelValue = getValidMinMax(getValidStep(val));\r
9013                             ngModelCtrl.$setViewValue(scope.currentModelValue);\r
9014                         };\r
9015 \r
9016                         var updateMin = function(val) {\r
9017                             min = parseFloat(val);\r
9018                             if(isNaN(min)){\r
9019                                min = SliderConfig.min; \r
9020                             }\r
9021                             scope.min = min;\r
9022                             modelRenderer();\r
9023                         };\r
9024 \r
9025                         var updateMax = function(val) {\r
9026                             max = parseFloat(val);\r
9027                             if(isNaN(max)){\r
9028                                max = SliderConfig.max; \r
9029                             }\r
9030                             scope.max = max;\r
9031                             modelRenderer();\r
9032                         };\r
9033 \r
9034                         var updateStep = function(val) {\r
9035                             step = parseFloat(val);\r
9036                             if (!attr['skipInterval']) {\r
9037                                 skipInterval = step;\r
9038                             }\r
9039                         };\r
9040 \r
9041                         var updateSkipInterval = function(val) {\r
9042                             skipInterval = step * Math.ceil(val / (step!==0?step:1));\r
9043                         };\r
9044 \r
9045                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(SliderConfig.min);\r
9046                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(SliderConfig.max);\r
9047                         if (angular.isDefined(attr.step)) {\r
9048                             attr.$observe('step', updateStep);\r
9049                         }\r
9050                         if (angular.isDefined(attr.skipInterval)) {\r
9051                             attr.$observe('skipInterval', updateSkipInterval);\r
9052                         }\r
9053                         scope.currentModelValue = getValidMinMax(getValidStep(min));\r
9054                         var onMouseDown = function(e) {\r
9055 \r
9056                             if(attr['disabled']){\r
9057                                 return;\r
9058                             }\r
9059 \r
9060                             switch (e.which) {\r
9061                                 case 1:\r
9062                                     // left mouse button\r
9063                                     break;\r
9064                                 case 2:\r
9065                                 case 3:\r
9066                                     // right or middle mouse button\r
9067                                     return;\r
9068                             }\r
9069 \r
9070                             scope.isDragging = true;\r
9071                             sliderKnob[0].focus();\r
9072                             updateTrackContainerRect();\r
9073                             if (attr['onDragInit']) {\r
9074                                 scope.onDragInit();\r
9075                             }\r
9076                             e.stopPropagation();\r
9077                             e.preventDefault();\r
9078                              scope.$apply(function() {\r
9079                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
9080                             });\r
9081                         };\r
9082 \r
9083                         var onMouseUp = function() {\r
9084 \r
9085                             if (attr['onDragEnd']) {\r
9086                                 scope.onDragEnd();\r
9087                             }\r
9088                             scope.isDragging = false;\r
9089                             scope.$digest();\r
9090                         };\r
9091 \r
9092                         var onMouseMove = function(e) {\r
9093                             if (scope.isDragging) {\r
9094                                 e.stopPropagation();\r
9095                                 e.preventDefault();\r
9096 \r
9097                                 scope.$apply(function() {\r
9098                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
9099                                 });\r
9100                             }\r
9101                         };\r
9102 \r
9103                         function onKeyDown(e) {\r
9104                             if (!(e.keyCode)) {\r
9105                                 e.keyCode = e.which;\r
9106                             }\r
9107                             var updateStep;\r
9108                             switch (e.keyCode) {\r
9109                                 case keymap.KEY.DOWN:\r
9110                                 case keymap.KEY.LEFT:\r
9111                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9112                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);\r
9113                                         if (currentIndex > 0) {\r
9114                                             currentIndex--;\r
9115                                         }\r
9116                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9117                                     }\r
9118                                     else {\r
9119                                         updateStep = ngModelCtrl.$viewValue - skipInterval;\r
9120                                     }\r
9121                                     break;\r
9122                                 case keymap.KEY.UP:\r
9123                                 case keymap.KEY.RIGHT:\r
9124                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9125                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);\r
9126                                         if (currentIndex < scope.sliderSnapPoints.length-1) {\r
9127                                             currentIndex++;\r
9128                                         }\r
9129                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9130                                     }\r
9131                                     else {\r
9132                                         updateStep = ngModelCtrl.$viewValue + skipInterval;\r
9133                                     }\r
9134                                     break;\r
9135                                 case keymap.KEY.END:\r
9136                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9137                                         currentIndex = scope.sliderSnapPoints.length-1;\r
9138                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9139                                     } else {\r
9140                                         setModelValue(scope.max);\r
9141                                     }\r
9142                                     e.preventDefault();\r
9143                                     e.stopPropagation();\r
9144                                     break;\r
9145                                 case keymap.KEY.HOME:\r
9146                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9147                                         currentIndex = 0;\r
9148                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9149                                     } else {\r
9150                                         setModelValue(scope.min);\r
9151                                     }\r
9152                                     e.preventDefault();\r
9153                                     e.stopPropagation();\r
9154                                     break;\r
9155                                 default:\r
9156                                     return;\r
9157                             }\r
9158 \r
9159                             if (angular.isNumber(updateStep) && !attr['disabled']) {\r
9160                                 e.stopPropagation();\r
9161                                 e.preventDefault();\r
9162                                 scope.$apply(function() {\r
9163                                     setModelValue(updateStep);\r
9164                                 });\r
9165                                 if (attr['onDragEnd']) {\r
9166                                     scope.onDragEnd();\r
9167                                 }\r
9168                             }\r
9169                         }\r
9170 \r
9171                         elm.on('keydown', onKeyDown);\r
9172                         elm.on('mousedown', onMouseDown);\r
9173 \r
9174                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);\r
9175                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);\r
9176 \r
9177                         attr.$observe('disabled', function (disabled) {\r
9178                             if (disabled) {\r
9179                                 sliderKnob.removeAttr('tabindex');\r
9180                             } else {\r
9181                                 sliderKnob.attr('tabindex', '0');\r
9182                                 disabled = false;\r
9183                             }\r
9184 \r
9185                             elm.toggleClass("slider-disabled", disabled);\r
9186 \r
9187                             if (angular.isDefined(attr.hideDisabledKnob)) {\r
9188                                 scope.hideKnob = disabled;\r
9189                             }\r
9190                         });\r
9191 \r
9192                         ngModelCtrl.$render = function() {\r
9193                             if (!scope.isDragging) {\r
9194                                 modelRenderer();\r
9195                                 if (attr['onRenderEnd'] && !attr['disabled']) {\r
9196                                     scope.onRenderEnd({currentModelValue: scope.currentModelValue});\r
9197                                 }\r
9198                             }\r
9199                         };\r
9200                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);\r
9201                         ngModelCtrl.$formatters.push(getValidMinMax);\r
9202                         ngModelCtrl.$formatters.push(getValidStep);\r
9203                     }\r
9204                 };\r
9205             }]);\r
9206 /**\r
9207  * @ngdoc directive\r
9208  * @name Forms.att:spinButton\r
9209  *\r
9210  * @param {String} spin-button-id - An ID for the input field\r
9211  * @param {Integer} min - Minimum value for the input\r
9212  * @param {Integer} max - Maximum value for the input\r
9213  * @param {Integer} step - Value by which input field increments or decrements on up/down arrow keys\r
9214  * @param {Integer} page-step - Value by which input field increments or decrements on page up/down keys\r
9215  * @param {boolean} input-model-key - Default value for input field\r
9216  * @param {boolean} disabled-flag - A boolean that triggers directive once the min or max value has reached\r
9217  *\r
9218  * @description\r
9219  *  <file src="src/spinButton/docs/readme.md" />\r
9220  *\r
9221  * @example\r
9222  *  <section id="code">\r
9223         <example module="b2b.att">\r
9224             <file src="src/spinButton/docs/demo.html" />\r
9225             <file src="src/spinButton/docs/demo.js" />\r
9226        </example>\r
9227     </section>\r
9228  * \r
9229  */\r
9230 angular.module('b2b.att.spinButton', ['b2b.att.utilities'])\r
9231     .constant('b2bSpinButtonConfig', {\r
9232         min: 1,\r
9233         max: 10,\r
9234         step: 1,\r
9235         pageStep: 10,\r
9236         inputModelKey: 'value',\r
9237         disabledFlag: false\r
9238     })\r
9239     .directive('b2bSpinButton', ['keymap', 'b2bSpinButtonConfig', 'b2bUserAgent', function (keymap, b2bSpinButtonConfig, userAgent) {\r
9240         return {\r
9241             restrict: 'EA',\r
9242             require: '?ngModel',\r
9243             transclude: false,\r
9244             replace: true,\r
9245             scope: {\r
9246                 min: '=min',\r
9247                 max: '=max',\r
9248                 step: '=step',\r
9249                 pageStep: '=pageStep',\r
9250                 spinButtonId: '@',\r
9251                 inputValue: '=ngModel',\r
9252                 inputModelKey: '@',\r
9253                 disabledFlag: "=?"\r
9254             },\r
9255             templateUrl: 'b2bTemplate/spinButton/spinButton.html',\r
9256             controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {\r
9257 \r
9258                 scope.isMobile = userAgent.isMobile();\r
9259                 scope.notMobile = userAgent.notMobile();\r
9260 \r
9261                 scope.min = attrs.min ? scope.min : b2bSpinButtonConfig.min;\r
9262                 scope.max = attrs.max ? scope.max : b2bSpinButtonConfig.max;\r
9263                 scope.step = attrs.step ? scope.step : b2bSpinButtonConfig.step;\r
9264                 scope.pageStep = attrs.pageStep ? scope.pageStep : b2bSpinButtonConfig.pageStep;\r
9265                 scope.inputModelKey = attrs.inputModelKey ? scope.inputModelKey : b2bSpinButtonConfig.inputModelKey;\r
9266                 scope.disabledFlag = attrs.disabledFlag ? scope.disabledFlag : b2bSpinButtonConfig.disabledFlag;\r
9267                 \r
9268                 if (scope.min < 0) {\r
9269                     scope.min = 0;\r
9270                 }\r
9271                 if (scope.max > 999) {\r
9272                     scope.max = 999;\r
9273                 }\r
9274 \r
9275                 scope.isPlusDisabled = function () {\r
9276                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] >= scope.max);\r
9277                 };\r
9278                 scope.isMinusDisabled = function () {\r
9279                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] <= scope.min);\r
9280                 };\r
9281 \r
9282                 scope.getValidateInputValue = function (value) {\r
9283                     if (value <= scope.min) {\r
9284                         return scope.min;\r
9285                     } else if (value >= scope.max) {\r
9286                         return scope.max;\r
9287                     } else {\r
9288                         return value;\r
9289                     }\r
9290                 };\r
9291 \r
9292                 scope.plus = function () {\r
9293                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.step);\r
9294                 };\r
9295                 scope.minus = function () {\r
9296                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.step);\r
9297                 };\r
9298                 scope.pagePlus = function () {\r
9299                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.pageStep);\r
9300                 };\r
9301                 scope.pageMinus = function () {\r
9302                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.pageStep);\r
9303                 };\r
9304 \r
9305             }],\r
9306             link: function (scope, elem) {\r
9307 \r
9308                 if (scope.notMobile) {\r
9309                     angular.element(elem).find('input').attr('aria-live', 'off');\r
9310                     angular.element(elem).find('input').attr('role', 'spinbutton');\r
9311                 }\r
9312 \r
9313                 elem.find('input').bind('keydown', function (e) {\r
9314                     if (e.keyCode === keymap.KEY.UP) {\r
9315                         scope.plus();\r
9316                     } else if (e.keyCode === keymap.KEY.DOWN){\r
9317                         scope.minus();\r
9318                     } else if (e.keyCode === keymap.KEY.HOME) {\r
9319                         scope.inputValue[scope.inputModelKey] = parseInt(scope.min);\r
9320                     } else if (e.keyCode === keymap.KEY.END) {\r
9321                         scope.inputValue[scope.inputModelKey] = parseInt(scope.max);\r
9322                     } else if (e.keyCode === keymap.KEY.PAGE_UP) {\r
9323                         scope.pagePlus();\r
9324                     } else if (e.keyCode === keymap.KEY.PAGE_DOWN) {\r
9325                         scope.pageMinus();\r
9326                     }\r
9327                     scope.$apply();\r
9328                 });\r
9329 \r
9330                 elem.find('input').bind('keyup', function () {\r
9331                     if (scope.inputValue[scope.inputModelKey] === null ||\r
9332                         scope.inputValue[scope.inputModelKey] === '' ||\r
9333                         scope.inputValue[scope.inputModelKey] < scope.min) {\r
9334                         scope.inputValue[scope.inputModelKey] = scope.min;\r
9335                         scope.$apply();\r
9336                     } else if (angular.isUndefined(scope.inputValue[scope.inputModelKey]) || \r
9337                                scope.inputValue[scope.inputModelKey] > scope.max) {\r
9338                         scope.inputValue[scope.inputModelKey] = scope.max;\r
9339                         scope.$apply();\r
9340                     }\r
9341                 });\r
9342 \r
9343                 scope.focusInputSpinButton = function (evt) {\r
9344                     evt.preventDefault();\r
9345                     if (scope.notMobile) {\r
9346                         elem[0].querySelector('input').focus();\r
9347                     }\r
9348                 };\r
9349 \r
9350             }\r
9351         };  \r
9352     }]);\r
9353 /** \r
9354  * @ngdoc directive \r
9355  * @name Template.att:Static Route\r
9356  * \r
9357  * @description \r
9358  *  <file src="src/staticRouteTemplate/docs/readme.md" /> \r
9359  * \r
9360  * @example \r
9361  *  <section id="code"> \r
9362         <example module="b2b.att"> \r
9363             <file src="src/staticRouteTemplate/docs/demo.html" /> \r
9364             <file src="src/staticRouteTemplate/docs/demo.js" /> \r
9365        </example> \r
9366     </section>    \r
9367  * \r
9368  */\r
9369 angular.module('b2b.att.staticRouteTemplate', ['b2b.att.utilities'])\r
9370   \r
9371 /**\r
9372  * @ngdoc directive\r
9373  * @name Progress & usage indicators.att:statusTracker\r
9374  *\r
9375  * @scope\r
9376  * @param {array} statuses - An array of status objects\r
9377  * @description\r
9378  * <file src="src/statusTracker/docs/readme.md" />\r
9379  *\r
9380  * @usage\r
9381  *\r
9382 <div ng-controller="statusTrackerController">\r
9383     <b2b-status-tracker statuses="statusObject"></b2b-status-tracker>\r
9384 </div>\r
9385 \r
9386  * @example\r
9387     <section id="code">   \r
9388         <b>HTML + AngularJS</b>\r
9389         <example module="b2b.att">\r
9390             <file src="src/statusTracker/docs/demo.html" />\r
9391             <file src="src/statusTracker/docs/demo.js" />\r
9392         </example>\r
9393     </section>\r
9394  */\r
9395 \r
9396 angular.module('b2b.att.statusTracker', ['b2b.att.utilities'])\r
9397 .constant('b2bStatusTrackerConfig', {\r
9398     'maxViewItems': 3\r
9399 })\r
9400 .directive('b2bStatusTracker', ['b2bStatusTrackerConfig', function(b2bStatusTrackerConfig) {\r
9401         return {\r
9402             restrict: 'EA',\r
9403             transclude: false,\r
9404             replace: true,\r
9405             scope:{\r
9406                 statuses: '='\r
9407             },\r
9408             templateUrl: function(scope) {\r
9409                 return 'b2bTemplate/statusTracker/statusTracker.html';\r
9410             },\r
9411             link: function(scope, element, attr) {\r
9412                 scope.currentViewIndex = 0;\r
9413                 scope.b2bStatusTrackerConfig = b2bStatusTrackerConfig;\r
9414 \r
9415                 scope.nextStatus = function() {\r
9416                     if (scope.currentViewIndex+1 <= scope.statuses.length) {\r
9417                         scope.currentViewIndex++;\r
9418                     }\r
9419                 };\r
9420                 scope.previousStatus = function() {\r
9421                     if (scope.currentViewIndex-1 >= 0) {\r
9422                         scope.currentViewIndex--;\r
9423                     }\r
9424                 };\r
9425                 scope.isInViewport = function(index) {\r
9426                     return (index < scope.currentViewIndex+3 && index >= scope.currentViewIndex);  // && index > scope.currentViewIndex-2\r
9427                 };\r
9428                 scope.currentStatus = function(index) {\r
9429                     if(index != undefined){\r
9430                         if(!scope.statuses[index].complete) {\r
9431                             if(index > 0 && scope.statuses[index-1].complete) {\r
9432                                 return true;\r
9433                             } else if(index == 0 && !scope.statuses[index].complete){\r
9434                                 return true;\r
9435                             } else {\r
9436                                 return false;\r
9437                             }\r
9438                         }\r
9439                     }\r
9440                 };\r
9441             }\r
9442         };\r
9443     }]);\r
9444 /**\r
9445  * @ngdoc directive\r
9446  * @name Progress & usage indicators.att:stepTracker\r
9447  *\r
9448  * @scope\r
9449  * @param {array} stepsItemsObject - An array of step objects\r
9450  * @param {Integer} currenIindex - This indicates the current running step\r
9451  * @param {Integer} viewportIndex - This is optional. This can used to start the view port rather than 1 item.\r
9452  * @description\r
9453  * <file src="src/stepTracker/docs/readme.md" />\r
9454  *\r
9455  * @usage\r
9456  *\r
9457  *  <b2b-step-tracker steps-items-object="stepsObject" current-index="currentStepIndex" step-indicator-heading="stepHeading"></b2b-step-tracker>\r
9458  *\r
9459 \r
9460  * @example\r
9461     <section id="code">   \r
9462         <b>HTML + AngularJS</b>\r
9463         <example module="b2b.att">\r
9464             <file src="src/stepTracker/docs/demo.html" />\r
9465             <file src="src/stepTracker/docs/demo.js" />\r
9466         </example>\r
9467     </section>\r
9468  */\r
9469 angular.module('b2b.att.stepTracker', ['b2b.att.utilities'])\r
9470     .constant('b2bStepTrackerConfig', {\r
9471         'maxViewItems': 5\r
9472     })\r
9473     .directive('b2bStepTracker', ['b2bStepTrackerConfig', function(b2bStepTrackerConfig) {\r
9474         return {\r
9475             restrict: 'EA',\r
9476             transclude: true,\r
9477             scope:{\r
9478                 stepsItemsObject:"=",\r
9479                 currentIndex:"=",\r
9480                 viewportIndex:"=?"\r
9481             },\r
9482             templateUrl: 'b2bTemplate/stepTracker/stepTracker.html',\r
9483             link: function(scope, ele, attr) {\r
9484                 if (angular.isDefined(scope.viewportIndex)) {\r
9485                     scope.currentViewIndex = scope.viewportIndex - 1;   \r
9486                 }else{\r
9487                     scope.currentViewIndex = 0;\r
9488                 }\r
9489                \r
9490                scope.b2bStepTrackerConfig = b2bStepTrackerConfig;\r
9491                scope.nextStatus = function() {\r
9492                     if (scope.currentViewIndex+1 <= scope.stepsItemsObject.length) {\r
9493                         scope.currentViewIndex++;\r
9494                     }\r
9495                 };\r
9496                 scope.previousStatus = function() {\r
9497                     if (scope.currentViewIndex-1 >= 0) {\r
9498                         scope.currentViewIndex--;\r
9499                     }\r
9500                 };\r
9501                 scope.isInViewport = function(index) {\r
9502                     return (index < scope.currentViewIndex+b2bStepTrackerConfig.maxViewItems && index >= scope.currentViewIndex);\r
9503                 };\r
9504             }\r
9505         };\r
9506     }]);\r
9507      \r
9508 /**\r
9509  * @ngdoc directive\r
9510  * @name Buttons, links & UI controls.att:switches\r
9511  *\r
9512  * @description\r
9513  *  <file src="src/switches/docs/readme.md" />\r
9514  *\r
9515  * @usage\r
9516  *  \r
9517  *  <!-- On / Off Toggle switch -->\r
9518  *  <label for="switch1" class="controlled-text-wrap"> This is ON\r
9519  *      <input type="checkbox" role="checkbox" b2b-switches id="switch1" ng-model="switch1.value">\r
9520  *  </label>\r
9521  *\r
9522  *  <!-- On / Off Toggle switch and DISABLED -->\r
9523  *  <label for="switch2" class="controlled-text-wrap"> This is ON (disabled)\r
9524  *      <input type="checkbox" role="checkbox" b2b-switches id="switch2" ng-model="switch1.value" ng-disabled="true" >\r
9525  *  </label> \r
9526  *\r
9527  *\r
9528  * @example\r
9529  *  <section id="code">\r
9530         <b>HTML + AngularJS</b>\r
9531         <example module="b2b.att">\r
9532             <file src="src/switches/docs/demo.js" />\r
9533             <file src="src/switches/docs/demo.html" />\r
9534         </example>\r
9535     </section>\r
9536  */\r
9537 angular.module('b2b.att.switches', ['b2b.att.utilities'])\r
9538     .directive('b2bSwitches', ['$compile', '$templateCache', 'keymap', 'events', function ($compile, $templateCache, keymap, events) {\r
9539         return {\r
9540             restrict: 'EA',\r
9541             require: ['ngModel'],\r
9542             link: function (scope, element, attrs, ctrl) {\r
9543                 var ngModelController = ctrl[0];\r
9544         \r
9545                 element.parent().bind("keydown", function (e) {\r
9546                     if (!attrs.disabled && (e.keyCode === keymap.KEY.ENTER || e.keyCode === keymap.KEY.SPACE)) {\r
9547                         events.preventDefault(e);\r
9548                         ngModelController.$setViewValue(!ngModelController.$viewValue);\r
9549                         element.prop("checked", ngModelController.$viewValue);\r
9550                     }\r
9551                 });\r
9552 \r
9553                 element.wrap('<div class="btn-switch">');\r
9554                 //element.attr("tabindex", -1);\r
9555                 if (navigator.userAgent.match(/iphone/i)){\r
9556                     element.attr("aria-live", "polite");\r
9557                 }\r
9558                 else {\r
9559                     element.removeAttr('aria-live');\r
9560                 }\r
9561 \r
9562                 var templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches.html"));\r
9563                 if (angular.isDefined(attrs.typeSpanish)) {\r
9564                     templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches-spanish.html"));\r
9565                 }\r
9566 \r
9567                 templateSwitch = $compile(templateSwitch)(scope);\r
9568                 element.parent().append(templateSwitch);\r
9569 \r
9570                 element.bind("focus", function (e) {\r
9571                     element.parent().addClass('focused');\r
9572                 });\r
9573 \r
9574                 element.bind("blur", function (e) {\r
9575                     element.parent().removeClass('focused');\r
9576                 });\r
9577             }\r
9578         };\r
9579     }]);\r
9580 /**\r
9581  * @ngdoc directive\r
9582  * @name Messages, modals & alerts.att:tableMessages\r
9583  *\r
9584  * @description\r
9585  *  <file src="src/tableMessages/docs/readme.md" />\r
9586  *\r
9587  * @usage\r
9588     <!-- no matching results -->\r
9589     <b2b-table-message msg-type="'noMatchingResults'">\r
9590        <p>No Matching Results</p>\r
9591     </b2b-table-message>\r
9592   \r
9593     <!-- info could not load -->\r
9594     <b2b-table-message msg-type="'infoCouldNotLoad'" on-refresh-click="refreshClicked()">\r
9595     </b2b-table-message>\r
9596    \r
9597     <!-- magnify search -->\r
9598     <b2b-table-message msg-type="'magnifySearch'">\r
9599     </b2b-table-message>\r
9600    \r
9601     <!-- loading data -->\r
9602     <b2b-table-message msg-type="'loadingTable'">\r
9603           <!-- custom html -->\r
9604           <p>The data is currently loading...</p>\r
9605     </b2b-table-message>\r
9606 \r
9607  * @example\r
9608     <section id="code">   \r
9609         <b>HTML + AngularJS</b>\r
9610         <example module="b2b.att">\r
9611             <file src="src/tableMessages/docs/demo.html" />\r
9612             <file src="src/tableMessages/docs/demo.js" />\r
9613         </example>\r
9614     </section>\r
9615  */\r
9616 angular.module('b2b.att.tableMessages', [])\r
9617     .directive('b2bTableMessage', [function() {\r
9618         return {\r
9619             restrict: 'AE',\r
9620             replace: true,\r
9621             transclude: true,\r
9622             scope: {\r
9623                 msgType: '=',\r
9624                 onRefreshClick: '&'\r
9625             },\r
9626             templateUrl: 'b2bTemplate/tableMessages/tableMessage.html',\r
9627             link: function(scope) {\r
9628                 scope.refreshAction = function(evt) {\r
9629                     scope.onRefreshClick(evt);\r
9630                 };\r
9631             }\r
9632         };\r
9633     }]);\r
9634 \r
9635 /**\r
9636  * @ngdoc directive\r
9637  * @name Tabs, tables & accordions.att:tableScrollbar\r
9638  *\r
9639  * @description\r
9640  *  <file src="src/tableScrollbar/docs/readme.md" />\r
9641  *\r
9642  * @usage\r
9643  * \r
9644 <b2b-table-scrollbar>\r
9645     <table>\r
9646         <thead type="header">\r
9647             <tr>\r
9648                 <th role="columnheader" scope="col" key="Id" id="col1">Id</th>\r
9649                 .....\r
9650             </tr>\r
9651         </thead>\r
9652         <tbody type="body">\r
9653             <tr>\r
9654                 <td id="rowheader0" headers="col1">1002</td>\r
9655                 .....\r
9656             </tr>\r
9657         </tbody>\r
9658     </table>\r
9659 </b2b-table-scrollbar>\r
9660  *\r
9661  * @example\r
9662  *  <section id="code">\r
9663         <example module="b2b.att">\r
9664             <file src="src/tableScrollbar/docs/demo.html" />\r
9665             <file src="src/tableScrollbar/docs/demo.js" />\r
9666        </example>\r
9667     </section>\r
9668  *\r
9669  */\r
9670 angular.module('b2b.att.tableScrollbar', [])\r
9671     .directive('b2bTableScrollbar', ['$timeout', function ($timeout) {\r
9672         return {\r
9673             restrict: 'E',\r
9674             scope: true,\r
9675             transclude: true,\r
9676             templateUrl: 'b2bTemplate/tableScrollbar/tableScrollbar.html',\r
9677             link: function (scope, element, attrs, ctrl) {\r
9678                 var firstThWidth, firstTdWidth, firstColumnWidth, firstColumnHeight, trHeight = 0;\r
9679                 var pxToScroll = '';\r
9680                 var tableElement = element.find('table');\r
9681                 var thElements = element.find('th');\r
9682                 var tdElements = element.find('td');\r
9683                 var innerContainer = angular.element(element[0].querySelector('.b2b-table-inner-container'));\r
9684                 var outerContainer = angular.element(element[0].querySelector('.b2b-table-scrollbar'));\r
9685 \r
9686                 scope.disableLeft = true;\r
9687                 scope.disableRight = false;\r
9688 \r
9689                 if (angular.isDefined(thElements[0])) {\r
9690                     firstThWidth = thElements[0].offsetWidth;\r
9691                 }\r
9692                 if (angular.isDefined(tdElements[0])) {\r
9693                     firstTdWidth = tdElements[0].offsetWidth;\r
9694                 }\r
9695                 firstColumnWidth = (firstThWidth > firstTdWidth) ? firstThWidth : firstTdWidth;\r
9696 \r
9697                 innerContainer.css({\r
9698                     'padding-left': (firstColumnWidth + 2) + 'px'\r
9699                 });\r
9700 \r
9701                 angular.forEach(element.find('tr'), function (eachTr, index) {\r
9702                     trObject = angular.element(eachTr);\r
9703                     firstColumn = angular.element(trObject.children()[0]);\r
9704 \r
9705                     angular.element(firstColumn).css({\r
9706                         'margin-left': -(firstColumnWidth + 2) + 'px',\r
9707                         'width': (firstColumnWidth + 2) + 'px',\r
9708                         'position': 'absolute'\r
9709                     });\r
9710 \r
9711                     trHeight = trObject[0].offsetHeight;\r
9712                     firstColumnHeight = firstColumn[0].offsetHeight;\r
9713                     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {\r
9714                         firstColumnHeight += 1;\r
9715                     }\r
9716 \r
9717                     if (trHeight !== firstColumnHeight - 1) {\r
9718                         if (trHeight > firstColumnHeight) {\r
9719                             if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {\r
9720                                 trHeight -= 1;\r
9721                             }\r
9722                             angular.element(firstColumn).css({\r
9723                                 'height': (trHeight + 1) + 'px'\r
9724                             });\r
9725                         } else {\r
9726                             angular.element(trObject).css({\r
9727                                 'height': (firstColumnHeight - 1) + 'px'\r
9728                             });\r
9729                         }\r
9730                     }\r
9731 \r
9732                 });\r
9733 \r
9734                 pxToScroll = outerContainer[0].offsetWidth - firstColumnWidth;\r
9735 \r
9736                 scope.scrollLeft = function () {\r
9737                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + 20 - pxToScroll;\r
9738                 };\r
9739 \r
9740                 scope.scrollRight = function () {\r
9741                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + pxToScroll - 20;\r
9742                 };\r
9743 \r
9744                 scope.checkScrollArrows = function () {\r
9745                     if (innerContainer[0].scrollLeft == 0) {\r
9746                         scope.disableLeft = true;\r
9747                     } else {\r
9748                         scope.disableLeft = false;\r
9749                     }\r
9750 \r
9751                     if (((innerContainer[0].offsetWidth - firstColumnWidth) + innerContainer[0].scrollLeft) >= tableElement[0].offsetWidth) {\r
9752                         scope.disableRight = true;\r
9753                     } else {\r
9754                         scope.disableRight = false;\r
9755                     }\r
9756                 };\r
9757 \r
9758                 innerContainer.bind('scroll', function () {\r
9759                     $timeout(function () {\r
9760                         scope.checkScrollArrows();\r
9761                     }, 1);\r
9762                 });\r
9763 \r
9764             }\r
9765         };\r
9766     }]);\r
9767 /**\r
9768  * @ngdoc directive\r
9769  * @name Tabs, tables & accordions.att:tables\r
9770  *\r
9771  * @description\r
9772  *  <file src="src/tables/docs/readme.md" />\r
9773  *\r
9774  * @usage\r
9775  *   \r
9776  Table\r
9777  <table b2b-table table-data="tableData" search-string="searchString">\r
9778     <thead b2b-table-row type="header">\r
9779         <tr>\r
9780             <th b2b-table-header key="requestId" default-sort="a" id="col1">Header 1</th>\r
9781             <th b2b-table-header key="requestType" sortable="false" id="col2">Header 2</th>\r
9782         </tr>\r
9783     </thead>\r
9784     <tbody b2b-table-row type="body" row-repeat="rowData in tableData">\r
9785         <tr>\r
9786             <td b2b-table-body id="rowheader{{$index}}" headers="col1" ng-bind="rowData['requestId']"> </td>\r
9787             <td b2b-table-body ng-bind="rowData['requestType']"></td>\r
9788         </tr>\r
9789     </tbody>\r
9790  </table>\r
9791  *\r
9792  * @example\r
9793  *  <section id="code">\r
9794         <example module="b2b.att">\r
9795             <file src="src/tables/docs/demo.html" />\r
9796             <file src="src/tables/docs/demo.js" />\r
9797        </example>\r
9798     </section>\r
9799  *\r
9800  */\r
9801 angular.module('b2b.att.tables', ['b2b.att.utilities'])\r
9802     .constant('b2bTableConfig', {\r
9803         defaultSortPattern: false, // true for descending & false for ascending\r
9804         highlightSearchStringClass: 'tablesorter-search-highlight',\r
9805         zebraStripCutOff: 6, // > zebraStripCutOff\r
9806         tableBreakpoints: [ // breakpoints are >= min and < max\r
9807             {\r
9808                 min: 0,\r
9809                 max: 480,\r
9810                 columns: 2\r
9811             },\r
9812             {\r
9813                 min: 480,\r
9814                 max: 768,\r
9815                 columns: 3\r
9816             },\r
9817             {\r
9818                 min: 768,\r
9819                 max: 1025,\r
9820                 columns: 5\r
9821             },\r
9822             {\r
9823                 min: 1025,\r
9824                 max: 1920,\r
9825                 columns: 7\r
9826             }\r
9827         ]\r
9828     })\r
9829     .directive('b2bTable', ['$filter', '$window', 'b2bTableConfig', '$timeout', function ($filter, $window, b2bTableConfig, $timeout) {\r
9830         return {\r
9831             restrict: 'EA',\r
9832             replace: true,\r
9833             transclude: true,\r
9834             scope: {\r
9835                 tableData: "=",\r
9836                 viewPerPage: "=",\r
9837                 currentPage: "=",\r
9838                 totalPage: "=",\r
9839                 searchCategory: "=",\r
9840                 searchString: "=",\r
9841                 nextSort: '='\r
9842             },\r
9843             require: 'b2bTable',\r
9844             templateUrl: 'b2bTemplate/tables/b2bTable.html',\r
9845             controller: ['$scope', '$attrs', function ($scope, $attrs) {\r
9846                 this.headers = [];\r
9847                 this.currentSortIndex = null;\r
9848                 this.responsive = $scope.responsive = $attrs.responsive;\r
9849                 this.maxTableColumns = -1;\r
9850                 this.totalTableColums = 0;\r
9851                 this.active = $scope.active = false;\r
9852                 this.responsiveRowScopes = [];\r
9853                 this.hideColumnPriority = [];\r
9854                 this.hiddenColumn = [];\r
9855                 this.setIndex = function (headerScope, priority) {\r
9856                     this.headers.push(headerScope);\r
9857                     if (this.responsive) {\r
9858                         this.totalTableColums++;\r
9859                         if (!isNaN(priority)) {\r
9860                             this.hideColumnPriority[priority] = this.totalTableColums - 1;\r
9861                         } else {\r
9862                             this.hideColumnPriority[this.totalTableColums - 1] = this.totalTableColums - 1;\r
9863                         }\r
9864                     }\r
9865                     return this.totalTableColums - 1;\r
9866                 };\r
9867                 this.getIndex = function (headerName) {\r
9868                     for (var i = 0; i < this.headers.length; i++) {\r
9869                         if (this.headers[i].headerName === headerName) {\r
9870                             return this.headers[i].index;\r
9871                         }\r
9872                     }\r
9873                     return null;\r
9874                 };\r
9875                 this.setResponsiveRow = function (responsiveRowScope) {\r
9876                     this.responsiveRowScopes.push(responsiveRowScope);\r
9877                 }\r
9878                 $scope.nextSort = '';\r
9879                 this.sortData = function (columnIndex, reverse, externalSort) {\r
9880                     if ($scope.$parent && $scope.$parent !== undefined) {\r
9881                         $scope.$parent.columnIndex = columnIndex;\r
9882                         $scope.$parent.reverse = reverse;\r
9883                     }\r
9884                     this.currentSortIndex = columnIndex;\r
9885                     if (externalSort === true) {\r
9886                         if (!reverse) {\r
9887                             $scope.nextSort = 'd'\r
9888                         } else {\r
9889                             $scope.nextSort = 'a'\r
9890                         }\r
9891                     }\r
9892                     $scope.currentPage = 1;\r
9893                     this.resetSortPattern();\r
9894                 };\r
9895                 this.getSearchString = function () {\r
9896                     return $scope.searchString;\r
9897                 };\r
9898                 this.resetSortPattern = function () {\r
9899                     for (var i = 0; i < this.headers.length; i++) {\r
9900                         var currentScope = this.headers[i];\r
9901                         if (currentScope.index !== this.currentSortIndex) {\r
9902                             currentScope.resetSortPattern();\r
9903                         }\r
9904                     }\r
9905                 };\r
9906 \r
9907                 $scope.$watch('nextSort', function (val) {\r
9908                     if ($scope.$parent && $scope.$parent !== undefined) {\r
9909                         $scope.$parent.nextSort = val;\r
9910                     }\r
9911 \r
9912                 });\r
9913             }],\r
9914             link: function (scope, elem, attr, ctrl) {\r
9915                 scope.searchCriteria = {};\r
9916                 scope.tableBreakpoints = attr.tableConfig ? scope.$parent.$eval(attr.tableConfig) : angular.copy(b2bTableConfig.tableBreakpoints);\r
9917                 scope.$watchCollection('tableData', function (value) {\r
9918                     if (value && !isNaN(value.length)) {\r
9919                         scope.totalRows = value.length;\r
9920                     }\r
9921                 });\r
9922                 scope.$watch('currentPage', function (val) {\r
9923                     if (scope.$parent && scope.$parent !== undefined) {\r
9924                         scope.$parent.currentPage = val;\r
9925                     }\r
9926 \r
9927                 });\r
9928                 scope.$watch('viewPerPage', function (val) {\r
9929                     if (scope.$parent && scope.$parent !== undefined) {\r
9930                         scope.$parent.viewPerPage = val;\r
9931                     }\r
9932                 });\r
9933                 scope.$watch('totalRows', function (val) {\r
9934                     if (scope.$parent && scope.$parent !== undefined) {\r
9935                         if (val > b2bTableConfig.zebraStripCutOff) {\r
9936                             scope.$parent.zebraStripFlag = true;\r
9937                         } else {\r
9938                             scope.$parent.zebraStripFlag = false;\r
9939                         }\r
9940                     }\r
9941                 });\r
9942                 scope.$watch(function () {\r
9943                     return scope.totalRows / scope.viewPerPage;\r
9944                 }, function (value) {\r
9945                     if (!isNaN(value)) {\r
9946                         scope.totalPage = Math.ceil(value);\r
9947                         scope.currentPage = 1;\r
9948                     }\r
9949                 });\r
9950                 var searchValCheck = function (val) {\r
9951                     if (angular.isDefined(val) && val !== null && val !== "") {\r
9952                         return true;\r
9953                     }\r
9954                 };\r
9955                 var setSearchCriteria = function (v1, v2) {\r
9956                     if (searchValCheck(v1) && searchValCheck(v2)) {\r
9957                         var index = ctrl.getIndex(v2);\r
9958                         scope.searchCriteria = {};\r
9959                         if (index !== null) {\r
9960                             scope.searchCriteria[index] = v1;\r
9961                         }\r
9962                     } else if (searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")) {\r
9963                         scope.searchCriteria = {\r
9964                             $: v1\r
9965                         };\r
9966                     } else {\r
9967                         scope.searchCriteria = {};\r
9968                     }\r
9969                 };\r
9970                 scope.$watch('searchCategory', function (newVal, oldVal) {\r
9971                     if (newVal !== oldVal) {\r
9972                         setSearchCriteria(scope.searchString, newVal);\r
9973                     }\r
9974                 });\r
9975                 scope.$watch('searchString', function (newVal, oldVal) {\r
9976                     if (newVal !== oldVal) {\r
9977                         setSearchCriteria(newVal, scope.searchCategory);\r
9978                     }\r
9979                 });\r
9980                 scope.$watchCollection('searchCriteria', function (val) {\r
9981                     if (scope.$parent && scope.$parent !== undefined) {\r
9982                         scope.$parent.searchCriteria = val;\r
9983                     }\r
9984                     scope.totalRows = scope.tableData && ($filter('filter')(scope.tableData, val, false)).length || 0;\r
9985                     scope.currentPage = 1;\r
9986                 });\r
9987                 var window = angular.element($window);\r
9988                 var findMaxTableColumns = function () {\r
9989                     var windowWidth;\r
9990                     windowWidth = $window.innerWidth;\r
9991                     ctrl.maxTableColumns = -1;\r
9992                     for (var i in scope.tableBreakpoints) {\r
9993                         if (windowWidth >= scope.tableBreakpoints[i].min && windowWidth < scope.tableBreakpoints[i].max) {\r
9994                             ctrl.maxTableColumns = scope.tableBreakpoints[i].columns;\r
9995                             break;\r
9996                         }\r
9997                     }\r
9998                     if (ctrl.maxTableColumns > -1 && ctrl.totalTableColums > ctrl.maxTableColumns) {\r
9999                         ctrl.active = true;\r
10000                     } else {\r
10001                         ctrl.active = false;\r
10002                     }\r
10003                     for (var i in ctrl.responsiveRowScopes) {\r
10004                         ctrl.responsiveRowScopes[i].setActive(ctrl.active);\r
10005                     }\r
10006                 };\r
10007                 var findHiddenColumn = function () {\r
10008                     var columnDiffenence = ctrl.maxTableColumns > -1 ? ctrl.totalTableColums - ctrl.maxTableColumns : 0;\r
10009                     ctrl.hiddenColumn = [];\r
10010                     if (columnDiffenence > 0) {\r
10011                         var tempHideColumnPriority = angular.copy(ctrl.hideColumnPriority);\r
10012                         for (var i = 0; i < columnDiffenence; i++) {\r
10013                             ctrl.hiddenColumn.push(tempHideColumnPriority.pop());\r
10014                         }\r
10015                     }\r
10016                 };\r
10017                 var resizeListener = function () {\r
10018                     findMaxTableColumns();\r
10019                     findHiddenColumn();\r
10020                 };\r
10021                 if (ctrl.responsive) {\r
10022                     window.bind('resize', function () {\r
10023                         resizeListener();\r
10024                         scope.$apply();\r
10025                     });\r
10026                     $timeout(function () {\r
10027                         resizeListener();\r
10028                     }, 100);\r
10029                 }\r
10030             }\r
10031         };\r
10032     }])\r
10033     .directive('b2bTableRow', [function () {\r
10034         return {\r
10035             restrict: 'EA',\r
10036             compile: function (elem, attr) {\r
10037                 if (attr.type === 'header') {\r
10038                     angular.noop();\r
10039                 } else if (attr.type === 'body') {\r
10040                     var html = elem.children();\r
10041                     if (attr.rowRepeat) {\r
10042                         html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false "));\r
10043                     }\r
10044                     html.attr('ng-class', "{'odd': $odd && zebraStripFlag}");\r
10045                     html.attr('class', 'data-row');\r
10046                     html.attr('b2b-responsive-row', '{{$index}}');\r
10047                     elem.append(html);\r
10048                 }\r
10049             }\r
10050         };\r
10051     }])\r
10052     .directive('b2bTableHeader', ['b2bTableConfig', function (b2bTableConfig) {\r
10053         return {\r
10054             restrict: 'EA',\r
10055             replace: true,\r
10056             transclude: true,\r
10057             scope: {\r
10058                 sortable: '@',\r
10059                 defaultSort: '@',\r
10060                 index: '@key'\r
10061             },\r
10062             require: '^b2bTable',\r
10063             templateUrl: function (elem, attr) {\r
10064                 if (attr.sortable === 'false') {\r
10065                     return 'b2bTemplate/tables/b2bTableHeaderUnsortable.html';\r
10066                 } else {\r
10067                     return 'b2bTemplate/tables/b2bTableHeaderSortable.html';\r
10068                 }\r
10069             },\r
10070             link: function (scope, elem, attr, ctrl) {\r
10071                 var reverse = b2bTableConfig.defaultSortPattern;\r
10072                 scope.headerName = elem.text();\r
10073                 scope.headerId = elem.attr('id');\r
10074                 scope.sortPattern = null;\r
10075                 var priority = parseInt(attr.priority, 10);\r
10076                 scope.columnIndex = ctrl.setIndex(scope, priority);\r
10077 \r
10078                 scope.isHidden = function () {\r
10079                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);\r
10080                 };\r
10081 \r
10082                 scope.$watch(function () {\r
10083                     return elem.text();\r
10084                 }, function (value) {\r
10085                     scope.headerName = value;\r
10086                 });\r
10087                 scope.sort = function (sortType) {\r
10088                     if (typeof sortType === 'boolean') {\r
10089                         reverse = sortType;\r
10090                     }\r
10091                     ctrl.sortData(scope.index, reverse, false);\r
10092                     scope.sortPattern = reverse ? 'descending' : 'ascending';\r
10093                     reverse = !reverse;\r
10094                 };\r
10095                 scope.$watch(function () {\r
10096                     return ctrl.currentSortIndex;\r
10097                 }, function (value) {\r
10098                     if (value !== scope.index) {\r
10099                         scope.sortPattern = null;\r
10100                     }\r
10101                 });\r
10102 \r
10103                 if (scope.sortable === undefined || scope.sortable === 'true' || scope.sortable === true) {\r
10104                     scope.sortable = 'true';\r
10105                 } else if (scope.sortable === false || scope.sortable === 'false') {\r
10106                     scope.sortable = 'false';\r
10107                 }\r
10108 \r
10109                 if (scope.sortable !== 'false') {\r
10110                     if (scope.defaultSort === 'A' || scope.defaultSort === 'a') {\r
10111                         scope.sort(false);\r
10112                     } else if (scope.defaultSort === 'D' || scope.defaultSort === 'd') {\r
10113                         scope.sort(true);\r
10114                     }\r
10115                 }\r
10116                 scope.resetSortPattern = function () {\r
10117                     reverse = b2bTableConfig.defaultSortPattern;\r
10118                 };\r
10119             }\r
10120         };\r
10121     }])\r
10122     .directive('b2bResponsiveRow', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {\r
10123         return {\r
10124             restrict: 'EA',\r
10125             require: '^b2bTable',\r
10126             controller: ['$scope', function ($scope) {\r
10127                 this.rowValues = $scope.rowValues = [];\r
10128                 this.setRowValues = function (rowValue) {\r
10129                     this.rowValues.push(rowValue);\r
10130                 };\r
10131                 var columnIndexCounter = -1;\r
10132                 this.getIndex = function () {\r
10133                     columnIndexCounter++;\r
10134                     return columnIndexCounter;\r
10135                 };\r
10136             }],\r
10137             link: function (scope, elem, attr, ctrl) {\r
10138                 if (ctrl.responsive) {\r
10139                     scope.rowIndex = attr.b2bResponsiveRow;\r
10140                     scope.active = false;\r
10141                     scope.expandFlag = false;\r
10142                     scope.headerValues = ctrl.headers;\r
10143                     ctrl.setResponsiveRow(scope);\r
10144                     var firstTd = elem.find('td').eq(0);\r
10145                     scope.setActive = function (activeFlag) {\r
10146                         scope.active = activeFlag;\r
10147                         if (scope.active) {\r
10148                             elem.addClass('has-button');\r
10149                             firstTd.attr('role', 'rowheader');\r
10150                             firstTd.parent().attr('role', 'row');\r
10151                         } else {\r
10152                             elem.removeClass('has-button');\r
10153                             firstTd.removeAttr('role');\r
10154                             firstTd.parent().removeAttr('role');\r
10155                         }\r
10156                     };\r
10157                     scope.toggleExpandFlag = function (expandFlag) {\r
10158                         if (angular.isDefined(expandFlag)) {\r
10159                             scope.expandFlag = expandFlag;\r
10160                         } else {\r
10161                             scope.expandFlag = !scope.expandFlag;\r
10162                         }\r
10163                         if (scope.expandFlag) {\r
10164                             elem.addClass('opened');\r
10165                         } else {\r
10166                             elem.removeClass('opened');\r
10167                         }\r
10168                     };\r
10169 \r
10170                     firstTd.attr('scope', 'row');\r
10171                     firstTd.addClass('col-1');\r
10172                     scope.$on('$destroy', function () {\r
10173                         elem.next().remove();\r
10174                     });\r
10175                     $timeout(function () {\r
10176                         scope.firstTdId = firstTd.attr('id');\r
10177                         var firstTdContent = firstTd.html();\r
10178                         var toggleButtonTemplate = '<span ng-show="!active">' + firstTdContent + '</span><button type="button" aria-describedby="sup-actNum{{$id}}" aria-expanded="{{expandFlag}}" ng-show="active" ng-click="toggleExpandFlag()"><i ng-class="{\'icon-primary-accordion-plus\': !expandFlag, \'icon-primary-accordion-minus\': expandFlag}" aria-hidden="true"></i>' + firstTdContent + '</button><span id="sup-actNum{{$id}}" style="display:none">{{expandFlag && "Hide row below." || "Show row below."}}</span>';\r
10179                         toggleButtonTemplate = $compile(toggleButtonTemplate)(scope);\r
10180                         firstTd.html('');\r
10181                         firstTd.prepend(toggleButtonTemplate);\r
10182 \r
10183                         var template = $templateCache.get('b2bTemplate/tables/b2bResponsiveRow.html');\r
10184                         template = $compile(template)(scope);\r
10185                         elem.after(template);\r
10186                     }, 100);\r
10187                 }\r
10188             }\r
10189         };\r
10190     }])\r
10191     .directive('b2bResponsiveList', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {\r
10192         return {\r
10193             restrict: 'EA',\r
10194             require: '^b2bTable',\r
10195             link: function (scope, elem, attr, ctrl) {\r
10196                 scope.columnIndex = parseInt(attr.b2bResponsiveList, 10);\r
10197                 scope.isVisible = function () {\r
10198                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);\r
10199                 };\r
10200             }\r
10201         };\r
10202     }])\r
10203     .directive('b2bTableBody', ['$filter', '$timeout', 'b2bTableConfig', function ($filter, $timeout, b2bTableConfig) {\r
10204         return {\r
10205             restrict: 'EA',\r
10206             require: ['^b2bTable', '?^b2bResponsiveRow'],\r
10207             scope: true,\r
10208             replace: true,\r
10209             transclude: true,\r
10210             templateUrl: 'b2bTemplate/tables/b2bTableBody.html',\r
10211             link: function (scope, elem, attr, ctrl) {\r
10212                 var b2bTableCtrl = ctrl[0];\r
10213                 var b2bResponsiveRowCtrl = ctrl[1];\r
10214                 var highlightSearchStringClass = b2bTableConfig.highlightSearchStringClass;\r
10215                 var searchString = "";\r
10216                 var wrapElement = function (elem) {\r
10217                     var text = elem.text();\r
10218                     elem.html($filter('b2bHighlight')(text, searchString, highlightSearchStringClass));\r
10219                 };\r
10220                 var traverse = function (elem) {\r
10221                     var innerHtml = elem.children();\r
10222                     if (innerHtml.length > 0) {\r
10223                         for (var i = 0; i < innerHtml.length; i++) {\r
10224                             traverse(innerHtml.eq(i));\r
10225                         }\r
10226                     } else {\r
10227                         wrapElement(elem);\r
10228                         return;\r
10229                     }\r
10230                 };\r
10231                 var clearWrap = function (elem) {\r
10232                     var elems = elem.find('*');\r
10233                     for (var i = 0; i < elems.length; i++) {\r
10234                         if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {\r
10235                             var text = elems.eq(i).text();\r
10236                             elems.eq(i).replaceWith(text);\r
10237                         }\r
10238                     }\r
10239                 };\r
10240                 if (b2bResponsiveRowCtrl) {\r
10241                     scope.columnIndex = b2bResponsiveRowCtrl.getIndex();\r
10242                     scope.isHidden = function () {\r
10243                         return (b2bTableCtrl.hiddenColumn.indexOf(scope.columnIndex) > -1);\r
10244                     };\r
10245                 }\r
10246                 $timeout(function () {\r
10247                     var actualHtml = elem.children();\r
10248                     scope.$watch(function () {\r
10249                         return b2bTableCtrl.getSearchString();\r
10250                     }, function (val) {\r
10251                         searchString = val;\r
10252                         clearWrap(elem);\r
10253                         if (actualHtml.length > 0) {\r
10254                             traverse(elem);\r
10255                         } else {\r
10256                             wrapElement(elem);\r
10257                         }\r
10258                     });\r
10259                     if (b2bResponsiveRowCtrl) {\r
10260                         b2bResponsiveRowCtrl.setRowValues(elem.html());\r
10261                     }\r
10262                 }, 50);\r
10263             }\r
10264         };\r
10265     }])\r
10266     .directive('b2bTableSort', ['b2bTableConfig','$timeout', function (b2bTableConfig,$timeout) {\r
10267         return {\r
10268             restrict: 'EA',\r
10269             replace: true,\r
10270             require: '^b2bTable',\r
10271             link: function (scope, elem, attr, ctrl) {\r
10272                 var initialSort = '',\r
10273                     nextSort = '',\r
10274                     tempsort = '';\r
10275                 initialSort = attr.initialSort;\r
10276 \r
10277                 scope.sortTable = function (msg) {\r
10278                     $timeout(function(){\r
10279                         if (nextSort.length > 0) {\r
10280 \r
10281                         if (nextSort === 'd' || nextSort === 'D') {\r
10282                             tempsort = nextSort\r
10283                             ctrl.sortData(msg, true, true);\r
10284                             nextSort = 'a';\r
10285                              $timeout(function(){\r
10286                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10287                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10288                                 }   \r
10289                             },100);\r
10290                             \r
10291                         } else {\r
10292                             tempsort = nextSort\r
10293                             ctrl.sortData(msg, false, true);\r
10294                             nextSort = 'd';\r
10295                              $timeout(function(){\r
10296                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10297                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10298                                 }   \r
10299                             },100);\r
10300                         }\r
10301                     } else if (initialSort.length > 0) {\r
10302 \r
10303                         if (initialSort === 'd' || initialSort === 'D') {\r
10304                             tempsort = nextSort\r
10305                             ctrl.sortData(msg, true, true);\r
10306                             nextSort = 'a';\r
10307                             $timeout(function(){\r
10308                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10309                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10310                                 }   \r
10311                             },100);\r
10312                              \r
10313                         } else {\r
10314                             tempsort = nextSort\r
10315                             ctrl.sortData(msg, false, true);\r
10316                             nextSort = 'd';\r
10317                              $timeout(function(){\r
10318                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10319                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10320                                 }   \r
10321                             },100);\r
10322 \r
10323                              \r
10324                         }\r
10325                     }\r
10326                     },10)\r
10327 \r
10328                 };\r
10329 \r
10330                 scope.sortDropdown = function(msg) {\r
10331 \r
10332                     if(tempsort==='') {\r
10333 \r
10334                         tempsort='a'\r
10335                     }\r
10336                     if(tempsort === 'd' || tempsort === 'D' ) {\r
10337                         ctrl.sortData(msg, true, false);       \r
10338                     } else {\r
10339                        ctrl.sortData(msg, false, false);\r
10340                     }\r
10341 \r
10342                 };\r
10343             }\r
10344         };\r
10345     }]);\r
10346 /**\r
10347  * @ngdoc directive\r
10348  * @name Tabs, tables & accordions.att:tabs\r
10349  *\r
10350  * @description\r
10351  *  <file src="src/tabs/docs/readme.md" />\r
10352  *\r
10353  * @usage\r
10354  *  <b2b-tabset tab-id-selected="activeTabsId">\r
10355         <b2b-tab ng-repeat="tab in gTabs" tab-item="tab" \r
10356                  id="{{tab.uniqueId}}" aria-controls="{{tab.tabPanelId}}"\r
10357                  ng-disabled="tab.disabled">\r
10358             {{tab.title}}\r
10359         </b2b-tab>\r
10360     </b2b-tabset>\r
10361  *\r
10362  * @example\r
10363  *  <section id="code">\r
10364         <example module="b2b.att">\r
10365             <file src="src/tabs/docs/demo.html" />\r
10366             <file src="src/tabs/docs/demo.js" />\r
10367         </example>\r
10368     </section>\r
10369  *\r
10370  */\r
10371 \r
10372 angular.module('b2b.att.tabs', ['b2b.att.utilities'])\r
10373     .directive('b2bTabset', function () {\r
10374         return {\r
10375             restrict: 'EA',\r
10376             transclude: true,\r
10377             replace: true,\r
10378             scope: {\r
10379                 tabIdSelected: '='\r
10380             },\r
10381             templateUrl: 'b2bTemplate/tabs/b2bTabset.html',\r
10382             controller: ['$scope', function ($scope) {\r
10383 \r
10384                 this.setTabIdSelected = function (tab) {\r
10385                     $scope.tabIdSelected = tab.id;\r
10386                 };\r
10387 \r
10388                 this.getTabIdSelected = function () {\r
10389                     return $scope.tabIdSelected;\r
10390                 };\r
10391             }]\r
10392         };\r
10393     })\r
10394     .directive('b2bTab', ['keymap', function (keymap) {\r
10395         return {\r
10396             restrict: 'EA',\r
10397             transclude: true,\r
10398             replace: true,\r
10399             require: '^b2bTabset',\r
10400             scope: {\r
10401                 tabItem: "="\r
10402             },\r
10403             templateUrl: 'b2bTemplate/tabs/b2bTab.html',\r
10404             controller: [function(){}],\r
10405             link: function (scope, element, attr, b2bTabsetCtrl) {\r
10406 \r
10407                 if (scope.tabItem && !scope.tabItem.disabled) {\r
10408                     scope.tabItem.disabled = false;\r
10409                 }\r
10410 \r
10411                 scope.isTabActive = function () {\r
10412                     return (scope.tabItem.id === b2bTabsetCtrl.getTabIdSelected());\r
10413                 };\r
10414 \r
10415                 scope.clickTab = function () {\r
10416                     if (attr.disabled) {\r
10417                         return;\r
10418                     }\r
10419                     b2bTabsetCtrl.setTabIdSelected(scope.tabItem);\r
10420                 };\r
10421 \r
10422                 scope.nextKey = function () {\r
10423                     var el = angular.element(element[0])[0];\r
10424                     var elementToFocus = null;\r
10425                     while (el && el.nextElementSibling) {\r
10426                         el = el.nextElementSibling;\r
10427                         if (!el.querySelector('a').disabled) {\r
10428                             elementToFocus = el.querySelector('a');\r
10429                             break;\r
10430                         }\r
10431                     }\r
10432 \r
10433                     if (!elementToFocus) {\r
10434                         var childTabs = element.parent().children();\r
10435                         for (var i = 0; i < childTabs.length; i++) {\r
10436                             if (!childTabs[i].querySelector('a').disabled) {\r
10437                                 elementToFocus = childTabs[i].querySelector('a');\r
10438                                 break;\r
10439                             }\r
10440                         }\r
10441                     }\r
10442 \r
10443                     if (elementToFocus) {\r
10444                         elementToFocus.focus();\r
10445                     }\r
10446                 };\r
10447 \r
10448                 scope.previousKey = function () {\r
10449                     var el = angular.element(element[0])[0];\r
10450                     var elementToFocus = null;\r
10451 \r
10452                     while (el && el.previousElementSibling) {\r
10453                         el = el.previousElementSibling;\r
10454                         if (!el.querySelector('a').disabled) {\r
10455                             elementToFocus = el.querySelector('a');\r
10456                             break;\r
10457                         }\r
10458                     }\r
10459 \r
10460                     if (!elementToFocus) {\r
10461                         var childTabs = element.parent().children();\r
10462                         for (var i = childTabs.length - 1; i > 0; i--) {\r
10463                             if (!childTabs[i].querySelector('a').disabled) {\r
10464                                 elementToFocus = childTabs[i].querySelector('a');\r
10465                                 break;\r
10466                             }\r
10467                         }\r
10468                     }\r
10469 \r
10470                     if (elementToFocus) {\r
10471                         elementToFocus.focus();\r
10472                     }\r
10473                 };\r
10474 \r
10475                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {\r
10476 \r
10477                     if (!(evt.keyCode)) {\r
10478                         evt.keyCode = evt.which;\r
10479                     }\r
10480 \r
10481                     switch (evt.keyCode) {\r
10482                         case keymap.KEY.RIGHT:\r
10483                             evt.preventDefault();\r
10484                             scope.nextKey();\r
10485                             break;\r
10486 \r
10487                         case keymap.KEY.LEFT:\r
10488                             evt.preventDefault();\r
10489                             scope.previousKey();\r
10490                             break;\r
10491 \r
10492                         default:;\r
10493                     }\r
10494                 });\r
10495             }\r
10496         };\r
10497     }]);\r
10498 /**\r
10499  * @ngdoc directive\r
10500  * @name Messages, modals & alerts.att:tagBadges\r
10501  *\r
10502  * @description\r
10503  *  <file src="src/tagBadges/docs/readme.md" />\r
10504  *\r
10505  * @example\r
10506  *  <section id="code">\r
10507         <example module="b2b.att">\r
10508             <file src="src/tagBadges/docs/demo.html" />\r
10509             <file src="src/tagBadges/docs/demo.js" />\r
10510         </example>\r
10511     </section>\r
10512  *\r
10513  */\r
10514 angular.module('b2b.att.tagBadges', ['b2b.att.utilities'])\r
10515         .directive('b2bTagBadge',['$timeout',function($timeout){\r
10516             return{\r
10517                 restrict: 'EA',\r
10518                 link: function(scope,elem,attr,ctrl){\r
10519                     elem.addClass('b2b-tags');\r
10520                     if(angular.element(elem[0].querySelector('.icon-primary-close')).length>0) {\r
10521                         var item = angular.element(elem[0].querySelector('.icon-primary-close'));\r
10522                         item.bind('click',function(){\r
10523                         elem.css({'height':'0','width':'0','padding':'0','border':'0'});\r
10524                         elem.attr('tabindex','0');\r
10525                         elem[0].focus();\r
10526                         item.parent().remove();\r
10527                         elem[0].bind('blur',function(){\r
10528                             elem[0].remove();\r
10529                         });\r
10530                     });  \r
10531                     }\r
10532                   \r
10533 \r
10534 \r
10535 \r
10536                 }\r
10537             };   \r
10538 }]);\r
10539 /**\r
10540  * @ngdoc directive\r
10541  * @name Forms.att:textArea\r
10542  *\r
10543  * @description\r
10544  *  <file src="src/textArea/docs/readme.md" />\r
10545  *\r
10546  * @usage\r
10547  *  <textarea b2b-reset b2b-reset-textarea ng-model="textAreaModel" ng-disabled="disabled" ng-trim="false" placeholder="{{placeholderText}}" rows="{{textAreaRows}}" maxlength="{{textAreaMaxlength}}" role="textarea"></textarea>\r
10548  *\r
10549  * @example\r
10550     <section id="code">\r
10551         <b>HTML + AngularJS</b>\r
10552         <example module="b2b.att">\r
10553             <file src="src/textArea/docs/demo.html" />\r
10554             <file src="src/textArea/docs/demo.js" />\r
10555         </example>\r
10556     </section>\r
10557  */\r
10558 angular.module('b2b.att.textArea', ['b2b.att.utilities'])\r
10559 \r
10560 .directive('b2bResetTextarea', [ function () {\r
10561     return {\r
10562         restrict: 'A',\r
10563         require: 'b2bReset',\r
10564         link: function (scope, element, attrs, ctrl) {\r
10565 \r
10566             var resetButton = ctrl.getResetButton();\r
10567             \r
10568             var computeScrollbarAndAddClass = function () {\r
10569                 if (element.prop('scrollHeight') > element[0].clientHeight) {\r
10570                     element.addClass('hasScrollbar');\r
10571                 } else {\r
10572                     element.removeClass('hasScrollbar');\r
10573                 }\r
10574             };\r
10575             \r
10576             computeScrollbarAndAddClass();\r
10577 \r
10578             element.on('focus keyup', function(){\r
10579                 computeScrollbarAndAddClass();\r
10580             });\r
10581         }\r
10582     };\r
10583 }]);\r
10584 \r
10585 /**\r
10586  * @ngdoc directive\r
10587  * @name Forms.att:tooltipsForForms\r
10588  *\r
10589  * @description\r
10590  *  <file src="src/tooltipsForForms/docs/readme.md" />\r
10591  *\r
10592  * @example\r
10593  <example module="b2b.att">\r
10594  <file src="src/tooltipsForForms/docs/demo.html" />\r
10595  <file src="src/tooltipsForForms/docs/demo.js" />\r
10596  </example>\r
10597  */\r
10598 angular.module('b2b.att.tooltipsForForms', ['b2b.att.utilities'])\r
10599         .directive('b2bTooltip', ['$document', '$window', '$isElement', function ($document, $window, $isElement) {\r
10600                 return  {\r
10601                     restrict: 'A',\r
10602                     link: function (scope, elem, attr, ctrl) {\r
10603                         var icon = elem[0].querySelector('a.tooltip-element');\r
10604                         var btnIcon = elem[0].querySelector('.btn.tooltip-element');\r
10605                         var tooltipText = elem[0].querySelector('.helpertext');\r
10606                         var tooltipWrapper = elem[0].querySelector('.tooltip-size-control');\r
10607                         if (elem.hasClass('tooltip-onfocus')) {\r
10608                             var inputElm = angular.element(elem[0].querySelector("input"));\r
10609                             var textAreaElm = angular.element(elem[0].querySelector("textarea"));\r
10610                         }\r
10611                         angular.element(icon).attr({'aria-expanded': false});\r
10612                         angular.element(btnIcon).attr({'aria-expanded': false});\r
10613                         var calcTooltip = function () {\r
10614                             if (!elem.hasClass('tooltip active')) {\r
10615                                 if (elem.hasClass('tooltip-onfocus')) {\r
10616                                     angular.element(elem[0].querySelector("input")).triggerHandler('focusout');\r
10617                                 }\r
10618                                 if (elem.hasClass('tooltip-onclick')) {\r
10619                                     return false;\r
10620                                 }\r
10621                                 angular.element(icon).removeClass('active');\r
10622                                 angular.element(icon).attr({'aria-expanded': true});\r
10623                                 angular.element(icon).attr({'aria-describedby': angular.element(tooltipText).attr('id')});\r
10624                                 angular.element(tooltipText).attr({'aria-hidden': false});\r
10625                                 elem.addClass('active');\r
10626 \r
10627                                 var tooltipIconPos = angular.element(icon).prop('offsetLeft'),\r
10628                                         tooltipPosition = angular.element(tooltipText).prop('offsetWidth') / 2,\r
10629                                         tipOffset = (tooltipIconPos - 30) - tooltipPosition,\r
10630                                         maxRightPos = (($window.innerWidth - 72) - (tooltipPosition * 2)) - 14.5;\r
10631 \r
10632                                 if ($window.innerWidth >= '768') {\r
10633                                     if (tipOffset < 0) {// if icon on far left side of page\r
10634                                         tipOffset = 15;\r
10635                                     }\r
10636                                     else if (tooltipIconPos > maxRightPos) {// if icon is far right side of page\r
10637                                         tipOffset = maxRightPos;\r
10638                                     }\r
10639                                     else {// if tooltip in the middle somewhere\r
10640                                         tipOffset = tipOffset;\r
10641                                     }\r
10642                                     angular.element(tooltipWrapper).css({left: tipOffset + 'px'});\r
10643                                 }\r
10644                             }\r
10645                         };\r
10646                         \r
10647                         // TOOLTIP LINK ONCLICK AND FOCUS\r
10648                         angular.element(icon).on('click mouseover mouseout focus blur', function (e) {\r
10649                             if (e.type == 'mouseover') {\r
10650                                 calcTooltip();\r
10651                             }\r
10652                             else if (e.type == 'mouseout' && elem.hasClass('active')) {\r
10653                                 if (!elem.hasClass('activeClick')) {\r
10654                                     angular.element(tooltipText).attr({\r
10655                                         'aria-hidden': true,\r
10656                                         'tabindex': '-1'\r
10657                                     });\r
10658                                     elem.removeClass('active');\r
10659                                 } else if (elem.hasClass('activeClick') && navigator.userAgent.match(/iphone/i)) {\r
10660                                     elem.removeClass('active activeClick');\r
10661                                 }\r
10662                             }\r
10663 \r
10664                             else {\r
10665                                 if (elem.hasClass('activeClick')) {\r
10666                                     angular.element(icon).attr({'aria-expanded': false});\r
10667                                     angular.element(tooltipText).attr({'aria-hidden': true});\r
10668                                     angular.element(icon).removeAttr('aria-describedby');\r
10669                                     elem.removeClass('activeClick active');\r
10670                                     e.preventDefault();\r
10671                                 }\r
10672                                 else if (e.type == 'click') {\r
10673                                     elem.addClass('activeClick');\r
10674                                     calcTooltip();\r
10675                                     e.preventDefault();\r
10676                                 }\r
10677                                 else {\r
10678                                     angular.element(icon).on('keydown', function (e) {\r
10679                                         if (e.keyCode == '32') {\r
10680                                             (elem.hasClass('active')) ? elem.removeClass('active') : elem.addClass('value');\r
10681                                             angular.element(icon).triggerHandler('click');\r
10682                                             e.preventDefault();\r
10683                                         } else if (e.keyCode == '27') {\r
10684                                             (elem.hasClass('active')) ? elem.removeClass('active activeClick') : elem.addClass('value');\r
10685                                         }\r
10686                                     });\r
10687                                     e.preventDefault();\r
10688                                 }\r
10689                             }\r
10690                             e.preventDefault();\r
10691                         });\r
10692 \r
10693                         // TOOLTIP BUTTON INSIDE A TEXT FIELD\r
10694                         angular.element(btnIcon).on('click', function (e) {\r
10695                             var $this = angular.element(this);\r
10696                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {\r
10697                                 elem.removeClass('active');\r
10698                                 $this.removeClass('active');\r
10699                                 angular.element(tooltipText).removeAttr('aria-live');\r
10700                                 $this.attr({'aria-expanded': 'false'});\r
10701                                 $this.removeAttr('aria-describedby');\r
10702                             } else {\r
10703                                 elem.addClass('active');\r
10704                                 $this.addClass('active');\r
10705                                 $this.attr({'aria-expanded': 'true', 'aria-describedby': angular.element(tooltipText).attr('id')});\r
10706                                 angular.element(tooltipText).attr({'aria-live': 'polite'});\r
10707                             }\r
10708                         });\r
10709 \r
10710                         angular.element(btnIcon).on('blur', function (e) {\r
10711                             var $this = angular.element(this);\r
10712                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {\r
10713                                 elem.removeClass('active');\r
10714                                 $this.removeClass('active');\r
10715                                 angular.element(tooltipText).removeAttr('aria-live');\r
10716                                 $this.attr({'aria-expanded': 'false'});\r
10717                                 $this.removeAttr('aria-describedby');\r
10718                             }\r
10719                         });  \r
10720 \r
10721                         angular.element(btnIcon).on('keydown', function (e) {\r
10722                             var $this = angular.element(this);\r
10723                             if (e.keyCode == '27') {\r
10724                                 var $this = angular.element(this);\r
10725                                 if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {\r
10726                                     elem.removeClass('active');\r
10727                                     $this.removeClass('active');\r
10728                                     angular.element(tooltipText).removeAttr('aria-live');\r
10729                                     $this.attr({'aria-expanded': 'false'});\r
10730                                     $this.removeAttr('aria-describedby');\r
10731                                 }\r
10732                             }\r
10733                         });\r
10734 \r
10735                         // close all tooltips if clicking something else\r
10736                         $document.bind('click', function (e) {\r
10737                             var isElement = $isElement(angular.element(e.target), elem, $document);\r
10738                             if (!isElement) {\r
10739                                 elem.removeClass('active');\r
10740                                 angular.element(elem[0].querySelector('.tooltip-element')).removeClass('active');\r
10741                                 angular.element(tooltipText).removeAttr('aria-live');\r
10742                                 angular.element(elem[0].querySelector('.tooltip-element')).attr({'aria-expanded': 'false'});\r
10743                                 angular.element(elem[0].querySelector('.tooltip-element')).removeAttr('aria-describedby');\r
10744                             };\r
10745                         });\r
10746 \r
10747                         angular.element(inputElm).on('keydown', function (e) {\r
10748                             if (e.keyCode == '27'){\r
10749                                 elem.removeClass('active');\r
10750                                 angular.element(tooltipText).css('display', 'none');\r
10751                                 angular.element(tooltipText).removeAttr('aria-live');\r
10752 \r
10753                                 if (angular.element(this).attr('aria-describedby') === undefined){\r
10754 \r
10755                                 }\r
10756 \r
10757                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){\r
10758 \r
10759                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);\r
10760 \r
10761                                     angular.element(this).attr('aria-describedby', describedByValue);\r
10762 \r
10763                                 }\r
10764                                 else {\r
10765                                     angular.element(this).removeAttr('aria-describedby');\r
10766                                 }\r
10767                             }\r
10768                         });\r
10769 \r
10770                         angular.element(textAreaElm).on('keydown', function (e) {\r
10771                             if (e.keyCode == '27'){\r
10772                                 elem.removeClass('active');\r
10773                                 angular.element(tooltipText).css('display', 'none');\r
10774                                 angular.element(tooltipText).removeAttr('aria-live');\r
10775                                 if (angular.element(this).attr('aria-describedby') === undefined){\r
10776 \r
10777                                 }\r
10778 \r
10779                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){\r
10780 \r
10781                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);\r
10782 \r
10783                                     angular.element(this).attr('aria-describedby', describedByValue);\r
10784 \r
10785                                 }\r
10786                                 else {\r
10787                                     angular.element(this).removeAttr('aria-describedby');\r
10788                                 }\r
10789                             }\r
10790                         });\r
10791 \r
10792                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXT FIELD\r
10793                         angular.element(inputElm).on('focus', function (e) {\r
10794                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');\r
10795                             for (var i = 0; i < allTooltip.length; i++) {\r
10796                                 if (angular.element(allTooltip[i]).hasClass('active')) {\r
10797                                     angular.element(allTooltip[i]).triggerHandler('click');\r
10798                                 }\r
10799                             };\r
10800                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});\r
10801                             angular.element(tooltipText).css('display', 'block');\r
10802                             angular.element(tooltipText).attr({'aria-live': 'polite'});\r
10803                             elem.addClass('active');\r
10804                         });\r
10805                         angular.element(inputElm).on('blur', function (e) {\r
10806                             elem.removeClass('active');\r
10807                             angular.element(tooltipText).css('display', 'none');\r
10808                             angular.element(tooltipText).removeAttr('aria-live');\r
10809                             angular.element(this).removeAttr('aria-describedby');\r
10810                         });\r
10811 \r
10812                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXTAREA\r
10813                         angular.element(textAreaElm).on('focus', function (e) {\r
10814                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');\r
10815                             for (var i = 0; i < allTooltip.length; i++) {\r
10816                                 if (angular.element(allTooltip[i]).hasClass('active')) {\r
10817                                     angular.element(allTooltip[i]).triggerHandler('click');\r
10818                                 }\r
10819                             };\r
10820                             elem.addClass('active');\r
10821                             angular.element(tooltipText).css('display', 'block');\r
10822                             angular.element(tooltipText).attr({'aria-live': 'polite'});\r
10823                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});\r
10824                         });\r
10825                         angular.element(textAreaElm).on('blur', function (e) {\r
10826                             elem.removeClass('active');\r
10827                             angular.element(tooltipText).css('display', 'none');\r
10828                             angular.element(tooltipText).removeAttr('aria-live');\r
10829                             angular.element(this).removeAttr('aria-describedby');\r
10830                         });\r
10831                     }\r
10832                 };\r
10833             }]); \r
10834 /**\r
10835  * @ngdoc directive\r
10836  * @name Navigation.att:TreeNavigation\r
10837  *\r
10838  *\r
10839  * @scope\r
10840  * @param {String} setRole - This value needs to be "tree". This is required to incorporate CATO requirements.\r
10841  * @param {Boolean} groupIt - This value needs to be "false" for top-level tree rendered.\r
10842  *\r
10843  * @description\r
10844  *  <file src="src/treeNav/docs/readme.md" />\r
10845  *\r
10846  * @usage\r
10847  *      <div class="b2b-tree">\r
10848  *                <b2b-tree-nav collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-nav>\r
10849  *            </div>\r
10850  * @example\r
10851  *  <section id="code">\r
10852         <example module="b2b.att">\r
10853             <file src="src/treeNav/docs/demo.html" />\r
10854             <file src="src/treeNav/docs/demo.js" />\r
10855        </example>\r
10856     </section>\r
10857  *\r
10858  */\r
10859 angular.module('b2b.att.treeNav', ['b2b.att.utilities'])\r
10860     .directive('b2bTreeNav', function () {\r
10861         return {\r
10862             restrict: "E",\r
10863             replace: true,\r
10864             scope: {\r
10865                 collection: '=',\r
10866                 groupIt: '=',\r
10867                 setRole: '@'\r
10868             },\r
10869             templateUrl: function (element, attrs) {\r
10870                 if (attrs.groupIt === 'true') {\r
10871                     return "b2bTemplate/treeNav/groupedTree.html";\r
10872                 } else {\r
10873                     return "b2bTemplate/treeNav/ungroupedTree.html";\r
10874                 }\r
10875             },\r
10876             link: function (scope) {               \r
10877                 if (!(scope.setRole === 'tree')) {\r
10878                     scope.setRole = 'group';\r
10879                 }             \r
10880             }\r
10881         }\r
10882     })\r
10883     .directive('b2bMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {\r
10884         return {\r
10885             restrict: "E",\r
10886             replace: true,\r
10887             scope: {\r
10888                 member: '=',\r
10889                 groupIt: '='\r
10890             },\r
10891             templateUrl: 'b2bTemplate/treeNav/treeMember.html',\r
10892             link: function (scope, element, attrs) {\r
10893                 scope.elemArr = [];\r
10894                 var removeRootTabIndex = function (elem) {\r
10895                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {\r
10896                         elem.attr('tabindex', -1);                        \r
10897                         return;\r
10898                     }\r
10899                     removeRootTabIndex(elem.parent());\r
10900                 };\r
10901                 scope.$watch('member.child', function(newVal, oldVal){                  \r
10902                     if(newVal !== oldVal){\r
10903                         scope.showChild();\r
10904                     };\r
10905                 });\r
10906                 scope.showChild = function () {\r
10907                         if (!element.hasClass('grouped')) {\r
10908                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {\r
10909                                 scope.groupIt = false;\r
10910                                 element.addClass('grouped');\r
10911                                 element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");\r
10912                                 $compile(element.contents())(scope);\r
10913                                 if(scope.member.active && scope.member.active === true){\r
10914                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
10915                                 };\r
10916                                 if(scope.member.selected && scope.member.selected === true){\r
10917                                     element.attr('aria-selected', true);\r
10918                                     element.attr('tabindex', 0);\r
10919                                     removeRootTabIndex(element);\r
10920                                 };\r
10921                                 if(scope.member.active && scope.member.active == undefined){\r
10922                                     element.find('i').eq(0).addClass('icon-primary-collapsed');\r
10923                                 };\r
10924                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {\r
10925                                 element.addClass('grouped');\r
10926                                 scope.groupIt = true;\r
10927                                 // FILTER - GROUPBY - APPROACH \r
10928                                 var j = 0;\r
10929                                 var grpName = '';\r
10930                                 if(scope.member.child[0].groupName !== undefined){\r
10931                                     grpName = scope.member.child[0].groupName;\r
10932                                 }\r
10933                                 else{\r
10934                                     var toSlice = scope.member.child[0].name.search(' ');\r
10935                                     grpName = scope.member.child[0].name.slice(0, toSlice);\r
10936                                 }\r
10937 \r
10938                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {\r
10939                                     j = 0;\r
10940                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        \r
10941                                         if (j === scope.member.child.length) {\r
10942                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
10943                                             break;\r
10944                                             \r
10945                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){\r
10946                                                 scope.member.child[j-1].activeGrp = true;\r
10947                                             };\r
10948                                             \r
10949                                         }\r
10950                                         if (i + scope.member.divide > scope.member.child.length) {\r
10951                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
10952                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
10953                                                 scope.member.child[j].activeGrp = true;\r
10954                                             };\r
10955 \r
10956                                         } else {\r
10957                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);\r
10958                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
10959                                                 scope.member.child[j].activeGrp = true;\r
10960                                             };\r
10961                                         }\r
10962                                     }\r
10963                                 }\r
10964                                 if(scope.member.divide){\r
10965                                     element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");\r
10966                                 } else {\r
10967                                     element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");\r
10968                                 }\r
10969                                 $compile(element.contents())(scope);\r
10970                                 if(scope.member.active && scope.member.active === true){\r
10971                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
10972                                 };\r
10973                                 if(scope.member.selected && scope.member.selected === true){\r
10974                                     element.attr('aria-selected', true);\r
10975                                 };\r
10976                                 if( scope.member.active && scope.member.active == undefined){\r
10977                                     element.find('i').eq(0).addClass('icon-primary-collapsed');\r
10978                                 };\r
10979                             }\r
10980                         }\r
10981                 };\r
10982                 //Below condition opens node for opening on json load.\r
10983                 if(scope.member.active && scope.member.active == true){\r
10984                     scope.showChild();\r
10985                 };\r
10986                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){\r
10987                     element.find('i').eq(0).addClass('icon-primary-collapsed');\r
10988                 }\r
10989                 else if(scope.member.child == undefined){\r
10990                     element.find('i').eq(0).addClass('icon-primary-circle');\r
10991                 };\r
10992                 element.bind('keydown', function (evt) {\r
10993                     switch (evt.keyCode) {\r
10994                         case keymap.KEY.ENTER:\r
10995                             if (element.hasClass('bg') && scope.member.onSelect !== undefined) {\r
10996                                 scope.member.onSelect(scope.member);\r
10997                             }\r
10998                             evt.stopPropagation();\r
10999                             break;\r
11000                         default: \r
11001                             break;                            \r
11002                     }\r
11003                     \r
11004                 });\r
11005                 //else getting true in every case .. so better use switch case .. that makes more sense you dumb.\r
11006                 element.bind('click', function (evt) {\r
11007                     scope.showChild();\r
11008                     var expandFunc = scope.member.onExpand;\r
11009                     \r
11010                     //onSelect\r
11011                         if (element.hasClass('bg') && scope.member.onSelect !== undefined) {\r
11012                                     scope.member.onSelect(scope.member);\r
11013                                 }\r
11014                         if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {\r
11015                            var eValue = scope.member.onExpand(scope.member);\r
11016                         }\r
11017                         if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {\r
11018                             scope.member.onCollapse(scope.member);\r
11019                         }\r
11020                 });\r
11021             }\r
11022         }\r
11023 }])\r
11024     .directive('b2bTreeLink', ['keymap', '$timeout', function (keymap, $timeout) {\r
11025         return {\r
11026             restrict: 'A',\r
11027             link: function (scope, element, attr, ctrl) {\r
11028                 var rootE, parentE, upE, downE;\r
11029                 var closeOthersUp = function (elem,isKeyPress,passiveClose) {\r
11030                     //For accordion functionality on sibling nodes\r
11031                     if (elem.find('a').eq(0).hasClass('active')) {\r
11032                         activeToggle(elem,isKeyPress,passiveClose);\r
11033                         return;\r
11034                     }\r
11035                     if (elem.hasClass('bg') && !isKeyPress) {\r
11036                         elem.removeClass('bg');\r
11037                         if (elem.attr('aria-selected')) {\r
11038                             elem.attr('aria-selected', 'false');\r
11039                         }                        \r
11040                     }\r
11041                     if (elem[0].previousElementSibling !== null) {\r
11042                         closeOthersUp(angular.element(elem[0].previousElementSibling),isKeyPress);\r
11043                     }\r
11044                 };\r
11045                 var closeOthersDown = function (elem,isKeyPress,passiveClose) {\r
11046                     //For accordion functionality on sibling nodes\r
11047                     if (elem.find('a').eq(0).hasClass('active')) {\r
11048                         activeToggle(elem,isKeyPress,passiveClose);\r
11049                         return;\r
11050                     }\r
11051                     if (elem.hasClass('bg') && !isKeyPress) {\r
11052                         elem.removeClass('bg');\r
11053                         if (elem.attr('aria-selected')) {\r
11054                             elem.attr('aria-selected', 'false');\r
11055                         }                        \r
11056                     }\r
11057                     if (elem[0].nextElementSibling !== null) {\r
11058                         closeOthersDown(angular.element(elem[0].nextElementSibling),isKeyPress);\r
11059                     }\r
11060                 };\r
11061 \r
11062                \r
11063                 var removeBackground = function(elem){\r
11064 \r
11065                     if(elem.hasClass('b2b-tree')){\r
11066                         angular.element(elem[0].getElementsByClassName('bg')).removeClass('bg');\r
11067                         return;\r
11068                     }else{\r
11069                         removeBackground(elem.parent().parent());\r
11070                     }\r
11071 \r
11072                 };\r
11073 \r
11074 /**\r
11075 * These two functions used for setting heights on parent nodes as the child node closes\r
11076 * Retaining this code for future reference\r
11077 \r
11078                 var addParentHeight = function(e, h) {\r
11079                     var parentLi = e.parent().parent();\r
11080                     var parentUl = e.parent();\r
11081                     if(!parentLi.hasClass('b2b-tree')) {\r
11082                         var addHeight = parentUl[0].offsetHeight + h;\r
11083                         parentLi.find('ul').eq(0).css({\r
11084                             height: addHeight+'px'\r
11085                         })\r
11086                         addParentHeight(parentLi, h);\r
11087                     }                    \r
11088                 };\r
11089 \r
11090                 var removeParentHeight = function(e, h) {\r
11091                     var parentLi = e.parent().parent();\r
11092                     var parentUl = e.parent();\r
11093                     if(!parentLi.hasClass('b2b-tree')) {\r
11094                         var addHeight = parentUl[0].offsetHeight - h;\r
11095                         parentLi.find('ul').eq(0).css({\r
11096                             height: addHeight+'px'\r
11097                         })\r
11098                         removeParentHeight(parentLi, h);\r
11099                     }\r
11100                 };\r
11101 */          \r
11102 \r
11103             // isKeyPress - to notify that the function is called by Right Key press\r
11104             // passiveClose -  prevents firing of oncollapse events during the action\r
11105             // of expand function(check the function definition)\r
11106 \r
11107                 var activeToggle = function (elem,isKeyPress,passiveClose) {\r
11108                     var element = elem.find('a').eq(0);\r
11109                     if (element.hasClass('active')) {\r
11110                         if(!isKeyPress){\r
11111                             elem.removeClass('bg');\r
11112                         }\r
11113                         \r
11114                         if (elem.attr('aria-selected') && !isKeyPress) {\r
11115                             elem.attr('aria-selected', 'false');\r
11116                         }\r
11117                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {\r
11118                             if(isKeyPress && scope.member){\r
11119                                 if (scope.member.onCollapse !== undefined && !passiveClose) {\r
11120                                     scope.member.onCollapse(scope.member);\r
11121                                 }\r
11122                             }\r
11123                             element.removeClass('active');\r
11124                             elem.attr('aria-expanded', 'false');\r
11125                             element.find('i').eq(0).removeClass('icon-primary-expanded');\r
11126                             element.find('i').eq(0).addClass('icon-primary-collapsed');\r
11127                             //For Animation: below commented code is used to manually set height of UL to zero \r
11128                             //retaining code for future reference\r
11129                             /*\r
11130                             var totalHeight = elem.find('ul')[0].scrollHeight;\r
11131                             removeParentHeight(elem, totalHeight);\r
11132                             elem.find('ul').eq(0).css({\r
11133                                 height: null\r
11134                             });*/\r
11135                         }\r
11136                     } else {\r
11137                         if(!isKeyPress){\r
11138                             elem.addClass('bg');\r
11139                             elem.attr('aria-selected', 'true');\r
11140                         }\r
11141                         \r
11142                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {\r
11143                             if(isKeyPress){\r
11144                                 if(typeof scope.showChild === 'function' ){\r
11145                                 scope.showChild();\r
11146                                 }\r
11147                                 if(scope.member){\r
11148                                     if (scope.member.onExpand !== undefined) {\r
11149                                         scope.member.onExpand(scope.member);\r
11150                                     }\r
11151                                 }\r
11152                             }\r
11153                             element.addClass('active');\r
11154                             elem.attr('aria-expanded', 'true');\r
11155                             element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
11156                             element.find('i').eq(0).addClass('icon-primary-expanded');\r
11157                             //For Animation: below commented code is used to manually set height of the ul generatedon the click of parent LI.\r
11158                             //retaining code for future reference\r
11159                             /*                            \r
11160                             var totalHeight = elem.find('ul')[0].scrollHeight;\r
11161                             addParentHeight(elem, totalHeight);\r
11162                             elem.find('ul').eq(0).css({\r
11163                                 height: totalHeight+'px'\r
11164                             });*/\r
11165                             \r
11166                         }\r
11167                     }\r
11168                 };\r
11169                 element.bind('click', function (evt) {\r
11170                     //first we close others and then we open the clicked element\r
11171                     if (element[0].previousElementSibling) {\r
11172                         closeOthersUp(angular.element(element[0].previousElementSibling));\r
11173                     }\r
11174                     if (element[0].nextElementSibling) {\r
11175                         closeOthersDown(angular.element(element[0].nextElementSibling));\r
11176                     }\r
11177                     removeBackground(element);\r
11178                     activeToggle(element);                    \r
11179                     \r
11180                     evt.stopPropagation();                    \r
11181                 });\r
11182                 //default root tree element tabindex set zero\r
11183                 if (element.parent().parent().hasClass('b2b-tree') && (element.parent()[0].previousElementSibling === null)) {\r
11184                     element.attr('tabindex', 0);\r
11185                 }\r
11186                 //check root via class\r
11187                 var isRoot = function (elem) {\r
11188                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {\r
11189                         return true;\r
11190                     } else {\r
11191                         return false;\r
11192                     }\r
11193                 };\r
11194                 var findRoot = function (elem) {\r
11195                     if (isRoot(elem)) {\r
11196                         rootE = elem;\r
11197                         return;\r
11198                     }\r
11199                     findRoot(elem.parent());\r
11200                 };\r
11201 \r
11202                 var findPreActive = function (elem) {\r
11203 \r
11204                     if (!(elem.hasClass("active"))) {\r
11205                         return;\r
11206                     } else {\r
11207                         var childElems = angular.element(elem[0].nextElementSibling.children);\r
11208                         lastE = angular.element(childElems[childElems.length - 1]);\r
11209                         if (lastE.find('a').eq(0).hasClass('active')) {\r
11210                             findPreActive(lastE.find('a').eq(0));\r
11211                         }\r
11212                         upE = lastE;\r
11213                     }\r
11214                 };\r
11215 \r
11216                 var findUp = function (elem) {\r
11217                     if (isRoot(elem)) {\r
11218                         upE = elem;\r
11219                         return;\r
11220                     }\r
11221                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {\r
11222                         upE = angular.element(elem[0].previousElementSibling);\r
11223                         if (upE.find('a').eq(0).hasClass('active')) {\r
11224                             findPreActive(upE.find('a').eq(0));\r
11225                         }\r
11226                     } else {\r
11227                         upE = elem.parent().parent();\r
11228                     }\r
11229                 };\r
11230 \r
11231                 var downElement = function (elem) {\r
11232                     if (elem.next().hasClass('tree-hide')) {\r
11233                         downElement(elem.next());\r
11234                     } else {\r
11235                         downE = elem.next();\r
11236                     }\r
11237                 }\r
11238                 var isBottomElem = false;\r
11239                 var downParent = function(liElem){\r
11240                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree')){\r
11241                         isBottomElem = true;\r
11242                         return;\r
11243                     }\r
11244                     if(liElem.next().length !== 0){\r
11245                         downE = liElem.next().eq(0);\r
11246                         return;\r
11247                     }\r
11248                     else {\r
11249                         downParent(liElem.parent().parent());\r
11250                     }\r
11251                 }\r
11252                 \r
11253                 var findDown = function (elem) {\r
11254                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {\r
11255                         downE = elem.parent();\r
11256                         return;\r
11257                     }\r
11258                     if (elem.hasClass('active')) {\r
11259                         downE = elem.next().find('li').eq(0);\r
11260                         if (downE.hasClass('tree-hide')) {\r
11261                             downElement(downE);\r
11262                         }\r
11263 \r
11264                     } else {\r
11265                         downParent(elem.parent());\r
11266                         if(isBottomElem === true){\r
11267                             downE = elem.parent();\r
11268                             isBottomElem = false;\r
11269                         }\r
11270                     }\r
11271                 };\r
11272 \r
11273 \r
11274                 var resetTabPosition = function(element){\r
11275                     findRoot(element);\r
11276                     angular.element(rootE.parent().parent()[0].querySelector("li[tabindex='0']")).attr('tabindex','-1');\r
11277                     var elemToFocus =  rootE.parent().parent()[0].querySelector(".bg")|| rootE;\r
11278 \r
11279                     angular.element(elemToFocus).attr('tabindex','0');\r
11280                 };\r
11281                 // Function to control the expansion of nodes when the user tabs into the tree and\r
11282                 // the slected node is not visible\r
11283                 var expand = function(elemArr){\r
11284                     var elem= elemArr.pop();\r
11285                     var element = elem.find('a').eq(0);                    \r
11286                     var selectedNode = elem.parent().parent()[0].querySelector(".bg");\r
11287                     if(selectedNode != null){\r
11288                         while(elem){\r
11289                              element = elem.find('a').eq(0);\r
11290                     if(!element.hasClass('active') ){\r
11291 \r
11292 \r
11293                     if (elem[0].previousElementSibling) {\r
11294                         closeOthersUp(angular.element(elem[0].previousElementSibling),true,true);\r
11295                         }\r
11296                         if (elem[0].nextElementSibling) {\r
11297                             closeOthersDown(angular.element(elem[0].nextElementSibling),true,true);\r
11298                         }\r
11299 \r
11300                          if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {\r
11301                             if(typeof scope.showChild === 'function' ){\r
11302                                 scope.showChild();\r
11303                             }\r
11304                             element.addClass('active');\r
11305                             elem.attr('aria-expanded', 'true');\r
11306                             element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
11307                             element.find('i').eq(0).addClass('icon-primary-expanded');\r
11308                             }\r
11309                           \r
11310                           }   \r
11311                           elem = elemArr.pop();\r
11312                         }                      \r
11313                         \r
11314                     }else{\r
11315                         return;\r
11316                     }                   \r
11317                 };\r
11318 \r
11319                 element.find('a').eq(0).bind('mouseenter', function (evt) {\r
11320                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {\r
11321                         angular.element(value).removeClass('activeTooltip') \r
11322                     });\r
11323                     element.addClass('activeTooltip');\r
11324                 });\r
11325                 element.find('a').eq(0).bind('mouseleave', function (evt) {\r
11326                     element.removeClass('activeTooltip');\r
11327                 });\r
11328                 element.bind('focus', function (evt) {\r
11329                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {\r
11330                         angular.element(value).removeClass('activeTooltip') \r
11331                     });\r
11332                     element.addClass('activeTooltip');\r
11333                 });\r
11334                 element.bind('blur', function (evt) {\r
11335                     element.removeClass('activeTooltip');\r
11336                 });\r
11337                 element.bind('keydown', function (evt) {\r
11338                     switch (evt.keyCode) {\r
11339                     case keymap.KEY.HOME:\r
11340                         evt.preventDefault();\r
11341                         evt.stopPropagation();\r
11342                         element.attr('tabindex', -1);\r
11343                         findRoot(element);\r
11344                         rootE.eq(0).attr('tabindex', 0);\r
11345                         rootE[0].focus();\r
11346                         break;\r
11347                     case keymap.KEY.LEFT:\r
11348                         evt.preventDefault();\r
11349                         evt.stopPropagation(); \r
11350                       \r
11351                         if(element.find('a').eq(0).hasClass('active')){\r
11352                             if (element[0].previousElementSibling) {\r
11353                                 closeOthersUp(angular.element(element[0].previousElementSibling),true);\r
11354                             }\r
11355                             if (element[0].nextElementSibling) {\r
11356                                 closeOthersDown(angular.element(element[0].nextElementSibling),true);\r
11357                              }\r
11358                              activeToggle(element,true);\r
11359                                 return;\r
11360                         }\r
11361                             element.attr('tabindex', -1);\r
11362                             parentE = element.parent().parent();\r
11363                             parentE.attr('tabindex', 0);\r
11364                             parentE[0].focus();\r
11365                         break;\r
11366                     case keymap.KEY.UP:\r
11367                         evt.preventDefault();\r
11368                         evt.stopPropagation();\r
11369                         element.attr('tabindex', -1);\r
11370                         findUp(element);\r
11371                         upE.eq(0).attr('tabindex', 0);\r
11372                         upE[0].focus();\r
11373                         break;\r
11374                     case keymap.KEY.RIGHT:\r
11375                         evt.preventDefault();\r
11376                         evt.stopPropagation();\r
11377                         if(element.find('i').eq(0).hasClass('icon-primary-circle')){\r
11378                             break;\r
11379                         }    \r
11380                         if (!element.find('a').eq(0).hasClass('active')) {\r
11381                             if (element[0].previousElementSibling) {\r
11382                         closeOthersUp(angular.element(element[0].previousElementSibling),true);\r
11383                         }\r
11384                         if (element[0].nextElementSibling) {\r
11385                             closeOthersDown(angular.element(element[0].nextElementSibling),true);\r
11386                         }\r
11387                         activeToggle(element,true);\r
11388                     \r
11389                         }\r
11390                         else {\r
11391                             element.attr('tabindex', -1);\r
11392                             findDown(element.find('a').eq(0));\r
11393                             downE.eq(0).attr('tabindex', 0);\r
11394                             downE[0].focus();                            \r
11395                         }                        \r
11396                         break;\r
11397                     case keymap.KEY.DOWN:\r
11398                         evt.preventDefault();\r
11399                         element.attr('tabindex', -1);\r
11400                         findDown(element.find('a').eq(0));\r
11401                         downE.eq(0).attr('tabindex', 0);\r
11402                         downE[0].focus();\r
11403                         evt.stopPropagation();\r
11404                         break;\r
11405                     case keymap.KEY.ENTER:\r
11406                         var isSelectedElem = element.hasClass('bg');\r
11407                         var enterFunc = function(element){\r
11408                             if (isSelectedElem) {\r
11409                                 element.removeClass('bg');\r
11410                                 if (element.attr('aria-selected')) {\r
11411                                     element.attr('aria-selected', 'false');\r
11412                                 }                        \r
11413                             }\r
11414                             else {\r
11415                                 element.addClass('bg');\r
11416                                 element.attr('aria-selected', 'true');                                   \r
11417                             }  \r
11418                         };                            \r
11419                         if (element[0].previousElementSibling) {\r
11420                             closeOthersUp(angular.element(element[0].previousElementSibling));\r
11421                         }\r
11422                         if (element[0].nextElementSibling) {\r
11423                             closeOthersDown(angular.element(element[0].nextElementSibling));\r
11424                         }                   \r
11425                         \r
11426                         removeBackground(element);\r
11427                         enterFunc(element);\r
11428                         evt.stopPropagation();                                                      \r
11429                         break;\r
11430                     case keymap.KEY.TAB:\r
11431                         $timeout(function(){\r
11432                             resetTabPosition(element);\r
11433                         },0);\r
11434                          evt.stopPropagation(); \r
11435                         \r
11436                         break;\r
11437                     default:\r
11438                         break;\r
11439                     }\r
11440                 });\r
11441             element.bind('keyup',function(evt){\r
11442                 if(evt.keyCode === keymap.KEY.TAB){\r
11443                   \r
11444                         var tempElem = element;\r
11445                         var elemArr = [];\r
11446                         while(!tempElem.hasClass('b2b-tree')){\r
11447                             elemArr.push(tempElem);\r
11448                             tempElem = tempElem.parent().parent();\r
11449                         }\r
11450                         elemArr.push(tempElem);\r
11451                       \r
11452                         expand(elemArr);                    \r
11453                 }\r
11454                  evt.stopPropagation(); \r
11455             });\r
11456             }\r
11457         };\r
11458     }]);\r
11459 /**\r
11460  * @ngdoc directive\r
11461  * @name Navigation.att:Tree nodes with checkboxes\r
11462  *\r
11463  * @param {String} setRole - The value needs to be "tree". This is required to incorporate CATO requirements.\r
11464  * @param {boolean} groupIt - The value needs to be "false" for top-level tree rendered. \r
11465  * @param {Object} collection -  The JSON object of tree to be rendered.\r
11466  * @description\r
11467  *  <file src="src/treeNodeCheckbox/docs/readme.md" />\r
11468  *\r
11469  * @usage\r
11470  *      <div class="b2b-tree-checkbox">\r
11471  *                <b2b-tree-node-checkbox collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-node-checkbox>\r
11472  *            </div>\r
11473  * @example\r
11474  *  <section id="code">\r
11475         <example module="b2b.att">\r
11476             <file src="src/treeNodeCheckbox/docs/demo.html" />\r
11477             <file src="src/treeNodeCheckbox/docs/demo.js" />\r
11478        </example>\r
11479     </section>\r
11480  *\r
11481  */\r
11482 angular.module('b2b.att.treeNodeCheckbox', ['b2b.att.utilities'])\r
11483     .directive('b2bTreeNodeCheckbox', function () {\r
11484         return {\r
11485             restrict: "E",\r
11486             replace: true,\r
11487             scope: {\r
11488                 collection: '=',\r
11489                 groupIt: '=',\r
11490                 setRole: '@'\r
11491             },\r
11492             templateUrl: function (element, attrs) {\r
11493                 if (attrs.groupIt === 'true') {\r
11494                     return "b2bTemplate/treeNodeCheckbox/groupedTree.html";\r
11495                 } else {\r
11496                     return "b2bTemplate/treeNodeCheckbox/ungroupedTree.html";\r
11497                 }\r
11498             },\r
11499             link: function (scope) {\r
11500                 if (!(scope.setRole === 'tree')) {\r
11501                     scope.setRole = 'group';\r
11502                 }\r
11503             }\r
11504         }\r
11505     })\r
11506     .directive('b2bTreeMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {\r
11507         return {\r
11508             restrict: "E",\r
11509             replace: true,\r
11510             scope: {\r
11511                 member: '=',\r
11512                 groupIt: '='\r
11513             },\r
11514             templateUrl: 'b2bTemplate/treeNodeCheckbox/treeMember.html',\r
11515             link: function (scope, element, attrs) {\r
11516                 scope.elemArr = [];\r
11517                 var removeRootTabIndex = function (elem) {\r
11518                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {\r
11519                         elem.attr('tabindex', -1);                        \r
11520                         return;\r
11521                     }\r
11522                     removeRootTabIndex(elem.parent());\r
11523                 };\r
11524                 scope.$watch('member.child', function(newVal, oldVal){                  \r
11525                     if(newVal !== oldVal){\r
11526                         scope.showChild();\r
11527                     };\r
11528                 });\r
11529 \r
11530                 var checkedCount = 0;\r
11531                 var nonCheckedCount = 0;\r
11532                 var checkBoxesCount = 0;\r
11533 \r
11534                 if(element.find('a').eq(0).find('input')){\r
11535                     if(scope.member.indeterminate){\r
11536                         element.find('a').eq(0).find('input').prop('indeterminate', true);\r
11537                         element.attr('aria-checked',"mixed");\r
11538                     }\r
11539                     element.attr('aria-checked',scope.member.isSelected);\r
11540                 }\r
11541 \r
11542                 element.find('a').eq(0).find('input').bind('change',function(){\r
11543                     scope.member.indeterminate = false;\r
11544                     downwardModalUpdate(scope.member);\r
11545                     downwardSelection(element);\r
11546                     upwardSelection(element);\r
11547                     element.attr('aria-checked',scope.member.isSelected);\r
11548                      if (scope.member.onSelect !== undefined) {\r
11549                         scope.member.onSelect(scope.member);\r
11550                     }\r
11551                 });\r
11552 \r
11553                 element.find('a').eq(0).find('input').bind('click',function(){\r
11554                     var elem = angular.element(this);\r
11555                     if(scope.member.indeterminate){\r
11556                         scope.member.indeterminate = false;\r
11557                         scope.member.isSelected = true;\r
11558                         elem.prop('indeterminate', false);\r
11559                         elem.prop('checked', true);\r
11560                         elem.triggerHandler('change');\r
11561                     }\r
11562                 });\r
11563 \r
11564                 var groupNode = false;\r
11565                 var checkedTreeNode = false;\r
11566 \r
11567                 var isCheckboxSelected = function(elem){\r
11568                     checkedTreeNode = false;\r
11569                     checkedTreeNode = angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked;\r
11570                 }\r
11571 \r
11572                 var findCheckbox = function(elem){\r
11573                     return angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox');\r
11574                 }\r
11575 \r
11576                 var updateGrpNodeCheckboxes = function(elem, checked){\r
11577                     angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked = checked;\r
11578                 }\r
11579 \r
11580                 \r
11581                 var isGroupNode = function(elem){\r
11582                     groupNode = false;\r
11583                     if(angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.grpTreeCheckbox')){\r
11584                         groupNode = true;\r
11585                     }\r
11586                 }\r
11587 \r
11588                 var downwardModalUpdate = function(curMember){\r
11589                     angular.forEach(curMember.child, function(childMember, key) {\r
11590                         childMember.isSelected = curMember.isSelected;\r
11591                         childMember.indeterminate = false;\r
11592                         if(angular.isArray(childMember.child) && scope.member.child.length > 0){\r
11593                             downwardModalUpdate(childMember);\r
11594                         }\r
11595                     });\r
11596                 }\r
11597 \r
11598                 var downwardSelection = function(elem){\r
11599                     if(findCheckbox(elem)){\r
11600                         isCheckboxSelected(elem)\r
11601                     } \r
11602                     if(angular.element(elem).find('ul').length > 0){\r
11603                         var childNodes = angular.element(elem).find('ul').eq(0).children('li');\r
11604                         for(var i=0; i<childNodes.length; i++){\r
11605                             if(findCheckbox(childNodes[i])){\r
11606                                 isGroupNode(childNodes[i]);\r
11607                                 angular.element(findCheckbox(childNodes[i])).prop('indeterminate', false);\r
11608                                 angular.element(childNodes[i]).attr('aria-checked',checkedTreeNode);\r
11609                                 if(groupNode){\r
11610                                     updateGrpNodeCheckboxes(childNodes[i],checkedTreeNode);\r
11611                                 }else{\r
11612                                     angular.element(childNodes[i]).scope().member.isSelected = checkedTreeNode;\r
11613                                     angular.element(childNodes[i]).scope().member.indeterminate = false\r
11614                                     angular.element(childNodes[i]).scope().$apply();\r
11615                                 }\r
11616                                 downwardSelection(childNodes[i]);\r
11617                             }\r
11618                         }\r
11619 \r
11620                     }\r
11621                 }\r
11622                 var upwardSelection = function(elem){\r
11623                     var childNodes = elem.parent().parent().find('ul').eq(0).children('li');\r
11624                     checkedCount = 0;\r
11625                     nonCheckedCount = 0;\r
11626                     checkBoxesCount = 0;    \r
11627                     for(i=0; i<childNodes.length; i++){\r
11628                         if(findCheckbox(childNodes[i])){\r
11629                             isGroupNode(childNodes[i]);\r
11630                             isCheckboxSelected(childNodes[i]);\r
11631                             checkBoxesCount++;\r
11632                             if(checkedTreeNode){\r
11633                                 checkedCount++;\r
11634                             }else if(!angular.element(angular.element(angular.element(childNodes[i]).find('a').eq(0))[0].querySelector('input.treeCheckBox')).prop('indeterminate')){\r
11635                                 nonCheckedCount++;\r
11636                             }\r
11637                         }\r
11638                     }\r
11639                     var parentNodeScope;\r
11640                     parentNodeScope = angular.element(elem.parent().parent()).scope();\r
11641                     if(findCheckbox(elem.parent().parent())){\r
11642                         if(nonCheckedCount == checkBoxesCount){\r
11643                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);\r
11644                             if(parentNodeScope &&  parentNodeScope.member){\r
11645                                 parentNodeScope.member.isSelected = false;\r
11646                                 parentNodeScope.member.indeterminate = false;\r
11647                             }else{\r
11648                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);\r
11649                             }\r
11650                             angular.element(elem.parent().parent()).attr('aria-checked',false);\r
11651                         }else if(checkedCount == checkBoxesCount){\r
11652                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);\r
11653                             if(parentNodeScope &&  parentNodeScope.member){\r
11654                                 parentNodeScope.member.isSelected = true;\r
11655                                 parentNodeScope.member.indeterminate = false;\r
11656                             }else{\r
11657                                 updateGrpNodeCheckboxes(elem.parent().parent(),true);\r
11658                             }\r
11659                             angular.element(elem.parent().parent()).attr('aria-checked',true);\r
11660                         }else{\r
11661                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', true);\r
11662                             if(parentNodeScope &&  parentNodeScope.member){\r
11663                                 parentNodeScope.member.isSelected = false;\r
11664                                 parentNodeScope.member.indeterminate = true;\r
11665                             }else{\r
11666                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);\r
11667                             }\r
11668                             angular.element(elem.parent().parent()).attr('aria-checked',"mixed");\r
11669                         }\r
11670                         if(parentNodeScope &&  parentNodeScope.member){\r
11671                             parentNodeScope.$apply();\r
11672                         }        \r
11673                     }\r
11674                     \r
11675                     \r
11676                     \r
11677                     if(elem.parent().parent().attr('role') == "treeitem"){\r
11678                         upwardSelection(elem.parent().parent());\r
11679                     }\r
11680                 }\r
11681 \r
11682                 scope.showChild = function () {\r
11683                         if (!element.hasClass('grouped')) {\r
11684                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {\r
11685                                 scope.groupIt = false;\r
11686                                 element.addClass('grouped');\r
11687                                 element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");\r
11688                                 $compile(element.contents())(scope);\r
11689                                 if(scope.member.active && scope.member.active === true){\r
11690                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');\r
11691                                 };\r
11692                                 if(scope.member.selected && scope.member.selected === true){\r
11693                                     element.attr('tabindex', 0);\r
11694                                     removeRootTabIndex(element);\r
11695                                 };\r
11696                                 if(scope.member.active && scope.member.active == undefined){\r
11697                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11698                                 };\r
11699                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {\r
11700                                 element.addClass('grouped');\r
11701                                 scope.groupIt = true;\r
11702                                 var j = 0;\r
11703                                 var grpName = '';\r
11704                                 if(scope.member.child[0].groupName !== undefined){\r
11705                                     grpName = scope.member.child[0].groupName;\r
11706                                 }\r
11707                                 else{\r
11708                                     var toSlice = scope.member.child[0].name.search(' ');\r
11709                                     grpName = scope.member.child[0].name.slice(0, toSlice);\r
11710                                 }\r
11711 \r
11712                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {\r
11713                                     j = 0;\r
11714                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        \r
11715                                         if (j === scope.member.child.length) {\r
11716                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
11717                                             break;\r
11718                                             \r
11719                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){\r
11720                                                 scope.member.child[j-1].activeGrp = true;\r
11721                                             };\r
11722                                             \r
11723                                         }\r
11724                                         if (i + scope.member.divide > scope.member.child.length) {\r
11725                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
11726                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
11727                                                 scope.member.child[j].activeGrp = true;\r
11728                                             };\r
11729 \r
11730                                         } else {\r
11731                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);\r
11732                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
11733                                                 scope.member.child[j].activeGrp = true;\r
11734                                             };\r
11735                                         }\r
11736                                     }\r
11737                                 }\r
11738                                 if(scope.member.divide){\r
11739                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");\r
11740                                 } else {\r
11741                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");\r
11742                                 }\r
11743                                 $compile(element.contents())(scope);\r
11744                                 if(scope.member.active && scope.member.active === true){\r
11745                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');\r
11746                                 };\r
11747                                 \r
11748                                 if( scope.member.active && scope.member.active == undefined){\r
11749                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11750                                 };\r
11751                             }\r
11752                         }\r
11753                         $timeout(function () {\r
11754                             if(!scope.member.indeterminate){\r
11755                                 downwardSelection(element);\r
11756                             }    \r
11757                         });  \r
11758 \r
11759                 };\r
11760                 \r
11761                 if(scope.member.active && scope.member.active == true){\r
11762                     scope.showChild();\r
11763                 };\r
11764                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){\r
11765                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11766                 }\r
11767                 else if(scope.member.child == undefined){\r
11768                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-circle');\r
11769                     if(scope.$parent.$index === 0) {\r
11770                         element.find('a').eq(0).append('<span class="first-link"></span>');\r
11771                     };\r
11772                 };\r
11773                 \r
11774                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {\r
11775                     scope.showChild();\r
11776                     var expandFunc = scope.member.onExpand;\r
11777                     if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {\r
11778                        var eValue = scope.member.onExpand(scope.member);\r
11779                     }\r
11780                     if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {\r
11781                         scope.member.onCollapse(scope.member);\r
11782                     }\r
11783                 });\r
11784 \r
11785                 angular.element(element[0].querySelectorAll('.treeNodeName')).eq(0).bind('click', function (evt) {\r
11786 \r
11787                 });\r
11788                 \r
11789             }\r
11790         }\r
11791 }])\r
11792     .directive('b2bTreeNodeLink', ['keymap', '$timeout', function (keymap, $timeout) {\r
11793         return {\r
11794             restrict: 'A',\r
11795             link: function (scope, element, attr, ctrl) {\r
11796                 var rootE, parentE, upE, downE;\r
11797                 var closeOthersUp = function (elem) {\r
11798                     \r
11799                     if (elem.find('a').eq(0).hasClass('active')) {\r
11800                         activeToggle(elem);\r
11801                         return;\r
11802                     }\r
11803                     if (elem.hasClass('bg')) {\r
11804                         elem.removeClass('bg');\r
11805                     }\r
11806                     if (elem[0].previousElementSibling !== null) {\r
11807                         closeOthersUp(angular.element(elem[0].previousElementSibling));\r
11808                     }\r
11809                 };\r
11810                 var closeOthersDown = function (elem) {\r
11811                     \r
11812                     if (elem.find('a').eq(0).hasClass('active')) {\r
11813                         activeToggle(elem);\r
11814                         return;\r
11815                     }\r
11816                     if (elem.hasClass('bg')) {\r
11817                         elem.removeClass('bg');\r
11818                     }\r
11819                     if (elem[0].nextElementSibling !== null) {\r
11820                         closeOthersDown(angular.element(elem[0].nextElementSibling));\r
11821                     }\r
11822                 };\r
11823 \r
11824                 var removeBackgroundUp = function (elem) {\r
11825                     \r
11826                     if (elem.hasClass('b2b-tree-checkbox')) {\r
11827                         return;\r
11828                     } else {\r
11829                         elem.parent().parent().removeClass('bg');\r
11830                         removeBackgroundUp(elem.parent().parent());\r
11831                     }\r
11832                 };\r
11833 \r
11834                 var removeBackgroundDown = function (elem) {\r
11835                     \r
11836                     angular.element(elem[0].querySelector('.bg')).removeClass('bg');\r
11837                 };\r
11838 \r
11839 \r
11840 \r
11841                 var activeToggle = function (elem) {\r
11842                     var element = elem.find('a').eq(0);\r
11843                     if (element.hasClass('active')) {\r
11844                         elem.removeClass('bg');\r
11845                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {\r
11846                             element.removeClass('active');\r
11847                             elem.attr('aria-expanded', 'false');\r
11848                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-expanded');\r
11849                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11850                         }\r
11851                     } else {\r
11852                         elem.addClass('bg');\r
11853                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {\r
11854                             element.addClass('active');\r
11855                             elem.attr('aria-expanded', 'true');\r
11856                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');\r
11857                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-expanded');\r
11858                         }\r
11859                     }\r
11860                 };\r
11861                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {\r
11862                     \r
11863                         if (element[0].previousElementSibling) {\r
11864                             closeOthersUp(angular.element(element[0].previousElementSibling));\r
11865                         }\r
11866                         if (element[0].nextElementSibling) {\r
11867                             closeOthersDown(angular.element(element[0].nextElementSibling));\r
11868                         }\r
11869 \r
11870                         activeToggle(element);\r
11871 \r
11872                     removeBackgroundDown(element);\r
11873                     removeBackgroundUp(element);\r
11874                     evt.stopPropagation();                    \r
11875                 });\r
11876                 \r
11877                 if (element.parent().parent().hasClass('b2b-tree-checkbox') && (element.parent()[0].previousElementSibling === null)) {\r
11878                     element.attr('tabindex', 0);\r
11879                 }\r
11880                 \r
11881                 var isRoot = function (elem) {\r
11882                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {\r
11883                         return true;\r
11884                     } else {\r
11885                         return false;\r
11886                     }\r
11887                 };\r
11888                 var findRoot = function (elem) {\r
11889                     if (isRoot(elem)) {\r
11890                         rootE = elem;\r
11891                         return;\r
11892                     }\r
11893                     findRoot(elem.parent());\r
11894                 };\r
11895 \r
11896                 var findPreActive = function (elem) {\r
11897 \r
11898                     if (!(elem.hasClass("active"))) {\r
11899                         return;\r
11900                     } else {\r
11901                         var childElems = angular.element(elem[0].nextElementSibling.children);\r
11902                         lastE = angular.element(childElems[childElems.length - 1]);\r
11903                         if (lastE.find('a').eq(0).hasClass('active')) {\r
11904                             findPreActive(lastE.find('a').eq(0));\r
11905                         }\r
11906                         upE = lastE;\r
11907                     }\r
11908                 };\r
11909 \r
11910                 var findUp = function (elem) {\r
11911                     if (isRoot(elem)) {\r
11912                         upE = elem;\r
11913                         return;\r
11914                     }\r
11915                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {\r
11916                         upE = angular.element(elem[0].previousElementSibling);\r
11917                         if (upE.find('a').eq(0).hasClass('active')) {\r
11918                             findPreActive(upE.find('a').eq(0));\r
11919                         }\r
11920                     } else {\r
11921                         upE = elem.parent().parent();\r
11922                     }\r
11923                 };\r
11924 \r
11925                 var downElement = function (elem) {\r
11926                     if (elem.next().hasClass('tree-hide')) {\r
11927                         downElement(elem.next());\r
11928                     } else {\r
11929                         downE = elem.next();\r
11930                     }\r
11931                 }\r
11932                 var isBottomElem = false;\r
11933                 var downParent = function(liElem){\r
11934                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree-checkbox')){\r
11935                         isBottomElem = true;\r
11936                         return;\r
11937                     }\r
11938                     if(liElem.next().length !== 0){\r
11939                         downE = liElem.next().eq(0);\r
11940                         return;\r
11941                     }\r
11942                     else {\r
11943                         downParent(liElem.parent().parent());\r
11944                     }\r
11945                 }\r
11946                 \r
11947                 var findDown = function (elem) {\r
11948                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {\r
11949                         downE = elem.parent();\r
11950                         return;\r
11951                     }\r
11952                     if (elem.hasClass('active')) {\r
11953                         downE = elem.next().find('li').eq(0);\r
11954                         if (downE.hasClass('tree-hide')) {\r
11955                             downElement(downE);\r
11956                         }\r
11957 \r
11958                     } else {\r
11959                         downParent(elem.parent());\r
11960                         if(isBottomElem === true){\r
11961                             downE = elem.parent();\r
11962                             isBottomElem = false;\r
11963                         }\r
11964                     }\r
11965                 };\r
11966                 element.bind('keydown', function (evt) {\r
11967                     switch (evt.keyCode) {\r
11968                     case keymap.KEY.HOME:\r
11969                         evt.preventDefault();\r
11970                         evt.stopPropagation();\r
11971                         element.attr('tabindex', -1);\r
11972                         findRoot(element);\r
11973                         rootE.eq(0).attr('tabindex', 0);\r
11974                         rootE[0].focus();\r
11975                         break;\r
11976                     case keymap.KEY.LEFT:\r
11977                         evt.preventDefault();\r
11978                         evt.stopPropagation();\r
11979                         if (!isRoot(element)) {\r
11980                             if(element.find('a').eq(0).hasClass('active')){\r
11981                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');\r
11982                                 return;\r
11983                             }\r
11984                             element.attr('tabindex', -1);\r
11985                             parentE = element.parent().parent();\r
11986                             parentE.attr('tabindex', 0);\r
11987                             parentE[0].focus();\r
11988                         } else {\r
11989                             if (element.find('a').eq(0).hasClass('active')) {\r
11990                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');\r
11991                             }\r
11992                         };\r
11993                         break;\r
11994                     case keymap.KEY.UP:\r
11995                         evt.preventDefault();\r
11996                         evt.stopPropagation();\r
11997                         element.attr('tabindex', -1);\r
11998                         findUp(element);\r
11999                         upE.eq(0).attr('tabindex', 0);\r
12000                         upE[0].focus();\r
12001                         break;\r
12002                     case keymap.KEY.RIGHT:\r
12003                         evt.preventDefault();\r
12004                         evt.stopPropagation();\r
12005                         if(angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')){\r
12006                             break;\r
12007                         }    \r
12008                         if (!element.find('a').eq(0).hasClass('active')) {\r
12009                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');\r
12010                         }\r
12011                         else {\r
12012                             element.attr('tabindex', -1);\r
12013                             findDown(element.find('a').eq(0));\r
12014                             downE.eq(0).attr('tabindex', 0);\r
12015                             downE[0].focus();                            \r
12016                         }                        \r
12017                         break;\r
12018                     case keymap.KEY.DOWN:\r
12019                         evt.preventDefault();\r
12020                         element.attr('tabindex', -1);\r
12021                         findDown(element.find('a').eq(0));\r
12022                         downE.eq(0).attr('tabindex', 0);\r
12023                         downE[0].focus();\r
12024                         evt.stopPropagation();\r
12025                         break;\r
12026                     case keymap.KEY.SPACE:\r
12027                     case keymap.KEY.ENTER:\r
12028                         evt.preventDefault();\r
12029                         evt.stopPropagation();\r
12030                         if(angular.isDefined(element.scope().member.isSelected)){\r
12031                             element.scope().member.isSelected = !element.scope().member.isSelected;\r
12032                             element.scope().member.indeterminate = false;\r
12033                             element.scope().$apply();\r
12034                             element.find('a').eq(0).find('input').prop('indeterminate', false);\r
12035                             element.find('a').eq(0).find('input').triggerHandler('change');\r
12036                         }\r
12037                         break;    \r
12038                     default:\r
12039                         break;\r
12040                     }\r
12041                 });\r
12042             }\r
12043         };\r
12044     }]);\r
12045 /*!\r
12046  * VERSION: 1.7.3\r
12047  * DATE: 2014-01-14\r
12048  * UPDATES AND DOCS AT: http://www.greensock.com\r
12049  *\r
12050  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r
12051  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r
12052  * Club GreenSock members, the software agreement that was issued with your membership.\r
12053  * \r
12054  * @author: Jack Doyle, jack@greensock.com\r
12055  **/\r
12056 (window._gsQueue || (window._gsQueue = [])).push( function() {\r
12057 \r
12058     "use strict";\r
12059 \r
12060     var _doc = document.documentElement,\r
12061         _window = window,\r
12062         _max = function(element, axis) {\r
12063             var dim = (axis === "x") ? "Width" : "Height",\r
12064                 scroll = "scroll" + dim,\r
12065                 client = "client" + dim,\r
12066                 body = document.body;\r
12067             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];\r
12068         },\r
12069 \r
12070         ScrollToPlugin = window._gsDefine.plugin({\r
12071             propName: "scrollTo",\r
12072             API: 2,\r
12073             version:"1.7.3",\r
12074 \r
12075             //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
12076             init: function(target, value, tween) {\r
12077                 this._wdw = (target === _window);\r
12078                 this._target = target;\r
12079                 this._tween = tween;\r
12080                 if (typeof(value) !== "object") {\r
12081                     value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".\r
12082                 }\r
12083                 this._autoKill = (value.autoKill !== false);\r
12084                 this.x = this.xPrev = this.getX();\r
12085                 this.y = this.yPrev = this.getY();\r
12086                 if (value.x != null) {\r
12087                     this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);\r
12088                     this._overwriteProps.push("scrollTo_x");\r
12089                 } else {\r
12090                     this.skipX = true;\r
12091                 }\r
12092                 if (value.y != null) {\r
12093                     this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);\r
12094                     this._overwriteProps.push("scrollTo_y");\r
12095                 } else {\r
12096                     this.skipY = true;\r
12097                 }\r
12098                 return true;\r
12099             },\r
12100 \r
12101             //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.)\r
12102             set: function(v) {\r
12103                 this._super.setRatio.call(this, v);\r
12104 \r
12105                 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,\r
12106                     y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,\r
12107                     yDif = y - this.yPrev,\r
12108                     xDif = x - this.xPrev;\r
12109 \r
12110                 if (this._autoKill) {\r
12111                     //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.\r
12112                     if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {\r
12113                         this.skipX = true; //if the user scrolls separately, we should stop tweening!\r
12114                     }\r
12115                     if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {\r
12116                         this.skipY = true; //if the user scrolls separately, we should stop tweening!\r
12117                     }\r
12118                     if (this.skipX && this.skipY) {\r
12119                         this._tween.kill();\r
12120                     }\r
12121                 }\r
12122                 if (this._wdw) {\r
12123                     _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);\r
12124                 } else {\r
12125                     if (!this.skipY) {\r
12126                         this._target.scrollTop = this.y;\r
12127                     }\r
12128                     if (!this.skipX) {\r
12129                         this._target.scrollLeft = this.x;\r
12130                     }\r
12131                 }\r
12132                 this.xPrev = this.x;\r
12133                 this.yPrev = this.y;\r
12134             }\r
12135 \r
12136         }),\r
12137         p = ScrollToPlugin.prototype;\r
12138 \r
12139     ScrollToPlugin.max = _max;\r
12140 \r
12141     p.getX = function() {\r
12142         return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;\r
12143     };\r
12144 \r
12145     p.getY = function() {\r
12146         return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;\r
12147     };\r
12148 \r
12149     p._kill = function(lookup) {\r
12150         if (lookup.scrollTo_x) {\r
12151             this.skipX = true;\r
12152         }\r
12153         if (lookup.scrollTo_y) {\r
12154             this.skipY = true;\r
12155         }\r
12156         return this._super._kill.call(this, lookup);\r
12157     };\r
12158 \r
12159 }); if (window._gsDefine) { window._gsQueue.pop()(); }\r
12160 /*!\r
12161  * VERSION: 1.12.1\r
12162  * DATE: 2014-06-26\r
12163  * UPDATES AND DOCS AT: http://www.greensock.com\r
12164  * \r
12165  * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin\r
12166  *\r
12167  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r
12168  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r
12169  * Club GreenSock members, the software agreement that was issued with your membership.\r
12170  * \r
12171  * @author: Jack Doyle, jack@greensock.com\r
12172  **/\r
12173 \r
12174 (window._gsQueue || (window._gsQueue = [])).push( function() {\r
12175 \r
12176     "use strict";\r
12177 \r
12178     window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {\r
12179 \r
12180         var _slice = [].slice,\r
12181             TweenMax = function(target, duration, vars) {\r
12182                 TweenLite.call(this, target, duration, vars);\r
12183                 this._cycle = 0;\r
12184                 this._yoyo = (this.vars.yoyo === true);\r
12185                 this._repeat = this.vars.repeat || 0;\r
12186                 this._repeatDelay = this.vars.repeatDelay || 0;\r
12187                 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.\r
12188                 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)\r
12189             },\r
12190             _tinyNum = 0.0000000001,\r
12191             TweenLiteInternals = TweenLite._internals,\r
12192             _isSelector = TweenLiteInternals.isSelector,\r
12193             _isArray = TweenLiteInternals.isArray,\r
12194             p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),\r
12195             _blankArray = [];\r
12196 \r
12197         TweenMax.version = "1.12.1";\r
12198         p.constructor = TweenMax;\r
12199         p.kill()._gc = false;\r
12200         TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;\r
12201         TweenMax.getTweensOf = TweenLite.getTweensOf;\r
12202         TweenMax.lagSmoothing = TweenLite.lagSmoothing;\r
12203         TweenMax.ticker = TweenLite.ticker;\r
12204         TweenMax.render = TweenLite.render;\r
12205 \r
12206         p.invalidate = function() {\r
12207             this._yoyo = (this.vars.yoyo === true);\r
12208             this._repeat = this.vars.repeat || 0;\r
12209             this._repeatDelay = this.vars.repeatDelay || 0;\r
12210             this._uncache(true);\r
12211             return TweenLite.prototype.invalidate.call(this);\r
12212         };\r
12213         \r
12214         p.updateTo = function(vars, resetDuration) {\r
12215             var curRatio = this.ratio, p;\r
12216             if (resetDuration && this._startTime < this._timeline._time) {\r
12217                 this._startTime = this._timeline._time;\r
12218                 this._uncache(false);\r
12219                 if (this._gc) {\r
12220                     this._enabled(true, false);\r
12221                 } else {\r
12222                     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.\r
12223                 }\r
12224             }\r
12225             for (p in vars) {\r
12226                 this.vars[p] = vars[p];\r
12227             }\r
12228             if (this._initted) {\r
12229                 if (resetDuration) {\r
12230                     this._initted = false;\r
12231                 } else {\r
12232                     if (this._gc) {\r
12233                         this._enabled(true, false);\r
12234                     }\r
12235                     if (this._notifyPluginsOfEnabled && this._firstPT) {\r
12236                         TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks\r
12237                     }\r
12238                     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. \r
12239                         var prevTime = this._time;\r
12240                         this.render(0, true, false);\r
12241                         this._initted = false;\r
12242                         this.render(prevTime, true, false);\r
12243                     } else if (this._time > 0) {\r
12244                         this._initted = false;\r
12245                         this._init();\r
12246                         var inv = 1 / (1 - curRatio),\r
12247                             pt = this._firstPT, endValue;\r
12248                         while (pt) {\r
12249                             endValue = pt.s + pt.c; \r
12250                             pt.c *= inv;\r
12251                             pt.s = endValue - pt.c;\r
12252                             pt = pt._next;\r
12253                         }\r
12254                     }\r
12255                 }\r
12256             }\r
12257             return this;\r
12258         };\r
12259                 \r
12260         p.render = function(time, suppressEvents, force) {\r
12261             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.\r
12262                 this.invalidate();\r
12263             }\r
12264             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),\r
12265                 prevTime = this._time,\r
12266                 prevTotalTime = this._totalTime, \r
12267                 prevCycle = this._cycle,\r
12268                 duration = this._duration,\r
12269                 prevRawPrevTime = this._rawPrevTime,\r
12270                 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;\r
12271             if (time >= totalDur) {\r
12272                 this._totalTime = totalDur;\r
12273                 this._cycle = this._repeat;\r
12274                 if (this._yoyo && (this._cycle & 1) !== 0) {\r
12275                     this._time = 0;\r
12276                     this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;\r
12277                 } else {\r
12278                     this._time = duration;\r
12279                     this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;\r
12280                 }\r
12281                 if (!this._reversed) {\r
12282                     isComplete = true;\r
12283                     callback = "onComplete";\r
12284                 }\r
12285                 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.\r
12286                     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.\r
12287                         time = 0;\r
12288                     }\r
12289                     if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {\r
12290                         force = true;\r
12291                         if (prevRawPrevTime > _tinyNum) {\r
12292                             callback = "onReverseComplete";\r
12293                         }\r
12294                     }\r
12295                     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.\r
12296                 }\r
12297                 \r
12298             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
12299                 this._totalTime = this._time = this._cycle = 0;\r
12300                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;\r
12301                 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {\r
12302                     callback = "onReverseComplete";\r
12303                     isComplete = this._reversed;\r
12304                 }\r
12305                 if (time < 0) {\r
12306                     this._active = false;\r
12307                     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.\r
12308                         if (prevRawPrevTime >= 0) {\r
12309                             force = true;\r
12310                         }\r
12311                         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.\r
12312                     }\r
12313                 } 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.\r
12314                     force = true;\r
12315                 }\r
12316             } else {\r
12317                 this._totalTime = this._time = time;\r
12318                 \r
12319                 if (this._repeat !== 0) {\r
12320                     cycleDuration = duration + this._repeatDelay;\r
12321                     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!)\r
12322                     if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {\r
12323                         this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)\r
12324                     }\r
12325                     this._time = this._totalTime - (this._cycle * cycleDuration);\r
12326                     if (this._yoyo) if ((this._cycle & 1) !== 0) {\r
12327                         this._time = duration - this._time;\r
12328                     }\r
12329                     if (this._time > duration) {\r
12330                         this._time = duration;\r
12331                     } else if (this._time < 0) {\r
12332                         this._time = 0;\r
12333                     }\r
12334                 }\r
12335 \r
12336                 if (this._easeType) {\r
12337                     r = this._time / duration;\r
12338                     type = this._easeType;\r
12339                     pow = this._easePower;\r
12340                     if (type === 1 || (type === 3 && r >= 0.5)) {\r
12341                         r = 1 - r;\r
12342                     }\r
12343                     if (type === 3) {\r
12344                         r *= 2;\r
12345                     }\r
12346                     if (pow === 1) {\r
12347                         r *= r;\r
12348                     } else if (pow === 2) {\r
12349                         r *= r * r;\r
12350                     } else if (pow === 3) {\r
12351                         r *= r * r * r;\r
12352                     } else if (pow === 4) {\r
12353                         r *= r * r * r * r;\r
12354                     }\r
12355 \r
12356                     if (type === 1) {\r
12357                         this.ratio = 1 - r;\r
12358                     } else if (type === 2) {\r
12359                         this.ratio = r;\r
12360                     } else if (this._time / duration < 0.5) {\r
12361                         this.ratio = r / 2;\r
12362                     } else {\r
12363                         this.ratio = 1 - (r / 2);\r
12364                     }\r
12365 \r
12366                 } else {\r
12367                     this.ratio = this._ease.getRatio(this._time / duration);\r
12368                 }\r
12369                 \r
12370             }\r
12371                 \r
12372             if (prevTime === this._time && !force && prevCycle === this._cycle) {\r
12373                 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.\r
12374                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
12375                 }\r
12376                 return;\r
12377             } else if (!this._initted) {\r
12378                 this._init();\r
12379                 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.\r
12380                     return;\r
12381                 } 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.\r
12382                     this._time = prevTime;\r
12383                     this._totalTime = prevTotalTime;\r
12384                     this._rawPrevTime = prevRawPrevTime;\r
12385                     this._cycle = prevCycle;\r
12386                     TweenLiteInternals.lazyTweens.push(this);\r
12387                     this._lazy = time;\r
12388                     return;\r
12389                 }\r
12390                 //_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.\r
12391                 if (this._time && !isComplete) {\r
12392                     this.ratio = this._ease.getRatio(this._time / duration);\r
12393                 } else if (isComplete && this._ease._calcEnd) {\r
12394                     this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);\r
12395                 }\r
12396             }\r
12397             if (this._lazy !== false) {\r
12398                 this._lazy = false;\r
12399             }\r
12400 \r
12401             if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {\r
12402                 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.\r
12403             }\r
12404             if (prevTotalTime === 0) {\r
12405                 if (this._initted === 2 && time > 0) {\r
12406                     //this.invalidate();\r
12407                     this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true\r
12408                 }\r
12409                 if (this._startAt) {\r
12410                     if (time >= 0) {\r
12411                         this._startAt.render(time, suppressEvents, force);\r
12412                     } else if (!callback) {\r
12413                         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.\r
12414                     }\r
12415                 }\r
12416                 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {\r
12417                     this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
12418                 }\r
12419             }\r
12420             \r
12421             pt = this._firstPT;\r
12422             while (pt) {\r
12423                 if (pt.f) {\r
12424                     pt.t[pt.p](pt.c * this.ratio + pt.s);\r
12425                 } else {\r
12426                     pt.t[pt.p] = pt.c * this.ratio + pt.s;\r
12427                 }\r
12428                 pt = pt._next;\r
12429             }\r
12430             \r
12431             if (this._onUpdate) {\r
12432                 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.\r
12433                     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.\r
12434                 }\r
12435                 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {\r
12436                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
12437                 }\r
12438             }\r
12439             if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {\r
12440                 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);\r
12441             }\r
12442             if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate\r
12443                 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.\r
12444                     this._startAt.render(time, suppressEvents, force);\r
12445                 }\r
12446                 if (isComplete) {\r
12447                     if (this._timeline.autoRemoveChildren) {\r
12448                         this._enabled(false, false);\r
12449                     }\r
12450                     this._active = false;\r
12451                 }\r
12452                 if (!suppressEvents && this.vars[callback]) {\r
12453                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
12454                 }\r
12455                 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.\r
12456                     this._rawPrevTime = 0;\r
12457                 }\r
12458             }\r
12459         };\r
12460         \r
12461 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------\r
12462         \r
12463         TweenMax.to = function(target, duration, vars) {\r
12464             return new TweenMax(target, duration, vars);\r
12465         };\r
12466         \r
12467         TweenMax.from = function(target, duration, vars) {\r
12468             vars.runBackwards = true;\r
12469             vars.immediateRender = (vars.immediateRender != false);\r
12470             return new TweenMax(target, duration, vars);\r
12471         };\r
12472         \r
12473         TweenMax.fromTo = function(target, duration, fromVars, toVars) {\r
12474             toVars.startAt = fromVars;\r
12475             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
12476             return new TweenMax(target, duration, toVars);\r
12477         };\r
12478         \r
12479         TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12480             stagger = stagger || 0;\r
12481             var delay = vars.delay || 0,\r
12482                 a = [],\r
12483                 finalComplete = function() {\r
12484                     if (vars.onComplete) {\r
12485                         vars.onComplete.apply(vars.onCompleteScope || this, arguments);\r
12486                     }\r
12487                     onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);\r
12488                 },\r
12489                 l, copy, i, p;\r
12490             if (!_isArray(targets)) {\r
12491                 if (typeof(targets) === "string") {\r
12492                     targets = TweenLite.selector(targets) || targets;\r
12493                 }\r
12494                 if (_isSelector(targets)) {\r
12495                     targets = _slice.call(targets, 0);\r
12496                 }\r
12497             }\r
12498             l = targets.length;\r
12499             for (i = 0; i < l; i++) {\r
12500                 copy = {};\r
12501                 for (p in vars) {\r
12502                     copy[p] = vars[p];\r
12503                 }\r
12504                 copy.delay = delay;\r
12505                 if (i === l - 1 && onCompleteAll) {\r
12506                     copy.onComplete = finalComplete;\r
12507                 }\r
12508                 a[i] = new TweenMax(targets[i], duration, copy);\r
12509                 delay += stagger;\r
12510             }\r
12511             return a;\r
12512         };\r
12513         \r
12514         TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12515             vars.runBackwards = true;\r
12516             vars.immediateRender = (vars.immediateRender != false);\r
12517             return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12518         };\r
12519         \r
12520         TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12521             toVars.startAt = fromVars;\r
12522             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
12523             return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12524         };\r
12525                 \r
12526         TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {\r
12527             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});\r
12528         };\r
12529         \r
12530         TweenMax.set = function(target, vars) {\r
12531             return new TweenMax(target, 0, vars);\r
12532         };\r
12533         \r
12534         TweenMax.isTweening = function(target) {\r
12535             return (TweenLite.getTweensOf(target, true).length > 0);\r
12536         };\r
12537         \r
12538         var _getChildrenOf = function(timeline, includeTimelines) {\r
12539                 var a = [],\r
12540                     cnt = 0,\r
12541                     tween = timeline._first;\r
12542                 while (tween) {\r
12543                     if (tween instanceof TweenLite) {\r
12544                         a[cnt++] = tween;\r
12545                     } else {\r
12546                         if (includeTimelines) {\r
12547                             a[cnt++] = tween;\r
12548                         }\r
12549                         a = a.concat(_getChildrenOf(tween, includeTimelines));\r
12550                         cnt = a.length;\r
12551                     }\r
12552                     tween = tween._next;\r
12553                 }\r
12554                 return a;\r
12555             }, \r
12556             getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {\r
12557                 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );\r
12558             };\r
12559         \r
12560         TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {\r
12561             if (tweens == null) {\r
12562                 tweens = true;\r
12563             }\r
12564             if (delayedCalls == null) {\r
12565                 delayedCalls = true;\r
12566             }\r
12567             var a = getAllTweens((timelines != false)),\r
12568                 l = a.length,\r
12569                 allTrue = (tweens && delayedCalls && timelines),\r
12570                 isDC, tween, i;\r
12571             for (i = 0; i < l; i++) {\r
12572                 tween = a[i];\r
12573                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {\r
12574                     if (complete) {\r
12575                         tween.totalTime(tween._reversed ? 0 : tween.totalDuration());\r
12576                     } else {\r
12577                         tween._enabled(false, false);\r
12578                     }\r
12579                 }\r
12580             }\r
12581         };\r
12582         \r
12583         TweenMax.killChildTweensOf = function(parent, complete) {\r
12584             if (parent == null) {\r
12585                 return;\r
12586             }\r
12587             var tl = TweenLiteInternals.tweenLookup,\r
12588                 a, curParent, p, i, l;\r
12589             if (typeof(parent) === "string") {\r
12590                 parent = TweenLite.selector(parent) || parent;\r
12591             }\r
12592             if (_isSelector(parent)) {\r
12593                 parent = _slice.call(parent, 0);\r
12594             }\r
12595             if (_isArray(parent)) {\r
12596                 i = parent.length;\r
12597                 while (--i > -1) {\r
12598                     TweenMax.killChildTweensOf(parent[i], complete);\r
12599                 }\r
12600                 return;\r
12601             }\r
12602             a = [];\r
12603             for (p in tl) {\r
12604                 curParent = tl[p].target.parentNode;\r
12605                 while (curParent) {\r
12606                     if (curParent === parent) {\r
12607                         a = a.concat(tl[p].tweens);\r
12608                     }\r
12609                     curParent = curParent.parentNode;\r
12610                 }\r
12611             }\r
12612             l = a.length;\r
12613             for (i = 0; i < l; i++) {\r
12614                 if (complete) {\r
12615                     a[i].totalTime(a[i].totalDuration());\r
12616                 }\r
12617                 a[i]._enabled(false, false);\r
12618             }\r
12619         };\r
12620 \r
12621         var _changePause = function(pause, tweens, delayedCalls, timelines) {\r
12622             tweens = (tweens !== false);\r
12623             delayedCalls = (delayedCalls !== false);\r
12624             timelines = (timelines !== false);\r
12625             var a = getAllTweens(timelines),\r
12626                 allTrue = (tweens && delayedCalls && timelines),\r
12627                 i = a.length,\r
12628                 isDC, tween;\r
12629             while (--i > -1) {\r
12630                 tween = a[i];\r
12631                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {\r
12632                     tween.paused(pause);\r
12633                 }\r
12634             }\r
12635         };\r
12636         \r
12637         TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {\r
12638             _changePause(true, tweens, delayedCalls, timelines);\r
12639         };\r
12640         \r
12641         TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {\r
12642             _changePause(false, tweens, delayedCalls, timelines);\r
12643         };\r
12644 \r
12645         TweenMax.globalTimeScale = function(value) {\r
12646             var tl = Animation._rootTimeline,\r
12647                 t = TweenLite.ticker.time;\r
12648             if (!arguments.length) {\r
12649                 return tl._timeScale;\r
12650             }\r
12651             value = value || _tinyNum; //can't allow zero because it'll throw the math off\r
12652             tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);\r
12653             tl = Animation._rootFramesTimeline;\r
12654             t = TweenLite.ticker.frame;\r
12655             tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);\r
12656             tl._timeScale = Animation._rootTimeline._timeScale = value;\r
12657             return value;\r
12658         };\r
12659         \r
12660     \r
12661 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------\r
12662         \r
12663         p.progress = function(value) {\r
12664             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);\r
12665         };\r
12666         \r
12667         p.totalProgress = function(value) {\r
12668             return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);\r
12669         };\r
12670         \r
12671         p.time = function(value, suppressEvents) {\r
12672             if (!arguments.length) {\r
12673                 return this._time;\r
12674             }\r
12675             if (this._dirty) {\r
12676                 this.totalDuration();\r
12677             }\r
12678             if (value > this._duration) {\r
12679                 value = this._duration;\r
12680             }\r
12681             if (this._yoyo && (this._cycle & 1) !== 0) {\r
12682                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));\r
12683             } else if (this._repeat !== 0) {\r
12684                 value += this._cycle * (this._duration + this._repeatDelay);\r
12685             }\r
12686             return this.totalTime(value, suppressEvents);\r
12687         };\r
12688 \r
12689         p.duration = function(value) {\r
12690             if (!arguments.length) {\r
12691                 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.\r
12692             }\r
12693             return Animation.prototype.duration.call(this, value);\r
12694         };\r
12695 \r
12696         p.totalDuration = function(value) {\r
12697             if (!arguments.length) {\r
12698                 if (this._dirty) {\r
12699                     //instead of Infinity, we use 999999999999 so that we can accommodate reverses\r
12700                     this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);\r
12701                     this._dirty = false;\r
12702                 }\r
12703                 return this._totalDuration;\r
12704             }\r
12705             return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );\r
12706         };\r
12707         \r
12708         p.repeat = function(value) {\r
12709             if (!arguments.length) {\r
12710                 return this._repeat;\r
12711             }\r
12712             this._repeat = value;\r
12713             return this._uncache(true);\r
12714         };\r
12715         \r
12716         p.repeatDelay = function(value) {\r
12717             if (!arguments.length) {\r
12718                 return this._repeatDelay;\r
12719             }\r
12720             this._repeatDelay = value;\r
12721             return this._uncache(true);\r
12722         };\r
12723         \r
12724         p.yoyo = function(value) {\r
12725             if (!arguments.length) {\r
12726                 return this._yoyo;\r
12727             }\r
12728             this._yoyo = value;\r
12729             return this;\r
12730         };\r
12731         \r
12732         \r
12733         return TweenMax;\r
12734         \r
12735     }, true);\r
12736 \r
12737 \r
12738 \r
12739 \r
12740 \r
12741 \r
12742 \r
12743 \r
12744 /*\r
12745  * ----------------------------------------------------------------\r
12746  * TimelineLite\r
12747  * ----------------------------------------------------------------\r
12748  */\r
12749     window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {\r
12750 \r
12751         var TimelineLite = function(vars) {\r
12752                 SimpleTimeline.call(this, vars);\r
12753                 this._labels = {};\r
12754                 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);\r
12755                 this.smoothChildTiming = (this.vars.smoothChildTiming === true);\r
12756                 this._sortChildren = true;\r
12757                 this._onUpdate = this.vars.onUpdate;\r
12758                 var v = this.vars,\r
12759                     val, p;\r
12760                 for (p in v) {\r
12761                     val = v[p];\r
12762                     if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {\r
12763                         v[p] = this._swapSelfInParams(val);\r
12764                     }\r
12765                 }\r
12766                 if (_isArray(v.tweens)) {\r
12767                     this.add(v.tweens, 0, v.align, v.stagger);\r
12768                 }\r
12769             },\r
12770             _tinyNum = 0.0000000001,\r
12771             _isSelector = TweenLite._internals.isSelector,\r
12772             _isArray = TweenLite._internals.isArray,\r
12773             _blankArray = [],\r
12774             _globals = window._gsDefine.globals,\r
12775             _copy = function(vars) {\r
12776                 var copy = {}, p;\r
12777                 for (p in vars) {\r
12778                     copy[p] = vars[p];\r
12779                 }\r
12780                 return copy;\r
12781             },\r
12782             _pauseCallback = function(tween, callback, params, scope) {\r
12783                 tween._timeline.pause(tween._startTime);\r
12784                 if (callback) {\r
12785                     callback.apply(scope || tween._timeline, params || _blankArray);\r
12786                 }\r
12787             },\r
12788             _slice = _blankArray.slice,\r
12789             p = TimelineLite.prototype = new SimpleTimeline();\r
12790 \r
12791         TimelineLite.version = "1.12.1";\r
12792         p.constructor = TimelineLite;\r
12793         p.kill()._gc = false;\r
12794 \r
12795         p.to = function(target, duration, vars, position) {\r
12796             var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;\r
12797             return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);\r
12798         };\r
12799 \r
12800         p.from = function(target, duration, vars, position) {\r
12801             return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);\r
12802         };\r
12803 \r
12804         p.fromTo = function(target, duration, fromVars, toVars, position) {\r
12805             var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;\r
12806             return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);\r
12807         };\r
12808 \r
12809         p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12810             var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),\r
12811                 i;\r
12812             if (typeof(targets) === "string") {\r
12813                 targets = TweenLite.selector(targets) || targets;\r
12814             }\r
12815             if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.\r
12816                 targets = _slice.call(targets, 0);\r
12817             }\r
12818             stagger = stagger || 0;\r
12819             for (i = 0; i < targets.length; i++) {\r
12820                 if (vars.startAt) {\r
12821                     vars.startAt = _copy(vars.startAt);\r
12822                 }\r
12823                 tl.to(targets[i], duration, _copy(vars), i * stagger);\r
12824             }\r
12825             return this.add(tl, position);\r
12826         };\r
12827 \r
12828         p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12829             vars.immediateRender = (vars.immediateRender != false);\r
12830             vars.runBackwards = true;\r
12831             return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12832         };\r
12833 \r
12834         p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12835             toVars.startAt = fromVars;\r
12836             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
12837             return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12838         };\r
12839 \r
12840         p.call = function(callback, params, scope, position) {\r
12841             return this.add( TweenLite.delayedCall(0, callback, params, scope), position);\r
12842         };\r
12843 \r
12844         p.set = function(target, vars, position) {\r
12845             position = this._parseTimeOrLabel(position, 0, true);\r
12846             if (vars.immediateRender == null) {\r
12847                 vars.immediateRender = (position === this._time && !this._paused);\r
12848             }\r
12849             return this.add( new TweenLite(target, 0, vars), position);\r
12850         };\r
12851 \r
12852         TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {\r
12853             vars = vars || {};\r
12854             if (vars.smoothChildTiming == null) {\r
12855                 vars.smoothChildTiming = true;\r
12856             }\r
12857             var tl = new TimelineLite(vars),\r
12858                 root = tl._timeline,\r
12859                 tween, next;\r
12860             if (ignoreDelayedCalls == null) {\r
12861                 ignoreDelayedCalls = true;\r
12862             }\r
12863             root._remove(tl, true);\r
12864             tl._startTime = 0;\r
12865             tl._rawPrevTime = tl._time = tl._totalTime = root._time;\r
12866             tween = root._first;\r
12867             while (tween) {\r
12868                 next = tween._next;\r
12869                 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {\r
12870                     tl.add(tween, tween._startTime - tween._delay);\r
12871                 }\r
12872                 tween = next;\r
12873             }\r
12874             root.add(tl, 0);\r
12875             return tl;\r
12876         };\r
12877 \r
12878         p.add = function(value, position, align, stagger) {\r
12879             var curTime, l, i, child, tl, beforeRawTime;\r
12880             if (typeof(position) !== "number") {\r
12881                 position = this._parseTimeOrLabel(position, 0, true, value);\r
12882             }\r
12883             if (!(value instanceof Animation)) {\r
12884                 if ((value instanceof Array) || (value && value.push && _isArray(value))) {\r
12885                     align = align || "normal";\r
12886                     stagger = stagger || 0;\r
12887                     curTime = position;\r
12888                     l = value.length;\r
12889                     for (i = 0; i < l; i++) {\r
12890                         if (_isArray(child = value[i])) {\r
12891                             child = new TimelineLite({tweens:child});\r
12892                         }\r
12893                         this.add(child, curTime);\r
12894                         if (typeof(child) !== "string" && typeof(child) !== "function") {\r
12895                             if (align === "sequence") {\r
12896                                 curTime = child._startTime + (child.totalDuration() / child._timeScale);\r
12897                             } else if (align === "start") {\r
12898                                 child._startTime -= child.delay();\r
12899                             }\r
12900                         }\r
12901                         curTime += stagger;\r
12902                     }\r
12903                     return this._uncache(true);\r
12904                 } else if (typeof(value) === "string") {\r
12905                     return this.addLabel(value, position);\r
12906                 } else if (typeof(value) === "function") {\r
12907                     value = TweenLite.delayedCall(0, value);\r
12908                 } else {\r
12909                     throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");\r
12910                 }\r
12911             }\r
12912 \r
12913             SimpleTimeline.prototype.add.call(this, value, position);\r
12914 \r
12915             //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.\r
12916             if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {\r
12917                 //in case any of the ancestors had completed but should now be enabled...\r
12918                 tl = this;\r
12919                 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.\r
12920                 while (tl._timeline) {\r
12921                     if (beforeRawTime && tl._timeline.smoothChildTiming) {\r
12922                         tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.\r
12923                     } else if (tl._gc) {\r
12924                         tl._enabled(true, false);\r
12925                     }\r
12926                     tl = tl._timeline;\r
12927                 }\r
12928             }\r
12929 \r
12930             return this;\r
12931         };\r
12932 \r
12933         p.remove = function(value) {\r
12934             if (value instanceof Animation) {\r
12935                 return this._remove(value, false);\r
12936             } else if (value instanceof Array || (value && value.push && _isArray(value))) {\r
12937                 var i = value.length;\r
12938                 while (--i > -1) {\r
12939                     this.remove(value[i]);\r
12940                 }\r
12941                 return this;\r
12942             } else if (typeof(value) === "string") {\r
12943                 return this.removeLabel(value);\r
12944             }\r
12945             return this.kill(null, value);\r
12946         };\r
12947 \r
12948         p._remove = function(tween, skipDisable) {\r
12949             SimpleTimeline.prototype._remove.call(this, tween, skipDisable);\r
12950             var last = this._last;\r
12951             if (!last) {\r
12952                 this._time = this._totalTime = this._duration = this._totalDuration = 0;\r
12953             } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {\r
12954                 this._time = this.duration();\r
12955                 this._totalTime = this._totalDuration;\r
12956             }\r
12957             return this;\r
12958         };\r
12959 \r
12960         p.append = function(value, offsetOrLabel) {\r
12961             return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));\r
12962         };\r
12963 \r
12964         p.insert = p.insertMultiple = function(value, position, align, stagger) {\r
12965             return this.add(value, position || 0, align, stagger);\r
12966         };\r
12967 \r
12968         p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {\r
12969             return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);\r
12970         };\r
12971 \r
12972         p.addLabel = function(label, position) {\r
12973             this._labels[label] = this._parseTimeOrLabel(position);\r
12974             return this;\r
12975         };\r
12976 \r
12977         p.addPause = function(position, callback, params, scope) {\r
12978             return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);\r
12979         };\r
12980 \r
12981         p.removeLabel = function(label) {\r
12982             delete this._labels[label];\r
12983             return this;\r
12984         };\r
12985 \r
12986         p.getLabelTime = function(label) {\r
12987             return (this._labels[label] != null) ? this._labels[label] : -1;\r
12988         };\r
12989 \r
12990         p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {\r
12991             var i;\r
12992             //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().\r
12993             if (ignore instanceof Animation && ignore.timeline === this) {\r
12994                 this.remove(ignore);\r
12995             } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {\r
12996                 i = ignore.length;\r
12997                 while (--i > -1) {\r
12998                     if (ignore[i] instanceof Animation && ignore[i].timeline === this) {\r
12999                         this.remove(ignore[i]);\r
13000                     }\r
13001                 }\r
13002             }\r
13003             if (typeof(offsetOrLabel) === "string") {\r
13004                 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);\r
13005             }\r
13006             offsetOrLabel = offsetOrLabel || 0;\r
13007             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).\r
13008                 i = timeOrLabel.indexOf("=");\r
13009                 if (i === -1) {\r
13010                     if (this._labels[timeOrLabel] == null) {\r
13011                         return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;\r
13012                     }\r
13013                     return this._labels[timeOrLabel] + offsetOrLabel;\r
13014                 }\r
13015                 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));\r
13016                 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();\r
13017             } else if (timeOrLabel == null) {\r
13018                 timeOrLabel = this.duration();\r
13019             }\r
13020             return Number(timeOrLabel) + offsetOrLabel;\r
13021         };\r
13022 \r
13023         p.seek = function(position, suppressEvents) {\r
13024             return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));\r
13025         };\r
13026 \r
13027         p.stop = function() {\r
13028             return this.paused(true);\r
13029         };\r
13030 \r
13031         p.gotoAndPlay = function(position, suppressEvents) {\r
13032             return this.play(position, suppressEvents);\r
13033         };\r
13034 \r
13035         p.gotoAndStop = function(position, suppressEvents) {\r
13036             return this.pause(position, suppressEvents);\r
13037         };\r
13038 \r
13039         p.render = function(time, suppressEvents, force) {\r
13040             if (this._gc) {\r
13041                 this._enabled(true, false);\r
13042             }\r
13043             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),\r
13044                 prevTime = this._time,\r
13045                 prevStart = this._startTime,\r
13046                 prevTimeScale = this._timeScale,\r
13047                 prevPaused = this._paused,\r
13048                 tween, isComplete, next, callback, internalForce;\r
13049             if (time >= totalDur) {\r
13050                 this._totalTime = this._time = totalDur;\r
13051                 if (!this._reversed) if (!this._hasPausedChild()) {\r
13052                     isComplete = true;\r
13053                     callback = "onComplete";\r
13054                     if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {\r
13055                         internalForce = true;\r
13056                         if (this._rawPrevTime > _tinyNum) {\r
13057                             callback = "onReverseComplete";\r
13058                         }\r
13059                     }\r
13060                 }\r
13061                 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.\r
13062                 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.\r
13063 \r
13064             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
13065                 this._totalTime = this._time = 0;\r
13066                 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {\r
13067                     callback = "onReverseComplete";\r
13068                     isComplete = this._reversed;\r
13069                 }\r
13070                 if (time < 0) {\r
13071                     this._active = false;\r
13072                     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.\r
13073                         internalForce = true;\r
13074                     }\r
13075                     this._rawPrevTime = time;\r
13076                 } else {\r
13077                     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.\r
13078 \r
13079                     time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)\r
13080                     if (!this._initted) {\r
13081                         internalForce = true;\r
13082                     }\r
13083                 }\r
13084 \r
13085             } else {\r
13086                 this._totalTime = this._time = this._rawPrevTime = time;\r
13087             }\r
13088             if ((this._time === prevTime || !this._first) && !force && !internalForce) {\r
13089                 return;\r
13090             } else if (!this._initted) {\r
13091                 this._initted = true;\r
13092             }\r
13093 \r
13094             if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {\r
13095                 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.\r
13096             }\r
13097 \r
13098             if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {\r
13099                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
13100             }\r
13101 \r
13102             if (this._time >= prevTime) {\r
13103                 tween = this._first;\r
13104                 while (tween) {\r
13105                     next = tween._next; //record it here because the value could change after rendering...\r
13106                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13107                         break;\r
13108                     } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {\r
13109                         if (!tween._reversed) {\r
13110                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13111                         } else {\r
13112                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13113                         }\r
13114                     }\r
13115                     tween = next;\r
13116                 }\r
13117             } else {\r
13118                 tween = this._last;\r
13119                 while (tween) {\r
13120                     next = tween._prev; //record it here because the value could change after rendering...\r
13121                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13122                         break;\r
13123                     } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {\r
13124                         if (!tween._reversed) {\r
13125                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13126                         } else {\r
13127                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13128                         }\r
13129                     }\r
13130                     tween = next;\r
13131                 }\r
13132             }\r
13133 \r
13134             if (this._onUpdate) if (!suppressEvents) {\r
13135                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
13136             }\r
13137 \r
13138             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\r
13139                 if (isComplete) {\r
13140                     if (this._timeline.autoRemoveChildren) {\r
13141                         this._enabled(false, false);\r
13142                     }\r
13143                     this._active = false;\r
13144                 }\r
13145                 if (!suppressEvents && this.vars[callback]) {\r
13146                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
13147                 }\r
13148             }\r
13149         };\r
13150 \r
13151         p._hasPausedChild = function() {\r
13152             var tween = this._first;\r
13153             while (tween) {\r
13154                 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {\r
13155                     return true;\r
13156                 }\r
13157                 tween = tween._next;\r
13158             }\r
13159             return false;\r
13160         };\r
13161 \r
13162         p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {\r
13163             ignoreBeforeTime = ignoreBeforeTime || -9999999999;\r
13164             var a = [],\r
13165                 tween = this._first,\r
13166                 cnt = 0;\r
13167             while (tween) {\r
13168                 if (tween._startTime < ignoreBeforeTime) {\r
13169                     //do nothing\r
13170                 } else if (tween instanceof TweenLite) {\r
13171                     if (tweens !== false) {\r
13172                         a[cnt++] = tween;\r
13173                     }\r
13174                 } else {\r
13175                     if (timelines !== false) {\r
13176                         a[cnt++] = tween;\r
13177                     }\r
13178                     if (nested !== false) {\r
13179                         a = a.concat(tween.getChildren(true, tweens, timelines));\r
13180                         cnt = a.length;\r
13181                     }\r
13182                 }\r
13183                 tween = tween._next;\r
13184             }\r
13185             return a;\r
13186         };\r
13187 \r
13188         p.getTweensOf = function(target, nested) {\r
13189             var disabled = this._gc,\r
13190                 a = [],\r
13191                 cnt = 0,\r
13192                 tweens, i;\r
13193             if (disabled) {\r
13194                 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.\r
13195             }\r
13196             tweens = TweenLite.getTweensOf(target);\r
13197             i = tweens.length;\r
13198             while (--i > -1) {\r
13199                 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {\r
13200                     a[cnt++] = tweens[i];\r
13201                 }\r
13202             }\r
13203             if (disabled) {\r
13204                 this._enabled(false, true);\r
13205             }\r
13206             return a;\r
13207         };\r
13208 \r
13209         p._contains = function(tween) {\r
13210             var tl = tween.timeline;\r
13211             while (tl) {\r
13212                 if (tl === this) {\r
13213                     return true;\r
13214                 }\r
13215                 tl = tl.timeline;\r
13216             }\r
13217             return false;\r
13218         };\r
13219 \r
13220         p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {\r
13221             ignoreBeforeTime = ignoreBeforeTime || 0;\r
13222             var tween = this._first,\r
13223                 labels = this._labels,\r
13224                 p;\r
13225             while (tween) {\r
13226                 if (tween._startTime >= ignoreBeforeTime) {\r
13227                     tween._startTime += amount;\r
13228                 }\r
13229                 tween = tween._next;\r
13230             }\r
13231             if (adjustLabels) {\r
13232                 for (p in labels) {\r
13233                     if (labels[p] >= ignoreBeforeTime) {\r
13234                         labels[p] += amount;\r
13235                     }\r
13236                 }\r
13237             }\r
13238             return this._uncache(true);\r
13239         };\r
13240 \r
13241         p._kill = function(vars, target) {\r
13242             if (!vars && !target) {\r
13243                 return this._enabled(false, false);\r
13244             }\r
13245             var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),\r
13246                 i = tweens.length,\r
13247                 changed = false;\r
13248             while (--i > -1) {\r
13249                 if (tweens[i]._kill(vars, target)) {\r
13250                     changed = true;\r
13251                 }\r
13252             }\r
13253             return changed;\r
13254         };\r
13255 \r
13256         p.clear = function(labels) {\r
13257             var tweens = this.getChildren(false, true, true),\r
13258                 i = tweens.length;\r
13259             this._time = this._totalTime = 0;\r
13260             while (--i > -1) {\r
13261                 tweens[i]._enabled(false, false);\r
13262             }\r
13263             if (labels !== false) {\r
13264                 this._labels = {};\r
13265             }\r
13266             return this._uncache(true);\r
13267         };\r
13268 \r
13269         p.invalidate = function() {\r
13270             var tween = this._first;\r
13271             while (tween) {\r
13272                 tween.invalidate();\r
13273                 tween = tween._next;\r
13274             }\r
13275             return this;\r
13276         };\r
13277 \r
13278         p._enabled = function(enabled, ignoreTimeline) {\r
13279             if (enabled === this._gc) {\r
13280                 var tween = this._first;\r
13281                 while (tween) {\r
13282                     tween._enabled(enabled, true);\r
13283                     tween = tween._next;\r
13284                 }\r
13285             }\r
13286             return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);\r
13287         };\r
13288 \r
13289         p.duration = function(value) {\r
13290             if (!arguments.length) {\r
13291                 if (this._dirty) {\r
13292                     this.totalDuration(); //just triggers recalculation\r
13293                 }\r
13294                 return this._duration;\r
13295             }\r
13296             if (this.duration() !== 0 && value !== 0) {\r
13297                 this.timeScale(this._duration / value);\r
13298             }\r
13299             return this;\r
13300         };\r
13301 \r
13302         p.totalDuration = function(value) {\r
13303             if (!arguments.length) {\r
13304                 if (this._dirty) {\r
13305                     var max = 0,\r
13306                         tween = this._last,\r
13307                         prevStart = 999999999999,\r
13308                         prev, end;\r
13309                     while (tween) {\r
13310                         prev = tween._prev; //record it here in case the tween changes position in the sequence...\r
13311                         if (tween._dirty) {\r
13312                             tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.\r
13313                         }\r
13314                         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\r
13315                             this.add(tween, tween._startTime - tween._delay);\r
13316                         } else {\r
13317                             prevStart = tween._startTime;\r
13318                         }\r
13319                         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.\r
13320                             max -= tween._startTime;\r
13321                             if (this._timeline.smoothChildTiming) {\r
13322                                 this._startTime += tween._startTime / this._timeScale;\r
13323                             }\r
13324                             this.shiftChildren(-tween._startTime, false, -9999999999);\r
13325                             prevStart = 0;\r
13326                         }\r
13327                         end = tween._startTime + (tween._totalDuration / tween._timeScale);\r
13328                         if (end > max) {\r
13329                             max = end;\r
13330                         }\r
13331                         tween = prev;\r
13332                     }\r
13333                     this._duration = this._totalDuration = max;\r
13334                     this._dirty = false;\r
13335                 }\r
13336                 return this._totalDuration;\r
13337             }\r
13338             if (this.totalDuration() !== 0) if (value !== 0) {\r
13339                 this.timeScale(this._totalDuration / value);\r
13340             }\r
13341             return this;\r
13342         };\r
13343 \r
13344         p.usesFrames = function() {\r
13345             var tl = this._timeline;\r
13346             while (tl._timeline) {\r
13347                 tl = tl._timeline;\r
13348             }\r
13349             return (tl === Animation._rootFramesTimeline);\r
13350         };\r
13351 \r
13352         p.rawTime = function() {\r
13353             return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;\r
13354         };\r
13355 \r
13356         return TimelineLite;\r
13357 \r
13358     }, true);\r
13359     \r
13360 \r
13361 \r
13362 \r
13363 \r
13364 \r
13365 \r
13366 \r
13367     \r
13368     \r
13369     \r
13370     \r
13371     \r
13372 /*\r
13373  * ----------------------------------------------------------------\r
13374  * TimelineMax\r
13375  * ----------------------------------------------------------------\r
13376  */\r
13377     window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {\r
13378 \r
13379         var TimelineMax = function(vars) {\r
13380                 TimelineLite.call(this, vars);\r
13381                 this._repeat = this.vars.repeat || 0;\r
13382                 this._repeatDelay = this.vars.repeatDelay || 0;\r
13383                 this._cycle = 0;\r
13384                 this._yoyo = (this.vars.yoyo === true);\r
13385                 this._dirty = true;\r
13386             },\r
13387             _tinyNum = 0.0000000001,\r
13388             _blankArray = [],\r
13389             _easeNone = new Ease(null, null, 1, 0),\r
13390             p = TimelineMax.prototype = new TimelineLite();\r
13391 \r
13392         p.constructor = TimelineMax;\r
13393         p.kill()._gc = false;\r
13394         TimelineMax.version = "1.12.1";\r
13395 \r
13396         p.invalidate = function() {\r
13397             this._yoyo = (this.vars.yoyo === true);\r
13398             this._repeat = this.vars.repeat || 0;\r
13399             this._repeatDelay = this.vars.repeatDelay || 0;\r
13400             this._uncache(true);\r
13401             return TimelineLite.prototype.invalidate.call(this);\r
13402         };\r
13403 \r
13404         p.addCallback = function(callback, position, params, scope) {\r
13405             return this.add( TweenLite.delayedCall(0, callback, params, scope), position);\r
13406         };\r
13407 \r
13408         p.removeCallback = function(callback, position) {\r
13409             if (callback) {\r
13410                 if (position == null) {\r
13411                     this._kill(null, callback);\r
13412                 } else {\r
13413                     var a = this.getTweensOf(callback, false),\r
13414                         i = a.length,\r
13415                         time = this._parseTimeOrLabel(position);\r
13416                     while (--i > -1) {\r
13417                         if (a[i]._startTime === time) {\r
13418                             a[i]._enabled(false, false);\r
13419                         }\r
13420                     }\r
13421                 }\r
13422             }\r
13423             return this;\r
13424         };\r
13425 \r
13426         p.tweenTo = function(position, vars) {\r
13427             vars = vars || {};\r
13428             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.\r
13429                 duration, p, t;\r
13430             for (p in vars) {\r
13431                 copy[p] = vars[p];\r
13432             }\r
13433             copy.time = this._parseTimeOrLabel(position);\r
13434             duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;\r
13435             t = new TweenLite(this, duration, copy);\r
13436             copy.onStart = function() {\r
13437                 t.target.paused(true);\r
13438                 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.\r
13439                     t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );\r
13440                 }\r
13441                 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.\r
13442                     vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);\r
13443                 }\r
13444             };\r
13445             return t;\r
13446         };\r
13447 \r
13448         p.tweenFromTo = function(fromPosition, toPosition, vars) {\r
13449             vars = vars || {};\r
13450             fromPosition = this._parseTimeOrLabel(fromPosition);\r
13451             vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};\r
13452             vars.immediateRender = (vars.immediateRender !== false);\r
13453             var t = this.tweenTo(toPosition, vars);\r
13454             return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);\r
13455         };\r
13456 \r
13457         p.render = function(time, suppressEvents, force) {\r
13458             if (this._gc) {\r
13459                 this._enabled(true, false);\r
13460             }\r
13461             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),\r
13462                 dur = this._duration,\r
13463                 prevTime = this._time,\r
13464                 prevTotalTime = this._totalTime,\r
13465                 prevStart = this._startTime,\r
13466                 prevTimeScale = this._timeScale,\r
13467                 prevRawPrevTime = this._rawPrevTime,\r
13468                 prevPaused = this._paused,\r
13469                 prevCycle = this._cycle,\r
13470                 tween, isComplete, next, callback, internalForce, cycleDuration;\r
13471             if (time >= totalDur) {\r
13472                 if (!this._locked) {\r
13473                     this._totalTime = totalDur;\r
13474                     this._cycle = this._repeat;\r
13475                 }\r
13476                 if (!this._reversed) if (!this._hasPausedChild()) {\r
13477                     isComplete = true;\r
13478                     callback = "onComplete";\r
13479                     if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {\r
13480                         internalForce = true;\r
13481                         if (prevRawPrevTime > _tinyNum) {\r
13482                             callback = "onReverseComplete";\r
13483                         }\r
13484                     }\r
13485                 }\r
13486                 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.\r
13487                 if (this._yoyo && (this._cycle & 1) !== 0) {\r
13488                     this._time = time = 0;\r
13489                 } else {\r
13490                     this._time = dur;\r
13491                     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.\r
13492                 }\r
13493 \r
13494             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
13495                 if (!this._locked) {\r
13496                     this._totalTime = this._cycle = 0;\r
13497                 }\r
13498                 this._time = 0;\r
13499                 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)\r
13500                     callback = "onReverseComplete";\r
13501                     isComplete = this._reversed;\r
13502                 }\r
13503                 if (time < 0) {\r
13504                     this._active = false;\r
13505                     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.\r
13506                         internalForce = true;\r
13507                     }\r
13508                     this._rawPrevTime = time;\r
13509                 } else {\r
13510                     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.\r
13511                     time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)\r
13512                     if (!this._initted) {\r
13513                         internalForce = true;\r
13514                     }\r
13515                 }\r
13516 \r
13517             } else {\r
13518                 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.\r
13519                     internalForce = true;\r
13520                 }\r
13521                 this._time = this._rawPrevTime = time;\r
13522                 if (!this._locked) {\r
13523                     this._totalTime = time;\r
13524                     if (this._repeat !== 0) {\r
13525                         cycleDuration = dur + this._repeatDelay;\r
13526                         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!)\r
13527                         if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {\r
13528                             this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)\r
13529                         }\r
13530                         this._time = this._totalTime - (this._cycle * cycleDuration);\r
13531                         if (this._yoyo) if ((this._cycle & 1) !== 0) {\r
13532                             this._time = dur - this._time;\r
13533                         }\r
13534                         if (this._time > dur) {\r
13535                             this._time = dur;\r
13536                             time = dur + 0.0001; //to avoid occasional floating point rounding error\r
13537                         } else if (this._time < 0) {\r
13538                             this._time = time = 0;\r
13539                         } else {\r
13540                             time = this._time;\r
13541                         }\r
13542                     }\r
13543                 }\r
13544             }\r
13545 \r
13546             if (this._cycle !== prevCycle) if (!this._locked) {\r
13547                 /*\r
13548                 make sure children at the end/beginning of the timeline are rendered properly. If, for example,\r
13549                 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which\r
13550                 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there\r
13551                 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So\r
13552                 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must\r
13553                 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.\r
13554                 */\r
13555                 var backwards = (this._yoyo && (prevCycle & 1) !== 0),\r
13556                     wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),\r
13557                     recTotalTime = this._totalTime,\r
13558                     recCycle = this._cycle,\r
13559                     recRawPrevTime = this._rawPrevTime,\r
13560                     recTime = this._time;\r
13561 \r
13562                 this._totalTime = prevCycle * dur;\r
13563                 if (this._cycle < prevCycle) {\r
13564                     backwards = !backwards;\r
13565                 } else {\r
13566                     this._totalTime += dur;\r
13567                 }\r
13568                 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.\r
13569 \r
13570                 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;\r
13571                 this._cycle = prevCycle;\r
13572                 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()\r
13573                 prevTime = (backwards) ? 0 : dur;\r
13574                 this.render(prevTime, suppressEvents, (dur === 0));\r
13575                 if (!suppressEvents) if (!this._gc) {\r
13576                     if (this.vars.onRepeat) {\r
13577                         this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);\r
13578                     }\r
13579                 }\r
13580                 if (wrap) {\r
13581                     prevTime = (backwards) ? dur + 0.0001 : -0.0001;\r
13582                     this.render(prevTime, true, false);\r
13583                 }\r
13584                 this._locked = false;\r
13585                 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)\r
13586                     return;\r
13587                 }\r
13588                 this._time = recTime;\r
13589                 this._totalTime = recTotalTime;\r
13590                 this._cycle = recCycle;\r
13591                 this._rawPrevTime = recRawPrevTime;\r
13592             }\r
13593 \r
13594             if ((this._time === prevTime || !this._first) && !force && !internalForce) {\r
13595                 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.\r
13596                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
13597                 }\r
13598                 return;\r
13599             } else if (!this._initted) {\r
13600                 this._initted = true;\r
13601             }\r
13602 \r
13603             if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {\r
13604                 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.\r
13605             }\r
13606 \r
13607             if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {\r
13608                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
13609             }\r
13610 \r
13611             if (this._time >= prevTime) {\r
13612                 tween = this._first;\r
13613                 while (tween) {\r
13614                     next = tween._next; //record it here because the value could change after rendering...\r
13615                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13616                         break;\r
13617                     } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {\r
13618                         if (!tween._reversed) {\r
13619                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13620                         } else {\r
13621                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13622                         }\r
13623 \r
13624                     }\r
13625                     tween = next;\r
13626                 }\r
13627             } else {\r
13628                 tween = this._last;\r
13629                 while (tween) {\r
13630                     next = tween._prev; //record it here because the value could change after rendering...\r
13631                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13632                         break;\r
13633                     } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {\r
13634                         if (!tween._reversed) {\r
13635                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13636                         } else {\r
13637                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13638                         }\r
13639                     }\r
13640                     tween = next;\r
13641                 }\r
13642             }\r
13643 \r
13644             if (this._onUpdate) if (!suppressEvents) {\r
13645                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
13646             }\r
13647             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\r
13648                 if (isComplete) {\r
13649                     if (this._timeline.autoRemoveChildren) {\r
13650                         this._enabled(false, false);\r
13651                     }\r
13652                     this._active = false;\r
13653                 }\r
13654                 if (!suppressEvents && this.vars[callback]) {\r
13655                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
13656                 }\r
13657             }\r
13658         };\r
13659 \r
13660         p.getActive = function(nested, tweens, timelines) {\r
13661             if (nested == null) {\r
13662                 nested = true;\r
13663             }\r
13664             if (tweens == null) {\r
13665                 tweens = true;\r
13666             }\r
13667             if (timelines == null) {\r
13668                 timelines = false;\r
13669             }\r
13670             var a = [],\r
13671                 all = this.getChildren(nested, tweens, timelines),\r
13672                 cnt = 0,\r
13673                 l = all.length,\r
13674                 i, tween;\r
13675             for (i = 0; i < l; i++) {\r
13676                 tween = all[i];\r
13677                 if (tween.isActive()) {\r
13678                     a[cnt++] = tween;\r
13679                 }\r
13680             }\r
13681             return a;\r
13682         };\r
13683 \r
13684 \r
13685         p.getLabelAfter = function(time) {\r
13686             if (!time) if (time !== 0) { //faster than isNan()\r
13687                 time = this._time;\r
13688             }\r
13689             var labels = this.getLabelsArray(),\r
13690                 l = labels.length,\r
13691                 i;\r
13692             for (i = 0; i < l; i++) {\r
13693                 if (labels[i].time > time) {\r
13694                     return labels[i].name;\r
13695                 }\r
13696             }\r
13697             return null;\r
13698         };\r
13699 \r
13700         p.getLabelBefore = function(time) {\r
13701             if (time == null) {\r
13702                 time = this._time;\r
13703             }\r
13704             var labels = this.getLabelsArray(),\r
13705                 i = labels.length;\r
13706             while (--i > -1) {\r
13707                 if (labels[i].time < time) {\r
13708                     return labels[i].name;\r
13709                 }\r
13710             }\r
13711             return null;\r
13712         };\r
13713 \r
13714         p.getLabelsArray = function() {\r
13715             var a = [],\r
13716                 cnt = 0,\r
13717                 p;\r
13718             for (p in this._labels) {\r
13719                 a[cnt++] = {time:this._labels[p], name:p};\r
13720             }\r
13721             a.sort(function(a,b) {\r
13722                 return a.time - b.time;\r
13723             });\r
13724             return a;\r
13725         };\r
13726 \r
13727 \r
13728 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------\r
13729 \r
13730         p.progress = function(value) {\r
13731             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);\r
13732         };\r
13733 \r
13734         p.totalProgress = function(value) {\r
13735             return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);\r
13736         };\r
13737 \r
13738         p.totalDuration = function(value) {\r
13739             if (!arguments.length) {\r
13740                 if (this._dirty) {\r
13741                     TimelineLite.prototype.totalDuration.call(this); //just forces refresh\r
13742                     //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.\r
13743                     this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);\r
13744                 }\r
13745                 return this._totalDuration;\r
13746             }\r
13747             return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );\r
13748         };\r
13749 \r
13750         p.time = function(value, suppressEvents) {\r
13751             if (!arguments.length) {\r
13752                 return this._time;\r
13753             }\r
13754             if (this._dirty) {\r
13755                 this.totalDuration();\r
13756             }\r
13757             if (value > this._duration) {\r
13758                 value = this._duration;\r
13759             }\r
13760             if (this._yoyo && (this._cycle & 1) !== 0) {\r
13761                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));\r
13762             } else if (this._repeat !== 0) {\r
13763                 value += this._cycle * (this._duration + this._repeatDelay);\r
13764             }\r
13765             return this.totalTime(value, suppressEvents);\r
13766         };\r
13767 \r
13768         p.repeat = function(value) {\r
13769             if (!arguments.length) {\r
13770                 return this._repeat;\r
13771             }\r
13772             this._repeat = value;\r
13773             return this._uncache(true);\r
13774         };\r
13775 \r
13776         p.repeatDelay = function(value) {\r
13777             if (!arguments.length) {\r
13778                 return this._repeatDelay;\r
13779             }\r
13780             this._repeatDelay = value;\r
13781             return this._uncache(true);\r
13782         };\r
13783 \r
13784         p.yoyo = function(value) {\r
13785             if (!arguments.length) {\r
13786                 return this._yoyo;\r
13787             }\r
13788             this._yoyo = value;\r
13789             return this;\r
13790         };\r
13791 \r
13792         p.currentLabel = function(value) {\r
13793             if (!arguments.length) {\r
13794                 return this.getLabelBefore(this._time + 0.00000001);\r
13795             }\r
13796             return this.seek(value, true);\r
13797         };\r
13798 \r
13799         return TimelineMax;\r
13800 \r
13801     }, true);\r
13802     \r
13803 \r
13804 \r
13805 \r
13806 \r
13807     \r
13808     \r
13809     \r
13810     \r
13811     \r
13812     \r
13813     \r
13814 /*\r
13815  * ----------------------------------------------------------------\r
13816  * BezierPlugin\r
13817  * ----------------------------------------------------------------\r
13818  */\r
13819     (function() {\r
13820 \r
13821         var _RAD2DEG = 180 / Math.PI,\r
13822             _r1 = [],\r
13823             _r2 = [],\r
13824             _r3 = [],\r
13825             _corProps = {},\r
13826             Segment = function(a, b, c, d) {\r
13827                 this.a = a;\r
13828                 this.b = b;\r
13829                 this.c = c;\r
13830                 this.d = d;\r
13831                 this.da = d - a;\r
13832                 this.ca = c - a;\r
13833                 this.ba = b - a;\r
13834             },\r
13835             _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",\r
13836             cubicToQuadratic = function(a, b, c, d) {\r
13837                 var q1 = {a:a},\r
13838                     q2 = {},\r
13839                     q3 = {},\r
13840                     q4 = {c:d},\r
13841                     mab = (a + b) / 2,\r
13842                     mbc = (b + c) / 2,\r
13843                     mcd = (c + d) / 2,\r
13844                     mabc = (mab + mbc) / 2,\r
13845                     mbcd = (mbc + mcd) / 2,\r
13846                     m8 = (mbcd - mabc) / 8;\r
13847                 q1.b = mab + (a - mab) / 4;\r
13848                 q2.b = mabc + m8;\r
13849                 q1.c = q2.a = (q1.b + q2.b) / 2;\r
13850                 q2.c = q3.a = (mabc + mbcd) / 2;\r
13851                 q3.b = mbcd - m8;\r
13852                 q4.b = mcd + (d - mcd) / 4;\r
13853                 q3.c = q4.a = (q3.b + q4.b) / 2;\r
13854                 return [q1, q2, q3, q4];\r
13855             },\r
13856             _calculateControlPoints = function(a, curviness, quad, basic, correlate) {\r
13857                 var l = a.length - 1,\r
13858                     ii = 0,\r
13859                     cp1 = a[0].a,\r
13860                     i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;\r
13861                 for (i = 0; i < l; i++) {\r
13862                     seg = a[ii];\r
13863                     p1 = seg.a;\r
13864                     p2 = seg.d;\r
13865                     p3 = a[ii+1].d;\r
13866 \r
13867                     if (correlate) {\r
13868                         r1 = _r1[i];\r
13869                         r2 = _r2[i];\r
13870                         tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);\r
13871                         m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));\r
13872                         m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));\r
13873                         mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));\r
13874                     } else {\r
13875                         m1 = p2 - (p2 - p1) * curviness * 0.5;\r
13876                         m2 = p2 + (p3 - p2) * curviness * 0.5;\r
13877                         mm = p2 - (m1 + m2) / 2;\r
13878                     }\r
13879                     m1 += mm;\r
13880                     m2 += mm;\r
13881 \r
13882                     seg.c = cp2 = m1;\r
13883                     if (i !== 0) {\r
13884                         seg.b = cp1;\r
13885                     } else {\r
13886                         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.\r
13887                     }\r
13888 \r
13889                     seg.da = p2 - p1;\r
13890                     seg.ca = cp2 - p1;\r
13891                     seg.ba = cp1 - p1;\r
13892 \r
13893                     if (quad) {\r
13894                         qb = cubicToQuadratic(p1, cp1, cp2, p2);\r
13895                         a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);\r
13896                         ii += 4;\r
13897                     } else {\r
13898                         ii++;\r
13899                     }\r
13900 \r
13901                     cp1 = m2;\r
13902                 }\r
13903                 seg = a[ii];\r
13904                 seg.b = cp1;\r
13905                 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.\r
13906                 seg.da = seg.d - seg.a;\r
13907                 seg.ca = seg.c - seg.a;\r
13908                 seg.ba = cp1 - seg.a;\r
13909                 if (quad) {\r
13910                     qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);\r
13911                     a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);\r
13912                 }\r
13913             },\r
13914             _parseAnchors = function(values, p, correlate, prepend) {\r
13915                 var a = [],\r
13916                     l, i, p1, p2, p3, tmp;\r
13917                 if (prepend) {\r
13918                     values = [prepend].concat(values);\r
13919                     i = values.length;\r
13920                     while (--i > -1) {\r
13921                         if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {\r
13922                             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\r
13923                         }\r
13924                     }\r
13925                 }\r
13926                 l = values.length - 2;\r
13927                 if (l < 0) {\r
13928                     a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);\r
13929                     return a;\r
13930                 }\r
13931                 for (i = 0; i < l; i++) {\r
13932                     p1 = values[i][p];\r
13933                     p2 = values[i+1][p];\r
13934                     a[i] = new Segment(p1, 0, 0, p2);\r
13935                     if (correlate) {\r
13936                         p3 = values[i+2][p];\r
13937                         _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);\r
13938                         _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);\r
13939                     }\r
13940                 }\r
13941                 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);\r
13942                 return a;\r
13943             },\r
13944             bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {\r
13945                 var obj = {},\r
13946                     props = [],\r
13947                     first = prepend || values[0],\r
13948                     i, p, a, j, r, l, seamless, last;\r
13949                 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;\r
13950                 if (curviness == null) {\r
13951                     curviness = 1;\r
13952                 }\r
13953                 for (p in values[0]) {\r
13954                     props.push(p);\r
13955                 }\r
13956                 //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)\r
13957                 if (values.length > 1) {\r
13958                     last = values[values.length - 1];\r
13959                     seamless = true;\r
13960                     i = props.length;\r
13961                     while (--i > -1) {\r
13962                         p = props[i];\r
13963                         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\r
13964                             seamless = false;\r
13965                             break;\r
13966                         }\r
13967                     }\r
13968                     if (seamless) {\r
13969                         values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens\r
13970                         if (prepend) {\r
13971                             values.unshift(prepend);\r
13972                         }\r
13973                         values.push(values[1]);\r
13974                         prepend = values[values.length - 3];\r
13975                     }\r
13976                 }\r
13977                 _r1.length = _r2.length = _r3.length = 0;\r
13978                 i = props.length;\r
13979                 while (--i > -1) {\r
13980                     p = props[i];\r
13981                     _corProps[p] = (correlate.indexOf(","+p+",") !== -1);\r
13982                     obj[p] = _parseAnchors(values, p, _corProps[p], prepend);\r
13983                 }\r
13984                 i = _r1.length;\r
13985                 while (--i > -1) {\r
13986                     _r1[i] = Math.sqrt(_r1[i]);\r
13987                     _r2[i] = Math.sqrt(_r2[i]);\r
13988                 }\r
13989                 if (!basic) {\r
13990                     i = props.length;\r
13991                     while (--i > -1) {\r
13992                         if (_corProps[p]) {\r
13993                             a = obj[props[i]];\r
13994                             l = a.length - 1;\r
13995                             for (j = 0; j < l; j++) {\r
13996                                 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];\r
13997                                 _r3[j] = (_r3[j] || 0) + r * r;\r
13998                             }\r
13999                         }\r
14000                     }\r
14001                     i = _r3.length;\r
14002                     while (--i > -1) {\r
14003                         _r3[i] = Math.sqrt(_r3[i]);\r
14004                     }\r
14005                 }\r
14006                 i = props.length;\r
14007                 j = quadratic ? 4 : 1;\r
14008                 while (--i > -1) {\r
14009                     p = props[i];\r
14010                     a = obj[p];\r
14011                     _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\r
14012                     if (seamless) {\r
14013                         a.splice(0, j);\r
14014                         a.splice(a.length - j, j);\r
14015                     }\r
14016                 }\r
14017                 return obj;\r
14018             },\r
14019             _parseBezierData = function(values, type, prepend) {\r
14020                 type = type || "soft";\r
14021                 var obj = {},\r
14022                     inc = (type === "cubic") ? 3 : 2,\r
14023                     soft = (type === "soft"),\r
14024                     props = [],\r
14025                     a, b, c, d, cur, i, j, l, p, cnt, tmp;\r
14026                 if (soft && prepend) {\r
14027                     values = [prepend].concat(values);\r
14028                 }\r
14029                 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }\r
14030                 for (p in values[0]) {\r
14031                     props.push(p);\r
14032                 }\r
14033                 i = props.length;\r
14034                 while (--i > -1) {\r
14035                     p = props[i];\r
14036                     obj[p] = cur = [];\r
14037                     cnt = 0;\r
14038                     l = values.length;\r
14039                     for (j = 0; j < l; j++) {\r
14040                         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);\r
14041                         if (soft) if (j > 1) if (j < l - 1) {\r
14042                             cur[cnt++] = (a + cur[cnt-2]) / 2;\r
14043                         }\r
14044                         cur[cnt++] = a;\r
14045                     }\r
14046                     l = cnt - inc + 1;\r
14047                     cnt = 0;\r
14048                     for (j = 0; j < l; j += inc) {\r
14049                         a = cur[j];\r
14050                         b = cur[j+1];\r
14051                         c = cur[j+2];\r
14052                         d = (inc === 2) ? 0 : cur[j+3];\r
14053                         cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);\r
14054                     }\r
14055                     cur.length = cnt;\r
14056                 }\r
14057                 return obj;\r
14058             },\r
14059             _addCubicLengths = function(a, steps, resolution) {\r
14060                 var inc = 1 / resolution,\r
14061                     j = a.length,\r
14062                     d, d1, s, da, ca, ba, p, i, inv, bez, index;\r
14063                 while (--j > -1) {\r
14064                     bez = a[j];\r
14065                     s = bez.a;\r
14066                     da = bez.d - s;\r
14067                     ca = bez.c - s;\r
14068                     ba = bez.b - s;\r
14069                     d = d1 = 0;\r
14070                     for (i = 1; i <= resolution; i++) {\r
14071                         p = inc * i;\r
14072                         inv = 1 - p;\r
14073                         d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);\r
14074                         index = j * resolution + i - 1;\r
14075                         steps[index] = (steps[index] || 0) + d * d;\r
14076                     }\r
14077                 }\r
14078             },\r
14079             _parseLengthData = function(obj, resolution) {\r
14080                 resolution = resolution >> 0 || 6;\r
14081                 var a = [],\r
14082                     lengths = [],\r
14083                     d = 0,\r
14084                     total = 0,\r
14085                     threshold = resolution - 1,\r
14086                     segments = [],\r
14087                     curLS = [], //current length segments array\r
14088                     p, i, l, index;\r
14089                 for (p in obj) {\r
14090                     _addCubicLengths(obj[p], a, resolution);\r
14091                 }\r
14092                 l = a.length;\r
14093                 for (i = 0; i < l; i++) {\r
14094                     d += Math.sqrt(a[i]);\r
14095                     index = i % resolution;\r
14096                     curLS[index] = d;\r
14097                     if (index === threshold) {\r
14098                         total += d;\r
14099                         index = (i / resolution) >> 0;\r
14100                         segments[index] = curLS;\r
14101                         lengths[index] = total;\r
14102                         d = 0;\r
14103                         curLS = [];\r
14104                     }\r
14105                 }\r
14106                 return {length:total, lengths:lengths, segments:segments};\r
14107             },\r
14108 \r
14109 \r
14110 \r
14111             BezierPlugin = window._gsDefine.plugin({\r
14112                     propName: "bezier",\r
14113                     priority: -1,\r
14114                     version: "1.3.2",\r
14115                     API: 2,\r
14116                     global:true,\r
14117 \r
14118                     //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
14119                     init: function(target, vars, tween) {\r
14120                         this._target = target;\r
14121                         if (vars instanceof Array) {\r
14122                             vars = {values:vars};\r
14123                         }\r
14124                         this._func = {};\r
14125                         this._round = {};\r
14126                         this._props = [];\r
14127                         this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);\r
14128                         var values = vars.values || [],\r
14129                             first = {},\r
14130                             second = values[0],\r
14131                             autoRotate = vars.autoRotate || tween.vars.orientToBezier,\r
14132                             p, isFunc, i, j, prepend;\r
14133 \r
14134                         this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;\r
14135                         for (p in second) {\r
14136                             this._props.push(p);\r
14137                         }\r
14138 \r
14139                         i = this._props.length;\r
14140                         while (--i > -1) {\r
14141                             p = this._props[i];\r
14142 \r
14143                             this._overwriteProps.push(p);\r
14144                             isFunc = this._func[p] = (typeof(target[p]) === "function");\r
14145                             first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();\r
14146                             if (!prepend) if (first[p] !== values[0][p]) {\r
14147                                 prepend = first;\r
14148                             }\r
14149                         }\r
14150                         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);\r
14151                         this._segCount = this._beziers[p].length;\r
14152 \r
14153                         if (this._timeRes) {\r
14154                             var ld = _parseLengthData(this._beziers, this._timeRes);\r
14155                             this._length = ld.length;\r
14156                             this._lengths = ld.lengths;\r
14157                             this._segments = ld.segments;\r
14158                             this._l1 = this._li = this._s1 = this._si = 0;\r
14159                             this._l2 = this._lengths[0];\r
14160                             this._curSeg = this._segments[0];\r
14161                             this._s2 = this._curSeg[0];\r
14162                             this._prec = 1 / this._curSeg.length;\r
14163                         }\r
14164 \r
14165                         if ((autoRotate = this._autoRotate)) {\r
14166                             this._initialRotations = [];\r
14167                             if (!(autoRotate[0] instanceof Array)) {\r
14168                                 this._autoRotate = autoRotate = [autoRotate];\r
14169                             }\r
14170                             i = autoRotate.length;\r
14171                             while (--i > -1) {\r
14172                                 for (j = 0; j < 3; j++) {\r
14173                                     p = autoRotate[i][j];\r
14174                                     this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;\r
14175                                 }\r
14176                                 p = autoRotate[i][2];\r
14177                                 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];\r
14178                             }\r
14179                         }\r
14180                         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.\r
14181                         return true;\r
14182                     },\r
14183 \r
14184                     //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.)\r
14185                     set: function(v) {\r
14186                         var segments = this._segCount,\r
14187                             func = this._func,\r
14188                             target = this._target,\r
14189                             notStart = (v !== this._startRatio),\r
14190                             curIndex, inv, i, p, b, t, val, l, lengths, curSeg;\r
14191                         if (!this._timeRes) {\r
14192                             curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;\r
14193                             t = (v - (curIndex * (1 / segments))) * segments;\r
14194                         } else {\r
14195                             lengths = this._lengths;\r
14196                             curSeg = this._curSeg;\r
14197                             v *= this._length;\r
14198                             i = this._li;\r
14199                             //find the appropriate segment (if the currently cached one isn't correct)\r
14200                             if (v > this._l2 && i < segments - 1) {\r
14201                                 l = segments - 1;\r
14202                                 while (i < l && (this._l2 = lengths[++i]) <= v) {   }\r
14203                                 this._l1 = lengths[i-1];\r
14204                                 this._li = i;\r
14205                                 this._curSeg = curSeg = this._segments[i];\r
14206                                 this._s2 = curSeg[(this._s1 = this._si = 0)];\r
14207                             } else if (v < this._l1 && i > 0) {\r
14208                                 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }\r
14209                                 if (i === 0 && v < this._l1) {\r
14210                                     this._l1 = 0;\r
14211                                 } else {\r
14212                                     i++;\r
14213                                 }\r
14214                                 this._l2 = lengths[i];\r
14215                                 this._li = i;\r
14216                                 this._curSeg = curSeg = this._segments[i];\r
14217                                 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;\r
14218                                 this._s2 = curSeg[this._si];\r
14219                             }\r
14220                             curIndex = i;\r
14221                             //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)\r
14222                             v -= this._l1;\r
14223                             i = this._si;\r
14224                             if (v > this._s2 && i < curSeg.length - 1) {\r
14225                                 l = curSeg.length - 1;\r
14226                                 while (i < l && (this._s2 = curSeg[++i]) <= v) {    }\r
14227                                 this._s1 = curSeg[i-1];\r
14228                                 this._si = i;\r
14229                             } else if (v < this._s1 && i > 0) {\r
14230                                 while (i > 0 && (this._s1 = curSeg[--i]) >= v) {    }\r
14231                                 if (i === 0 && v < this._s1) {\r
14232                                     this._s1 = 0;\r
14233                                 } else {\r
14234                                     i++;\r
14235                                 }\r
14236                                 this._s2 = curSeg[i];\r
14237                                 this._si = i;\r
14238                             }\r
14239                             t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;\r
14240                         }\r
14241                         inv = 1 - t;\r
14242 \r
14243                         i = this._props.length;\r
14244                         while (--i > -1) {\r
14245                             p = this._props[i];\r
14246                             b = this._beziers[p][curIndex];\r
14247                             val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;\r
14248                             if (this._round[p]) {\r
14249                                 val = Math.round(val);\r
14250                             }\r
14251                             if (func[p]) {\r
14252                                 target[p](val);\r
14253                             } else {\r
14254                                 target[p] = val;\r
14255                             }\r
14256                         }\r
14257 \r
14258                         if (this._autoRotate) {\r
14259                             var ar = this._autoRotate,\r
14260                                 b2, x1, y1, x2, y2, add, conv;\r
14261                             i = ar.length;\r
14262                             while (--i > -1) {\r
14263                                 p = ar[i][2];\r
14264                                 add = ar[i][3] || 0;\r
14265                                 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;\r
14266                                 b = this._beziers[ar[i][0]];\r
14267                                 b2 = this._beziers[ar[i][1]];\r
14268 \r
14269                                 if (b && b2) { //in case one of the properties got overwritten.\r
14270                                     b = b[curIndex];\r
14271                                     b2 = b2[curIndex];\r
14272 \r
14273                                     x1 = b.a + (b.b - b.a) * t;\r
14274                                     x2 = b.b + (b.c - b.b) * t;\r
14275                                     x1 += (x2 - x1) * t;\r
14276                                     x2 += ((b.c + (b.d - b.c) * t) - x2) * t;\r
14277 \r
14278                                     y1 = b2.a + (b2.b - b2.a) * t;\r
14279                                     y2 = b2.b + (b2.c - b2.b) * t;\r
14280                                     y1 += (y2 - y1) * t;\r
14281                                     y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;\r
14282 \r
14283                                     val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];\r
14284 \r
14285                                     if (func[p]) {\r
14286                                         target[p](val);\r
14287                                     } else {\r
14288                                         target[p] = val;\r
14289                                     }\r
14290                                 }\r
14291                             }\r
14292                         }\r
14293                     }\r
14294             }),\r
14295             p = BezierPlugin.prototype;\r
14296 \r
14297 \r
14298         BezierPlugin.bezierThrough = bezierThrough;\r
14299         BezierPlugin.cubicToQuadratic = cubicToQuadratic;\r
14300         BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite\r
14301         BezierPlugin.quadraticToCubic = function(a, b, c) {\r
14302             return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);\r
14303         };\r
14304 \r
14305         BezierPlugin._cssRegister = function() {\r
14306             var CSSPlugin = window._gsDefine.globals.CSSPlugin;\r
14307             if (!CSSPlugin) {\r
14308                 return;\r
14309             }\r
14310             var _internals = CSSPlugin._internals,\r
14311                 _parseToProxy = _internals._parseToProxy,\r
14312                 _setPluginRatio = _internals._setPluginRatio,\r
14313                 CSSPropTween = _internals.CSSPropTween;\r
14314             _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {\r
14315                 if (e instanceof Array) {\r
14316                     e = {values:e};\r
14317                 }\r
14318                 plugin = new BezierPlugin();\r
14319                 var values = e.values,\r
14320                     l = values.length - 1,\r
14321                     pluginValues = [],\r
14322                     v = {},\r
14323                     i, p, data;\r
14324                 if (l < 0) {\r
14325                     return pt;\r
14326                 }\r
14327                 for (i = 0; i <= l; i++) {\r
14328                     data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));\r
14329                     pluginValues[i] = data.end;\r
14330                 }\r
14331                 for (p in e) {\r
14332                     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.\r
14333                 }\r
14334                 v.values = pluginValues;\r
14335                 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);\r
14336                 pt.data = data;\r
14337                 pt.plugin = plugin;\r
14338                 pt.setRatio = _setPluginRatio;\r
14339                 if (v.autoRotate === 0) {\r
14340                     v.autoRotate = true;\r
14341                 }\r
14342                 if (v.autoRotate && !(v.autoRotate instanceof Array)) {\r
14343                     i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);\r
14344                     v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;\r
14345                 }\r
14346                 if (v.autoRotate) {\r
14347                     if (!cssp._transform) {\r
14348                         cssp._enableTransforms(false);\r
14349                     }\r
14350                     data.autoRotate = cssp._target._gsTransform;\r
14351                 }\r
14352                 plugin._onInitTween(data.proxy, v, cssp._tween);\r
14353                 return pt;\r
14354             }});\r
14355         };\r
14356 \r
14357         p._roundProps = function(lookup, value) {\r
14358             var op = this._overwriteProps,\r
14359                 i = op.length;\r
14360             while (--i > -1) {\r
14361                 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {\r
14362                     this._round[op[i]] = value;\r
14363                 }\r
14364             }\r
14365         };\r
14366 \r
14367         p._kill = function(lookup) {\r
14368             var a = this._props,\r
14369                 p, i;\r
14370             for (p in this._beziers) {\r
14371                 if (p in lookup) {\r
14372                     delete this._beziers[p];\r
14373                     delete this._func[p];\r
14374                     i = a.length;\r
14375                     while (--i > -1) {\r
14376                         if (a[i] === p) {\r
14377                             a.splice(i, 1);\r
14378                         }\r
14379                     }\r
14380                 }\r
14381             }\r
14382             return this._super._kill.call(this, lookup);\r
14383         };\r
14384 \r
14385     }());\r
14386 \r
14387 \r
14388 \r
14389 \r
14390 \r
14391 \r
14392     \r
14393     \r
14394     \r
14395     \r
14396     \r
14397     \r
14398     \r
14399     \r
14400 /*\r
14401  * ----------------------------------------------------------------\r
14402  * CSSPlugin\r
14403  * ----------------------------------------------------------------\r
14404  */\r
14405     window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {\r
14406 \r
14407         /** @constructor **/\r
14408         var CSSPlugin = function() {\r
14409                 TweenPlugin.call(this, "css");\r
14410                 this._overwriteProps.length = 0;\r
14411                 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)\r
14412             },\r
14413             _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.\r
14414             _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\r
14415             _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter\r
14416             _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.\r
14417             _specialProps = {},\r
14418             p = CSSPlugin.prototype = new TweenPlugin("css");\r
14419 \r
14420         p.constructor = CSSPlugin;\r
14421         CSSPlugin.version = "1.12.1";\r
14422         CSSPlugin.API = 2;\r
14423         CSSPlugin.defaultTransformPerspective = 0;\r
14424         CSSPlugin.defaultSkewType = "compensated";\r
14425         p = "px"; //we'll reuse the "p" variable to keep file size down\r
14426         CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};\r
14427 \r
14428 \r
14429         var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,\r
14430             _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,\r
14431             _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)"\r
14432             _NaNExp = /[^\d\-\.]/g,\r
14433             _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,\r
14434             _opacityExp = /opacity *= *([^)]*)/i,\r
14435             _opacityValExp = /opacity:([^;]*)/i,\r
14436             _alphaFilterExp = /alpha\(opacity *=.+?\)/i,\r
14437             _rgbhslExp = /^(rgb|hsl)/,\r
14438             _capsExp = /([A-Z])/g,\r
14439             _camelExp = /-([a-z])/gi,\r
14440             _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)\r
14441             _camelFunc = function(s, g) { return g.toUpperCase(); },\r
14442             _horizExp = /(?:Left|Right|Width)/i,\r
14443             _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,\r
14444             _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,\r
14445             _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis\r
14446             _DEG2RAD = Math.PI / 180,\r
14447             _RAD2DEG = 180 / Math.PI,\r
14448             _forcePT = {},\r
14449             _doc = document,\r
14450             _tempDiv = _doc.createElement("div"),\r
14451             _tempImg = _doc.createElement("img"),\r
14452             _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins\r
14453             _agent = navigator.userAgent,\r
14454             _autoRound,\r
14455             _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).\r
14456 \r
14457             _isSafari,\r
14458             _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.\r
14459             _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!)\r
14460             _ieVers,\r
14461             _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.\r
14462                 var i = _agent.indexOf("Android"),\r
14463                     d = _doc.createElement("div"), a;\r
14464 \r
14465                 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));\r
14466                 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));\r
14467                 _isFirefox = (_agent.indexOf("Firefox") !== -1);\r
14468 \r
14469                 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {\r
14470                     _ieVers = parseFloat( RegExp.$1 );\r
14471                 }\r
14472 \r
14473                 d.innerHTML = "<a title='' style='top:1px;opacity:.55;'>a</a>";\r
14474                 a = d.getElementsByTagName("a")[0];\r
14475                 return a ? /^0.55/.test(a.style.opacity) : false;\r
14476             }()),\r
14477             _getIEOpacity = function(v) {\r
14478                 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);\r
14479             },\r
14480             _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.\r
14481                 if (window.console) {\r
14482                     //console.log(s);\r
14483                 }\r
14484             },\r
14485             _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"\r
14486             _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".\r
14487 \r
14488             // @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)\r
14489             _checkPropPrefix = function(p, e) {\r
14490                 e = e || _tempDiv;\r
14491                 var s = e.style,\r
14492                     a, i;\r
14493                 if (s[p] !== undefined) {\r
14494                     return p;\r
14495                 }\r
14496                 p = p.charAt(0).toUpperCase() + p.substr(1);\r
14497                 a = ["O","Moz","ms","Ms","Webkit"];\r
14498                 i = 5;\r
14499                 while (--i > -1 && s[a[i]+p] === undefined) { }\r
14500                 if (i >= 0) {\r
14501                     _prefix = (i === 3) ? "ms" : a[i];\r
14502                     _prefixCSS = "-" + _prefix.toLowerCase() + "-";\r
14503                     return _prefix + p;\r
14504                 }\r
14505                 return null;\r
14506             },\r
14507 \r
14508             _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},\r
14509 \r
14510             /**\r
14511              * @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:\r
14512              * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");\r
14513              *\r
14514              * @param {!Object} t Target element whose style property you want to query\r
14515              * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)\r
14516              * @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.\r
14517              * @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.\r
14518              * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".\r
14519              * @return {?string} The current property value\r
14520              */\r
14521             _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {\r
14522                 var rv;\r
14523                 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.\r
14524                     return _getIEOpacity(t);\r
14525                 }\r
14526                 if (!calc && t.style[p]) {\r
14527                     rv = t.style[p];\r
14528                 } else if ((cs = cs || _getComputedStyle(t))) {\r
14529                     rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());\r
14530                 } else if (t.currentStyle) {\r
14531                     rv = t.currentStyle[p];\r
14532                 }\r
14533                 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;\r
14534             },\r
14535 \r
14536             /**\r
14537              * @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.\r
14538              * @param {!Object} t Target element\r
14539              * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)\r
14540              * @param {!number} v Value\r
14541              * @param {string=} sfx Suffix (like "px" or "%" or "em")\r
14542              * @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.\r
14543              * @return {number} value in pixels\r
14544              */\r
14545             _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {\r
14546                 if (sfx === "px" || !sfx) { return v; }\r
14547                 if (sfx === "auto" || !v) { return 0; }\r
14548                 var horiz = _horizExp.test(p),\r
14549                     node = t,\r
14550                     style = _tempDiv.style,\r
14551                     neg = (v < 0),\r
14552                     pix, cache, time;\r
14553                 if (neg) {\r
14554                     v = -v;\r
14555                 }\r
14556                 if (sfx === "%" && p.indexOf("border") !== -1) {\r
14557                     pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);\r
14558                 } else {\r
14559                     style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";\r
14560                     if (sfx === "%" || !node.appendChild) {\r
14561                         node = t.parentNode || _doc.body;\r
14562                         cache = node._gsCache;\r
14563                         time = TweenLite.ticker.frame;\r
14564                         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)\r
14565                             return cache.width * v / 100;\r
14566                         }\r
14567                         style[(horiz ? "width" : "height")] = v + sfx;\r
14568                     } else {\r
14569                         style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;\r
14570                     }\r
14571                     node.appendChild(_tempDiv);\r
14572                     pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);\r
14573                     node.removeChild(_tempDiv);\r
14574                     if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {\r
14575                         cache = node._gsCache = node._gsCache || {};\r
14576                         cache.time = time;\r
14577                         cache.width = pix / v * 100;\r
14578                     }\r
14579                     if (pix === 0 && !recurse) {\r
14580                         pix = _convertToPixels(t, p, v, sfx, true);\r
14581                     }\r
14582                 }\r
14583                 return neg ? -pix : pix;\r
14584             },\r
14585             _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\r
14586                 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }\r
14587                 var dim = ((p === "left") ? "Left" : "Top"),\r
14588                     v = _getStyle(t, "margin" + dim, cs);\r
14589                 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);\r
14590             },\r
14591 \r
14592             // @private returns at object containing ALL of the style properties in camelCase and their associated values.\r
14593             _getAllStyles = function(t, cs) {\r
14594                 var s = {},\r
14595                     i, tr;\r
14596                 if ((cs = cs || _getComputedStyle(t, null))) {\r
14597                     if ((i = cs.length)) {\r
14598                         while (--i > -1) {\r
14599                             s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);\r
14600                         }\r
14601                     } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.\r
14602                         for (i in cs) {\r
14603                             s[i] = cs[i];\r
14604                         }\r
14605                     }\r
14606                 } else if ((cs = t.currentStyle || t.style)) {\r
14607                     for (i in cs) {\r
14608                         if (typeof(i) === "string" && s[i] === undefined) {\r
14609                             s[i.replace(_camelExp, _camelFunc)] = cs[i];\r
14610                         }\r
14611                     }\r
14612                 }\r
14613                 if (!_supportsOpacity) {\r
14614                     s.opacity = _getIEOpacity(t);\r
14615                 }\r
14616                 tr = _getTransform(t, cs, false);\r
14617                 s.rotation = tr.rotation;\r
14618                 s.skewX = tr.skewX;\r
14619                 s.scaleX = tr.scaleX;\r
14620                 s.scaleY = tr.scaleY;\r
14621                 s.x = tr.x;\r
14622                 s.y = tr.y;\r
14623                 if (_supports3D) {\r
14624                     s.z = tr.z;\r
14625                     s.rotationX = tr.rotationX;\r
14626                     s.rotationY = tr.rotationY;\r
14627                     s.scaleZ = tr.scaleZ;\r
14628                 }\r
14629                 if (s.filters) {\r
14630                     delete s.filters;\r
14631                 }\r
14632                 return s;\r
14633             },\r
14634 \r
14635             // @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.\r
14636             _cssDif = function(t, s1, s2, vars, forceLookup) {\r
14637                 var difs = {},\r
14638                     style = t.style,\r
14639                     val, p, mpt;\r
14640                 for (p in s2) {\r
14641                     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") {\r
14642                         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.\r
14643                         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.\r
14644                             mpt = new MiniPropTween(style, p, style[p], mpt);\r
14645                         }\r
14646                     }\r
14647                 }\r
14648                 if (vars) {\r
14649                     for (p in vars) { //copy properties (except className)\r
14650                         if (p !== "className") {\r
14651                             difs[p] = vars[p];\r
14652                         }\r
14653                     }\r
14654                 }\r
14655                 return {difs:difs, firstMPT:mpt};\r
14656             },\r
14657             _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},\r
14658             _margins = ["marginLeft","marginRight","marginTop","marginBottom"],\r
14659 \r
14660             /**\r
14661              * @private Gets the width or height of an element\r
14662              * @param {!Object} t Target element\r
14663              * @param {!string} p Property name ("width" or "height")\r
14664              * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.\r
14665              * @return {number} Dimension (in pixels)\r
14666              */\r
14667             _getDimension = function(t, p, cs) {\r
14668                 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),\r
14669                     a = _dimensions[p],\r
14670                     i = a.length;\r
14671                 cs = cs || _getComputedStyle(t, null);\r
14672                 while (--i > -1) {\r
14673                     v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;\r
14674                     v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;\r
14675                 }\r
14676                 return v;\r
14677             },\r
14678 \r
14679             // @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)\r
14680             _parsePosition = function(v, recObj) {\r
14681                 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".\r
14682                     v = "0 0";\r
14683                 }\r
14684                 var a = v.split(" "),\r
14685                     x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],\r
14686                     y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];\r
14687                 if (y == null) {\r
14688                     y = "0";\r
14689                 } else if (y === "center") {\r
14690                     y = "50%";\r
14691                 }\r
14692                 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.\r
14693                     x = "50%";\r
14694                 }\r
14695                 if (recObj) {\r
14696                     recObj.oxp = (x.indexOf("%") !== -1);\r
14697                     recObj.oyp = (y.indexOf("%") !== -1);\r
14698                     recObj.oxr = (x.charAt(1) === "=");\r
14699                     recObj.oyr = (y.charAt(1) === "=");\r
14700                     recObj.ox = parseFloat(x.replace(_NaNExp, ""));\r
14701                     recObj.oy = parseFloat(y.replace(_NaNExp, ""));\r
14702                 }\r
14703                 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");\r
14704             },\r
14705 \r
14706             /**\r
14707              * @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!)\r
14708              * @param {(number|string)} e End value which is typically a string, but could be a number\r
14709              * @param {(number|string)} b Beginning value which is typically a string but could be a number\r
14710              * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)\r
14711              */\r
14712             _parseChange = function(e, b) {\r
14713                 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);\r
14714             },\r
14715 \r
14716             /**\r
14717              * @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.\r
14718              * @param {Object} v Value to be parsed\r
14719              * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)\r
14720              * @return {number} Parsed value\r
14721              */\r
14722             _parseVal = function(v, d) {\r
14723                 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);\r
14724             },\r
14725 \r
14726             /**\r
14727              * @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.\r
14728              * @param {Object} v Value to be parsed\r
14729              * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)\r
14730              * @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"\r
14731              * @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.\r
14732              * @return {number} parsed angle in radians\r
14733              */\r
14734             _parseAngle = function(v, d, p, directionalEnd) {\r
14735                 var min = 0.000001,\r
14736                     cap, split, dif, result;\r
14737                 if (v == null) {\r
14738                     result = d;\r
14739                 } else if (typeof(v) === "number") {\r
14740                     result = v;\r
14741                 } else {\r
14742                     cap = 360;\r
14743                     split = v.split("_");\r
14744                     dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);\r
14745                     if (split.length) {\r
14746                         if (directionalEnd) {\r
14747                             directionalEnd[p] = d + dif;\r
14748                         }\r
14749                         if (v.indexOf("short") !== -1) {\r
14750                             dif = dif % cap;\r
14751                             if (dif !== dif % (cap / 2)) {\r
14752                                 dif = (dif < 0) ? dif + cap : dif - cap;\r
14753                             }\r
14754                         }\r
14755                         if (v.indexOf("_cw") !== -1 && dif < 0) {\r
14756                             dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
14757                         } else if (v.indexOf("ccw") !== -1 && dif > 0) {\r
14758                             dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
14759                         }\r
14760                     }\r
14761                     result = d + dif;\r
14762                 }\r
14763                 if (result < min && result > -min) {\r
14764                     result = 0;\r
14765                 }\r
14766                 return result;\r
14767             },\r
14768 \r
14769             _colorLookup = {aqua:[0,255,255],\r
14770                 lime:[0,255,0],\r
14771                 silver:[192,192,192],\r
14772                 black:[0,0,0],\r
14773                 maroon:[128,0,0],\r
14774                 teal:[0,128,128],\r
14775                 blue:[0,0,255],\r
14776                 navy:[0,0,128],\r
14777                 white:[255,255,255],\r
14778                 fuchsia:[255,0,255],\r
14779                 olive:[128,128,0],\r
14780                 yellow:[255,255,0],\r
14781                 orange:[255,165,0],\r
14782                 gray:[128,128,128],\r
14783                 purple:[128,0,128],\r
14784                 green:[0,128,0],\r
14785                 red:[255,0,0],\r
14786                 pink:[255,192,203],\r
14787                 cyan:[0,255,255],\r
14788                 transparent:[255,255,255,0]},\r
14789 \r
14790             _hue = function(h, m1, m2) {\r
14791                 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;\r
14792                 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;\r
14793             },\r
14794 \r
14795             /**\r
14796              * @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)\r
14797              * @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.\r
14798              * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.\r
14799              */\r
14800             _parseColor = function(v) {\r
14801                 var c1, c2, c3, h, s, l;\r
14802                 if (!v || v === "") {\r
14803                     return _colorLookup.black;\r
14804                 }\r
14805                 if (typeof(v) === "number") {\r
14806                     return [v >> 16, (v >> 8) & 255, v & 255];\r
14807                 }\r
14808                 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.\r
14809                     v = v.substr(0, v.length - 1);\r
14810                 }\r
14811                 if (_colorLookup[v]) {\r
14812                     return _colorLookup[v];\r
14813                 }\r
14814                 if (v.charAt(0) === "#") {\r
14815                     if (v.length === 4) { //for shorthand like #9F0\r
14816                         c1 = v.charAt(1),\r
14817                         c2 = v.charAt(2),\r
14818                         c3 = v.charAt(3);\r
14819                         v = "#" + c1 + c1 + c2 + c2 + c3 + c3;\r
14820                     }\r
14821                     v = parseInt(v.substr(1), 16);\r
14822                     return [v >> 16, (v >> 8) & 255, v & 255];\r
14823                 }\r
14824                 if (v.substr(0, 3) === "hsl") {\r
14825                     v = v.match(_numExp);\r
14826                     h = (Number(v[0]) % 360) / 360;\r
14827                     s = Number(v[1]) / 100;\r
14828                     l = Number(v[2]) / 100;\r
14829                     c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;\r
14830                     c1 = l * 2 - c2;\r
14831                     if (v.length > 3) {\r
14832                         v[3] = Number(v[3]);\r
14833                     }\r
14834                     v[0] = _hue(h + 1 / 3, c1, c2);\r
14835                     v[1] = _hue(h, c1, c2);\r
14836                     v[2] = _hue(h - 1 / 3, c1, c2);\r
14837                     return v;\r
14838                 }\r
14839                 v = v.match(_numExp) || _colorLookup.transparent;\r
14840                 v[0] = Number(v[0]);\r
14841                 v[1] = Number(v[1]);\r
14842                 v[2] = Number(v[2]);\r
14843                 if (v.length > 3) {\r
14844                     v[3] = Number(v[3]);\r
14845                 }\r
14846                 return v;\r
14847             },\r
14848             _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.\r
14849 \r
14850         for (p in _colorLookup) {\r
14851             _colorExp += "|" + p + "\\b";\r
14852         }\r
14853         _colorExp = new RegExp(_colorExp+")", "gi");\r
14854 \r
14855         /**\r
14856          * @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.\r
14857          * @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.\r
14858          * @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.\r
14859          * @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.\r
14860          * @return {Function} formatter function\r
14861          */\r
14862         var _getFormatter = function(dflt, clr, collapsible, multi) {\r
14863                 if (dflt == null) {\r
14864                     return function(v) {return v;};\r
14865                 }\r
14866                 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",\r
14867                     dVals = dflt.split(dColor).join("").match(_valuesExp) || [],\r
14868                     pfx = dflt.substr(0, dflt.indexOf(dVals[0])),\r
14869                     sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",\r
14870                     delim = (dflt.indexOf(" ") !== -1) ? " " : ",",\r
14871                     numVals = dVals.length,\r
14872                     dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",\r
14873                     formatter;\r
14874                 if (!numVals) {\r
14875                     return function(v) {return v;};\r
14876                 }\r
14877                 if (clr) {\r
14878                     formatter = function(v) {\r
14879                         var color, vals, i, a;\r
14880                         if (typeof(v) === "number") {\r
14881                             v += dSfx;\r
14882                         } else if (multi && _commasOutsideParenExp.test(v)) {\r
14883                             a = v.replace(_commasOutsideParenExp, "|").split("|");\r
14884                             for (i = 0; i < a.length; i++) {\r
14885                                 a[i] = formatter(a[i]);\r
14886                             }\r
14887                             return a.join(",");\r
14888                         }\r
14889                         color = (v.match(_colorExp) || [dColor])[0];\r
14890                         vals = v.split(color).join("").match(_valuesExp) || [];\r
14891                         i = vals.length;\r
14892                         if (numVals > i--) {\r
14893                             while (++i < numVals) {\r
14894                                 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];\r
14895                             }\r
14896                         }\r
14897                         return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");\r
14898                     };\r
14899                     return formatter;\r
14900 \r
14901                 }\r
14902                 formatter = function(v) {\r
14903                     var vals, a, i;\r
14904                     if (typeof(v) === "number") {\r
14905                         v += dSfx;\r
14906                     } else if (multi && _commasOutsideParenExp.test(v)) {\r
14907                         a = v.replace(_commasOutsideParenExp, "|").split("|");\r
14908                         for (i = 0; i < a.length; i++) {\r
14909                             a[i] = formatter(a[i]);\r
14910                         }\r
14911                         return a.join(",");\r
14912                     }\r
14913                     vals = v.match(_valuesExp) || [];\r
14914                     i = vals.length;\r
14915                     if (numVals > i--) {\r
14916                         while (++i < numVals) {\r
14917                             vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];\r
14918                         }\r
14919                     }\r
14920                     return pfx + vals.join(delim) + sfx;\r
14921                 };\r
14922                 return formatter;\r
14923             },\r
14924 \r
14925             /**\r
14926              * @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.\r
14927              * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"\r
14928              * @return {Function} a formatter function\r
14929              */\r
14930             _getEdgeParser = function(props) {\r
14931                 props = props.split(",");\r
14932                 return function(t, e, p, cssp, pt, plugin, vars) {\r
14933                     var a = (e + "").split(" "),\r
14934                         i;\r
14935                     vars = {};\r
14936                     for (i = 0; i < 4; i++) {\r
14937                         vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];\r
14938                     }\r
14939                     return cssp.parse(t, vars, pt, plugin);\r
14940                 };\r
14941             },\r
14942 \r
14943             // @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.\r
14944             _setPluginRatio = _internals._setPluginRatio = function(v) {\r
14945                 this.plugin.setRatio(v);\r
14946                 var d = this.data,\r
14947                     proxy = d.proxy,\r
14948                     mpt = d.firstMPT,\r
14949                     min = 0.000001,\r
14950                     val, pt, i, str;\r
14951                 while (mpt) {\r
14952                     val = proxy[mpt.v];\r
14953                     if (mpt.r) {\r
14954                         val = Math.round(val);\r
14955                     } else if (val < min && val > -min) {\r
14956                         val = 0;\r
14957                     }\r
14958                     mpt.t[mpt.p] = val;\r
14959                     mpt = mpt._next;\r
14960                 }\r
14961                 if (d.autoRotate) {\r
14962                     d.autoRotate.rotation = proxy.rotation;\r
14963                 }\r
14964                 //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.\r
14965                 if (v === 1) {\r
14966                     mpt = d.firstMPT;\r
14967                     while (mpt) {\r
14968                         pt = mpt.t;\r
14969                         if (!pt.type) {\r
14970                             pt.e = pt.s + pt.xs0;\r
14971                         } else if (pt.type === 1) {\r
14972                             str = pt.xs0 + pt.s + pt.xs1;\r
14973                             for (i = 1; i < pt.l; i++) {\r
14974                                 str += pt["xn"+i] + pt["xs"+(i+1)];\r
14975                             }\r
14976                             pt.e = str;\r
14977                         }\r
14978                         mpt = mpt._next;\r
14979                     }\r
14980                 }\r
14981             },\r
14982 \r
14983             /**\r
14984              * @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.\r
14985              * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)\r
14986              * @param {!string} p property name\r
14987              * @param {(number|string|object)} v value\r
14988              * @param {MiniPropTween=} next next MiniPropTween in the linked list\r
14989              * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer\r
14990              */\r
14991             MiniPropTween = function(t, p, v, next, r) {\r
14992                 this.t = t;\r
14993                 this.p = p;\r
14994                 this.v = v;\r
14995                 this.r = r;\r
14996                 if (next) {\r
14997                     next._prev = this;\r
14998                     this._next = next;\r
14999                 }\r
15000             },\r
15001 \r
15002             /**\r
15003              * @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.\r
15004              * This method returns an object that has the following properties:\r
15005              *  - 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\r
15006              *  - 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\r
15007              *  - firstMPT: the first MiniPropTween in the linked list\r
15008              *  - 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.\r
15009              * @param {!Object} t target object to be tweened\r
15010              * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed\r
15011              * @param {!CSSPlugin} cssp The CSSPlugin instance\r
15012              * @param {CSSPropTween=} pt the next CSSPropTween in the linked list\r
15013              * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values\r
15014              * @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.\r
15015              * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)\r
15016              */\r
15017             _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {\r
15018                 var bpt = pt,\r
15019                     start = {},\r
15020                     end = {},\r
15021                     transform = cssp._transform,\r
15022                     oldForce = _forcePT,\r
15023                     i, p, xp, mpt, firstPT;\r
15024                 cssp._transform = null;\r
15025                 _forcePT = vars;\r
15026                 pt = firstPT = cssp.parse(t, vars, pt, plugin);\r
15027                 _forcePT = oldForce;\r
15028                 //break off from the linked list so the new ones are isolated.\r
15029                 if (shallow) {\r
15030                     cssp._transform = transform;\r
15031                     if (bpt) {\r
15032                         bpt._prev = null;\r
15033                         if (bpt._prev) {\r
15034                             bpt._prev._next = null;\r
15035                         }\r
15036                     }\r
15037                 }\r
15038                 while (pt && pt !== bpt) {\r
15039                     if (pt.type <= 1) {\r
15040                         p = pt.p;\r
15041                         end[p] = pt.s + pt.c;\r
15042                         start[p] = pt.s;\r
15043                         if (!shallow) {\r
15044                             mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);\r
15045                             pt.c = 0;\r
15046                         }\r
15047                         if (pt.type === 1) {\r
15048                             i = pt.l;\r
15049                             while (--i > 0) {\r
15050                                 xp = "xn" + i;\r
15051                                 p = pt.p + "_" + xp;\r
15052                                 end[p] = pt.data[xp];\r
15053                                 start[p] = pt[xp];\r
15054                                 if (!shallow) {\r
15055                                     mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);\r
15056                                 }\r
15057                             }\r
15058                         }\r
15059                     }\r
15060                     pt = pt._next;\r
15061                 }\r
15062                 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};\r
15063             },\r
15064 \r
15065 \r
15066 \r
15067             /**\r
15068              * @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.\r
15069              * CSSPropTweens have the following optional properties as well (not defined through the constructor):\r
15070              *  - 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.\r
15071              *  - 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)\r
15072              *  - 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.\r
15073              *  - 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.\r
15074              *  - 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.\r
15075              * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.\r
15076              * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".\r
15077              * @param {number} s Starting numeric value\r
15078              * @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.\r
15079              * @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.\r
15080              * @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.\r
15081              * @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"\r
15082              * @param {boolean=} r If true, the value(s) should be rounded\r
15083              * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.\r
15084              * @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.\r
15085              * @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.\r
15086              */\r
15087             CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {\r
15088                 this.t = t; //target\r
15089                 this.p = p; //property\r
15090                 this.s = s; //starting value\r
15091                 this.c = c; //change value\r
15092                 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)\r
15093                 if (!(t instanceof CSSPropTween)) {\r
15094                     _overwriteProps.push(this.n);\r
15095                 }\r
15096                 this.r = r; //round (boolean)\r
15097                 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\r
15098                 if (pr) {\r
15099                     this.pr = pr;\r
15100                     _hasPriority = true;\r
15101                 }\r
15102                 this.b = (b === undefined) ? s : b;\r
15103                 this.e = (e === undefined) ? s + c : e;\r
15104                 if (next) {\r
15105                     this._next = next;\r
15106                     next._prev = this;\r
15107                 }\r
15108             },\r
15109 \r
15110             /**\r
15111              * 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:\r
15112              * 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);\r
15113              * 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().\r
15114              * 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.\r
15115              *\r
15116              * @param {!Object} t Target whose property will be tweened\r
15117              * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")\r
15118              * @param {string} b Beginning value\r
15119              * @param {string} e Ending value\r
15120              * @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)\r
15121              * @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\r
15122              * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).\r
15123              * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.\r
15124              * @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}\r
15125              * @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.\r
15126              * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.\r
15127              */\r
15128             _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {\r
15129                 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);\r
15130                 b = b || dflt || "";\r
15131                 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);\r
15132                 e += ""; //ensures it's a string\r
15133                 var ba = b.split(", ").join(",").split(" "), //beginning array\r
15134                     ea = e.split(", ").join(",").split(" "), //ending array\r
15135                     l = ba.length,\r
15136                     autoRound = (_autoRound !== false),\r
15137                     i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;\r
15138                 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {\r
15139                     ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");\r
15140                     ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");\r
15141                     l = ba.length;\r
15142                 }\r
15143                 if (l !== ea.length) {\r
15144                     //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");\r
15145                     ba = (dflt || "").split(" ");\r
15146                     l = ba.length;\r
15147                 }\r
15148                 pt.plugin = plugin;\r
15149                 pt.setRatio = setRatio;\r
15150                 for (i = 0; i < l; i++) {\r
15151                     bv = ba[i];\r
15152                     ev = ea[i];\r
15153                     bn = parseFloat(bv);\r
15154 \r
15155                     //if the value begins with a number (most common). It's fine if it has a suffix like px\r
15156                     if (bn || bn === 0) {\r
15157                         pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);\r
15158 \r
15159                     //if the value is a color\r
15160                     } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {\r
15161                         str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.\r
15162                         bv = _parseColor(bv);\r
15163                         ev = _parseColor(ev);\r
15164                         rgba = (bv.length + ev.length > 6);\r
15165                         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\r
15166                             pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";\r
15167                             pt.e = pt.e.split(ea[i]).join("transparent");\r
15168                         } else {\r
15169                             if (!_supportsOpacity) { //old versions of IE don't support rgba().\r
15170                                 rgba = false;\r
15171                             }\r
15172                             pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)\r
15173                                 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)\r
15174                                 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);\r
15175                             if (rgba) {\r
15176                                 bv = (bv.length < 4) ? 1 : bv[3];\r
15177                                 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);\r
15178                             }\r
15179                         }\r
15180 \r
15181                     } else {\r
15182                         bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array\r
15183 \r
15184                         //if no number is found, treat it as a non-tweening value and just append the string to the current xs.\r
15185                         if (!bnums) {\r
15186                             pt["xs" + pt.l] += pt.l ? " " + bv : bv;\r
15187 \r
15188                         //loop through all the numbers that are found and construct the extra values on the pt.\r
15189                         } else {\r
15190                             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\r
15191                             if (!enums || enums.length !== bnums.length) {\r
15192                                 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");\r
15193                                 return pt;\r
15194                             }\r
15195                             ni = 0;\r
15196                             for (xi = 0; xi < bnums.length; xi++) {\r
15197                                 cv = bnums[xi];\r
15198                                 temp = bv.indexOf(cv, ni);\r
15199                                 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));\r
15200                                 ni = temp + cv.length;\r
15201                             }\r
15202                             pt["xs" + pt.l] += bv.substr(ni);\r
15203                         }\r
15204                     }\r
15205                 }\r
15206                 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.\r
15207                 if (e.indexOf("=") !== -1) if (pt.data) {\r
15208                     str = pt.xs0 + pt.data.s;\r
15209                     for (i = 1; i < pt.l; i++) {\r
15210                         str += pt["xs" + i] + pt.data["xn" + i];\r
15211                     }\r
15212                     pt.e = str + pt["xs" + i];\r
15213                 }\r
15214                 if (!pt.l) {\r
15215                     pt.type = -1;\r
15216                     pt.xs0 = pt.e;\r
15217                 }\r
15218                 return pt.xfirst || pt;\r
15219             },\r
15220             i = 9;\r
15221 \r
15222 \r
15223         p = CSSPropTween.prototype;\r
15224         p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.\r
15225         while (--i > 0) {\r
15226             p["xn" + i] = 0;\r
15227             p["xs" + i] = "";\r
15228         }\r
15229         p.xs0 = "";\r
15230         p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;\r
15231 \r
15232 \r
15233         /**\r
15234          * 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:\r
15235          * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"\r
15236          * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).\r
15237          * @param {string=} pfx Prefix (if any)\r
15238          * @param {!number} s Starting value\r
15239          * @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.\r
15240          * @param {string=} sfx Suffix (if any)\r
15241          * @param {boolean=} r Round (if true).\r
15242          * @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.\r
15243          * @return {CSSPropTween} returns itself so that multiple methods can be chained together.\r
15244          */\r
15245         p.appendXtra = function(pfx, s, c, sfx, r, pad) {\r
15246             var pt = this,\r
15247                 l = pt.l;\r
15248             pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";\r
15249             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!\r
15250                 pt["xs" + l] += s + (sfx || "");\r
15251                 return pt;\r
15252             }\r
15253             pt.l++;\r
15254             pt.type = pt.setRatio ? 2 : 1;\r
15255             pt["xs" + pt.l] = sfx || "";\r
15256             if (l > 0) {\r
15257                 pt.data["xn" + l] = s + c;\r
15258                 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)\r
15259                 pt["xn" + l] = s;\r
15260                 if (!pt.plugin) {\r
15261                     pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);\r
15262                     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.\r
15263                 }\r
15264                 return pt;\r
15265             }\r
15266             pt.data = {s:s + c};\r
15267             pt.rxp = {};\r
15268             pt.s = s;\r
15269             pt.c = c;\r
15270             pt.r = r;\r
15271             return pt;\r
15272         };\r
15273 \r
15274         /**\r
15275          * @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.\r
15276          * @param {!string} p Property name (like "boxShadow" or "throwProps")\r
15277          * @param {Object=} options An object containing any of the following configuration options:\r
15278          *                      - defaultValue: the default value\r
15279          *                      - 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)\r
15280          *                      - 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.)\r
15281          *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)\r
15282          *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.\r
15283          *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.\r
15284          *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.\r
15285          *                      - 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.\r
15286          *                      - 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).\r
15287          */\r
15288         var SpecialProp = function(p, options) {\r
15289                 options = options || {};\r
15290                 this.p = options.prefix ? _checkPropPrefix(p) || p : p;\r
15291                 _specialProps[p] = _specialProps[this.p] = this;\r
15292                 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);\r
15293                 if (options.parser) {\r
15294                     this.parse = options.parser;\r
15295                 }\r
15296                 this.clrs = options.color;\r
15297                 this.multi = options.multi;\r
15298                 this.keyword = options.keyword;\r
15299                 this.dflt = options.defaultValue;\r
15300                 this.pr = options.priority || 0;\r
15301             },\r
15302 \r
15303             //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.\r
15304             _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {\r
15305                 if (typeof(options) !== "object") {\r
15306                     options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin\r
15307                 }\r
15308                 var a = p.split(","),\r
15309                     d = options.defaultValue,\r
15310                     i, temp;\r
15311                 defaults = defaults || [d];\r
15312                 for (i = 0; i < a.length; i++) {\r
15313                     options.prefix = (i === 0 && options.prefix);\r
15314                     options.defaultValue = defaults[i] || d;\r
15315                     temp = new SpecialProp(a[i], options);\r
15316                 }\r
15317             },\r
15318 \r
15319             //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.\r
15320             _registerPluginProp = function(p) {\r
15321                 if (!_specialProps[p]) {\r
15322                     var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";\r
15323                     _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {\r
15324                         var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];\r
15325                         if (!pluginClass) {\r
15326                             _log("Error: " + pluginName + " js file not loaded.");\r
15327                             return pt;\r
15328                         }\r
15329                         pluginClass._cssRegister();\r
15330                         return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);\r
15331                     }});\r
15332                 }\r
15333             };\r
15334 \r
15335 \r
15336         p = SpecialProp.prototype;\r
15337 \r
15338         /**\r
15339          * 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)\r
15340          * @param {!Object} t target element\r
15341          * @param {(string|number|object)} b beginning value\r
15342          * @param {(string|number|object)} e ending (destination) value\r
15343          * @param {CSSPropTween=} pt next CSSPropTween in the linked list\r
15344          * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.\r
15345          * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.\r
15346          * @return {CSSPropTween=} First CSSPropTween in the linked list\r
15347          */\r
15348         p.parseComplex = function(t, b, e, pt, plugin, setRatio) {\r
15349             var kwd = this.keyword,\r
15350                 i, ba, ea, l, bi, ei;\r
15351             //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)\r
15352             if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {\r
15353                 ba = b.replace(_commasOutsideParenExp, "|").split("|");\r
15354                 ea = e.replace(_commasOutsideParenExp, "|").split("|");\r
15355             } else if (kwd) {\r
15356                 ba = [b];\r
15357                 ea = [e];\r
15358             }\r
15359             if (ea) {\r
15360                 l = (ea.length > ba.length) ? ea.length : ba.length;\r
15361                 for (i = 0; i < l; i++) {\r
15362                     b = ba[i] = ba[i] || this.dflt;\r
15363                     e = ea[i] = ea[i] || this.dflt;\r
15364                     if (kwd) {\r
15365                         bi = b.indexOf(kwd);\r
15366                         ei = e.indexOf(kwd);\r
15367                         if (bi !== ei) {\r
15368                             e = (ei === -1) ? ea : ba;\r
15369                             e[i] += " " + kwd;\r
15370                         }\r
15371                     }\r
15372                 }\r
15373                 b = ba.join(", ");\r
15374                 e = ea.join(", ");\r
15375             }\r
15376             return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);\r
15377         };\r
15378 \r
15379         /**\r
15380          * 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:\r
15381          * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);\r
15382          * 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).\r
15383          * @param {!Object} t Target object whose property is being tweened\r
15384          * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).\r
15385          * @param {!string} p Property name\r
15386          * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.\r
15387          * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)\r
15388          * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.\r
15389          * @param {Object=} vars Original vars object that contains the data for parsing.\r
15390          * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.\r
15391          */\r
15392         p.parse = function(t, e, p, cssp, pt, plugin, vars) {\r
15393             return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);\r
15394         };\r
15395 \r
15396         /**\r
15397          * 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:\r
15398          *  1) Target object whose property should be tweened (typically a DOM element)\r
15399          *  2) The end/destination value (could be a string, number, object, or whatever you want)\r
15400          *  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)\r
15401          *\r
15402          * 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:\r
15403          *\r
15404          * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {\r
15405          *      var start = target.style.width;\r
15406          *      return function(ratio) {\r
15407          *              target.style.width = (start + value * ratio) + "px";\r
15408          *              console.log("set width to " + target.style.width);\r
15409          *          }\r
15410          * }, 0);\r
15411          *\r
15412          * Then, when I do this tween, it will trigger my special property:\r
15413          *\r
15414          * TweenLite.to(element, 1, {css:{myCustomProp:100}});\r
15415          *\r
15416          * In the example, of course, we're just changing the width, but you can do anything you want.\r
15417          *\r
15418          * @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}})\r
15419          * @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.\r
15420          * @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.\r
15421          */\r
15422         CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {\r
15423             _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {\r
15424                 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);\r
15425                 rv.plugin = plugin;\r
15426                 rv.setRatio = onInitTween(t, e, cssp._tween, p);\r
15427                 return rv;\r
15428             }, priority:priority});\r
15429         };\r
15430 \r
15431 \r
15432 \r
15433 \r
15434 \r
15435 \r
15436 \r
15437 \r
15438         //transform-related methods and properties\r
15439         var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),\r
15440             _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.\r
15441             _transformPropCSS = _prefixCSS + "transform",\r
15442             _transformOriginProp = _checkPropPrefix("transformOrigin"),\r
15443             _supports3D = (_checkPropPrefix("perspective") !== null),\r
15444             Transform = _internals.Transform = function() {\r
15445                 this.skewY = 0;\r
15446             },\r
15447 \r
15448             /**\r
15449              * 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.\r
15450              * @param {!Object} t target element\r
15451              * @param {Object=} cs computed style object (optional)\r
15452              * @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...}\r
15453              * @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)\r
15454              * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}\r
15455              */\r
15456             _getTransform = _internals.getTransform = function(t, cs, rec, parse) {\r
15457                 if (t._gsTransform && rec && !parse) {\r
15458                     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.\r
15459                 }\r
15460                 var tm = rec ? t._gsTransform || new Transform() : new Transform(),\r
15461                     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.\r
15462                     min = 0.00002,\r
15463                     rnd = 100000,\r
15464                     minAngle = 179.99,\r
15465                     minPI = minAngle * _DEG2RAD,\r
15466                     zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,\r
15467                     s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;\r
15468                 if (_transformProp) {\r
15469                     s = _getStyle(t, _transformPropCSS, cs, true);\r
15470                 } else if (t.currentStyle) {\r
15471                     //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.\r
15472                     s = t.currentStyle.filter.match(_ieGetMatrixExp);\r
15473                     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(",") : "";\r
15474                 }\r
15475                 //split the matrix values out into an array (m for matrix)\r
15476                 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];\r
15477                 i = m.length;\r
15478                 while (--i > -1) {\r
15479                     n = Number(m[i]);\r
15480                     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).\r
15481                 }\r
15482                 if (m.length === 16) {\r
15483 \r
15484                     //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)\r
15485                     var a13 = m[8], a23 = m[9], a33 = m[10],\r
15486                         a14 = m[12], a24 = m[13], a34 = m[14];\r
15487 \r
15488                     //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari\r
15489                     if (tm.zOrigin) {\r
15490                         a34 = -tm.zOrigin;\r
15491                         a14 = a13*a34-m[12];\r
15492                         a24 = a23*a34-m[13];\r
15493                         a34 = a33*a34+tm.zOrigin-m[14];\r
15494                     }\r
15495 \r
15496                     //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.\r
15497                     if (!rec || parse || tm.rotationX == null) {\r
15498                         var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],\r
15499                             a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],\r
15500                             a43 = m[11],\r
15501                             angle = Math.atan2(a32, a33),\r
15502                             xFlip = (angle < -minPI || angle > minPI),\r
15503                             t1, t2, t3, cos, sin, yFlip, zFlip;\r
15504                         tm.rotationX = angle * _RAD2DEG;\r
15505                         //rotationX\r
15506                         if (angle) {\r
15507                             cos = Math.cos(-angle);\r
15508                             sin = Math.sin(-angle);\r
15509                             t1 = a12*cos+a13*sin;\r
15510                             t2 = a22*cos+a23*sin;\r
15511                             t3 = a32*cos+a33*sin;\r
15512                             a13 = a12*-sin+a13*cos;\r
15513                             a23 = a22*-sin+a23*cos;\r
15514                             a33 = a32*-sin+a33*cos;\r
15515                             a43 = a42*-sin+a43*cos;\r
15516                             a12 = t1;\r
15517                             a22 = t2;\r
15518                             a32 = t3;\r
15519                         }\r
15520                         //rotationY\r
15521                         angle = Math.atan2(a13, a11);\r
15522                         tm.rotationY = angle * _RAD2DEG;\r
15523                         if (angle) {\r
15524                             yFlip = (angle < -minPI || angle > minPI);\r
15525                             cos = Math.cos(-angle);\r
15526                             sin = Math.sin(-angle);\r
15527                             t1 = a11*cos-a13*sin;\r
15528                             t2 = a21*cos-a23*sin;\r
15529                             t3 = a31*cos-a33*sin;\r
15530                             a23 = a21*sin+a23*cos;\r
15531                             a33 = a31*sin+a33*cos;\r
15532                             a43 = a41*sin+a43*cos;\r
15533                             a11 = t1;\r
15534                             a21 = t2;\r
15535                             a31 = t3;\r
15536                         }\r
15537                         //rotationZ\r
15538                         angle = Math.atan2(a21, a22);\r
15539                         tm.rotation = angle * _RAD2DEG;\r
15540                         if (angle) {\r
15541                             zFlip = (angle < -minPI || angle > minPI);\r
15542                             cos = Math.cos(-angle);\r
15543                             sin = Math.sin(-angle);\r
15544                             a11 = a11*cos+a12*sin;\r
15545                             t2 = a21*cos+a22*sin;\r
15546                             a22 = a21*-sin+a22*cos;\r
15547                             a32 = a31*-sin+a32*cos;\r
15548                             a21 = t2;\r
15549                         }\r
15550 \r
15551                         if (zFlip && xFlip) {\r
15552                             tm.rotation = tm.rotationX = 0;\r
15553                         } else if (zFlip && yFlip) {\r
15554                             tm.rotation = tm.rotationY = 0;\r
15555                         } else if (yFlip && xFlip) {\r
15556                             tm.rotationY = tm.rotationX = 0;\r
15557                         }\r
15558 \r
15559                         tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;\r
15560                         tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;\r
15561                         tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;\r
15562                         tm.skewX = 0;\r
15563                         tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;\r
15564                         tm.x = a14;\r
15565                         tm.y = a24;\r
15566                         tm.z = a34;\r
15567                     }\r
15568 \r
15569                 } 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.\r
15570                     var k = (m.length >= 6),\r
15571                         a = k ? m[0] : 1,\r
15572                         b = m[1] || 0,\r
15573                         c = m[2] || 0,\r
15574                         d = k ? m[3] : 1;\r
15575                     tm.x = m[4] || 0;\r
15576                     tm.y = m[5] || 0;\r
15577                     scaleX = Math.sqrt(a * a + b * b);\r
15578                     scaleY = Math.sqrt(d * d + c * c);\r
15579                     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).\r
15580                     skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;\r
15581                     difX = scaleX - Math.abs(tm.scaleX || 0);\r
15582                     difY = scaleY - Math.abs(tm.scaleY || 0);\r
15583                     if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {\r
15584                         if (invX) {\r
15585                             scaleX *= -1;\r
15586                             skewX += (rotation <= 0) ? 180 : -180;\r
15587                             rotation += (rotation <= 0) ? 180 : -180;\r
15588                         } else {\r
15589                             scaleY *= -1;\r
15590                             skewX += (skewX <= 0) ? 180 : -180;\r
15591                         }\r
15592                     }\r
15593                     difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.\r
15594                     difS = (skewX - tm.skewX) % 180;\r
15595                     //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.\r
15596                     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)) {\r
15597                         tm.scaleX = scaleX;\r
15598                         tm.scaleY = scaleY;\r
15599                         tm.rotation = rotation;\r
15600                         tm.skewX = skewX;\r
15601                     }\r
15602                     if (_supports3D) {\r
15603                         tm.rotationX = tm.rotationY = tm.z = 0;\r
15604                         tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;\r
15605                         tm.scaleZ = 1;\r
15606                     }\r
15607                 }\r
15608                 tm.zOrigin = zOrigin;\r
15609 \r
15610                 //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.\r
15611                 for (i in tm) {\r
15612                     if (tm[i] < min) if (tm[i] > -min) {\r
15613                         tm[i] = 0;\r
15614                     }\r
15615                 }\r
15616                 //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);\r
15617                 if (rec) {\r
15618                     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)\r
15619                 }\r
15620                 return tm;\r
15621             },\r
15622 \r
15623             //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)\r
15624             _setIETransformRatio = function(v) {\r
15625                 var t = this.data, //refers to the element's _gsTransform object\r
15626                     ang = -t.rotation * _DEG2RAD,\r
15627                     skew = ang + t.skewX * _DEG2RAD,\r
15628                     rnd = 100000,\r
15629                     a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,\r
15630                     b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,\r
15631                     c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,\r
15632                     d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,\r
15633                     style = this.t.style,\r
15634                     cs = this.t.currentStyle,\r
15635                     filters, val;\r
15636                 if (!cs) {\r
15637                     return;\r
15638                 }\r
15639                 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)\r
15640                 b = -c;\r
15641                 c = -val;\r
15642                 filters = cs.filter;\r
15643                 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight\r
15644                 var w = this.t.offsetWidth,\r
15645                     h = this.t.offsetHeight,\r
15646                     clip = (cs.position !== "absolute"),\r
15647                     m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,\r
15648                     ox = t.x,\r
15649                     oy = t.y,\r
15650                     dx, dy;\r
15651 \r
15652                 //if transformOrigin is being used, adjust the offset x and y\r
15653                 if (t.ox != null) {\r
15654                     dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;\r
15655                     dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;\r
15656                     ox += dx - (dx * a + dy * b);\r
15657                     oy += dy - (dx * c + dy * d);\r
15658                 }\r
15659 \r
15660                 if (!clip) {\r
15661                     m += ", sizingMethod='auto expand')";\r
15662                 } else {\r
15663                     dx = (w / 2);\r
15664                     dy = (h / 2);\r
15665                     //translate to ensure that transformations occur around the correct origin (default is center).\r
15666                     m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";\r
15667                 }\r
15668                 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {\r
15669                     style.filter = filters.replace(_ieSetMatrixExp, m);\r
15670                 } else {\r
15671                     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.\r
15672                 }\r
15673 \r
15674                 //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.\r
15675                 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) {\r
15676                     style.removeAttribute("filter");\r
15677                 }\r
15678 \r
15679                 //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).\r
15680                 if (!clip) {\r
15681                     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\r
15682                         marg, prop, dif;\r
15683                     dx = t.ieOffsetX || 0;\r
15684                     dy = t.ieOffsetY || 0;\r
15685                     t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);\r
15686                     t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);\r
15687                     for (i = 0; i < 4; i++) {\r
15688                         prop = _margins[i];\r
15689                         marg = cs[prop];\r
15690                         //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)\r
15691                         val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;\r
15692                         if (val !== t[prop]) {\r
15693                             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.\r
15694                         } else {\r
15695                             dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;\r
15696                         }\r
15697                         style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";\r
15698                     }\r
15699                 }\r
15700             },\r
15701 \r
15702             _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {\r
15703                 var t = this.data, //refers to the element's _gsTransform object\r
15704                     style = this.t.style,\r
15705                     angle = t.rotation * _DEG2RAD,\r
15706                     sx = t.scaleX,\r
15707                     sy = t.scaleY,\r
15708                     sz = t.scaleZ,\r
15709                     perspective = t.perspective,\r
15710                     a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,\r
15711                     zOrigin, rnd, cos, sin, t1, t2, t3, t4;\r
15712                 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\r
15713                     _set2DTransformRatio.call(this, v);\r
15714                     return;\r
15715                 }\r
15716                 if (_isFirefox) {\r
15717                     var n = 0.0001;\r
15718                     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.\r
15719                         sx = sz = 0.00002;\r
15720                     }\r
15721                     if (sy < n && sy > -n) {\r
15722                         sy = sz = 0.00002;\r
15723                     }\r
15724                     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).\r
15725                         perspective = 0;\r
15726                     }\r
15727                 }\r
15728                 if (angle || t.skewX) {\r
15729                     cos = Math.cos(angle);\r
15730                     sin = Math.sin(angle);\r
15731                     a11 = cos;\r
15732                     a21 = sin;\r
15733                     if (t.skewX) {\r
15734                         angle -= t.skewX * _DEG2RAD;\r
15735                         cos = Math.cos(angle);\r
15736                         sin = Math.sin(angle);\r
15737                         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\r
15738                             t1 = Math.tan(t.skewX * _DEG2RAD);\r
15739                             t1 = Math.sqrt(1 + t1 * t1);\r
15740                             cos *= t1;\r
15741                             sin *= t1;\r
15742                         }\r
15743                     }\r
15744                     a12 = -sin;\r
15745                     a22 = cos;\r
15746 \r
15747                 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...\r
15748                     style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");\r
15749                     return;\r
15750                 } else {\r
15751                     a11 = a22 = 1;\r
15752                     a12 = a21 = 0;\r
15753                 }\r
15754                 a33 = 1;\r
15755                 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;\r
15756                 a43 = (perspective) ? -1 / perspective : 0;\r
15757                 zOrigin = t.zOrigin;\r
15758                 rnd = 100000;\r
15759                 angle = t.rotationY * _DEG2RAD;\r
15760                 if (angle) {\r
15761                     cos = Math.cos(angle);\r
15762                     sin = Math.sin(angle);\r
15763                     a31 = a33*-sin;\r
15764                     a41 = a43*-sin;\r
15765                     a13 = a11*sin;\r
15766                     a23 = a21*sin;\r
15767                     a33 *= cos;\r
15768                     a43 *= cos;\r
15769                     a11 *= cos;\r
15770                     a21 *= cos;\r
15771                 }\r
15772                 angle = t.rotationX * _DEG2RAD;\r
15773                 if (angle) {\r
15774                     cos = Math.cos(angle);\r
15775                     sin = Math.sin(angle);\r
15776                     t1 = a12*cos+a13*sin;\r
15777                     t2 = a22*cos+a23*sin;\r
15778                     t3 = a32*cos+a33*sin;\r
15779                     t4 = a42*cos+a43*sin;\r
15780                     a13 = a12*-sin+a13*cos;\r
15781                     a23 = a22*-sin+a23*cos;\r
15782                     a33 = a32*-sin+a33*cos;\r
15783                     a43 = a42*-sin+a43*cos;\r
15784                     a12 = t1;\r
15785                     a22 = t2;\r
15786                     a32 = t3;\r
15787                     a42 = t4;\r
15788                 }\r
15789                 if (sz !== 1) {\r
15790                     a13*=sz;\r
15791                     a23*=sz;\r
15792                     a33*=sz;\r
15793                     a43*=sz;\r
15794                 }\r
15795                 if (sy !== 1) {\r
15796                     a12*=sy;\r
15797                     a22*=sy;\r
15798                     a32*=sy;\r
15799                     a42*=sy;\r
15800                 }\r
15801                 if (sx !== 1) {\r
15802                     a11*=sx;\r
15803                     a21*=sx;\r
15804                     a31*=sx;\r
15805                     a41*=sx;\r
15806                 }\r
15807                 if (zOrigin) {\r
15808                     a34 -= zOrigin;\r
15809                     a14 = a13*a34;\r
15810                     a24 = a23*a34;\r
15811                     a34 = a33*a34+zOrigin;\r
15812                 }\r
15813                 //we round the x, y, and z slightly differently to allow even larger values.\r
15814                 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;\r
15815                 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;\r
15816                 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;\r
15817                 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(",") + ")";\r
15818             },\r
15819 \r
15820             _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {\r
15821                 var t = this.data, //refers to the element's _gsTransform object\r
15822                     targ = this.t,\r
15823                     style = targ.style,\r
15824                     ang, skew, rnd, sx, sy;\r
15825                 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.\r
15826                     this.setRatio = _set3DTransformRatio;\r
15827                     _set3DTransformRatio.call(this, v);\r
15828                     return;\r
15829                 }\r
15830                 if (!t.rotation && !t.skewX) {\r
15831                     style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";\r
15832                 } else {\r
15833                     ang = t.rotation * _DEG2RAD;\r
15834                     skew = ang - t.skewX * _DEG2RAD;\r
15835                     rnd = 100000;\r
15836                     sx = t.scaleX * rnd;\r
15837                     sy = t.scaleY * rnd;\r
15838                     //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.\r
15839                     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 + ")";\r
15840                 }\r
15841             };\r
15842 \r
15843         _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) {\r
15844             if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.\r
15845             var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),\r
15846                 style = t.style,\r
15847                 min = 0.000001,\r
15848                 i = _transformProps.length,\r
15849                 v = vars,\r
15850                 endRotations = {},\r
15851                 m2, skewY, copy, orig, has3D, hasChange, dr;\r
15852             if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"\r
15853                 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.\r
15854                 copy[_transformProp] = v.transform;\r
15855                 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.\r
15856                 copy.position = "absolute";\r
15857                 _doc.body.appendChild(_tempDiv);\r
15858                 m2 = _getTransform(_tempDiv, null, false);\r
15859                 _doc.body.removeChild(_tempDiv);\r
15860             } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)\r
15861                 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),\r
15862                     scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),\r
15863                     scaleZ:_parseVal(v.scaleZ, m1.scaleZ),\r
15864                     x:_parseVal(v.x, m1.x),\r
15865                     y:_parseVal(v.y, m1.y),\r
15866                     z:_parseVal(v.z, m1.z),\r
15867                     perspective:_parseVal(v.transformPerspective, m1.perspective)};\r
15868                 dr = v.directionalRotation;\r
15869                 if (dr != null) {\r
15870                     if (typeof(dr) === "object") {\r
15871                         for (copy in dr) {\r
15872                             v[copy] = dr[copy];\r
15873                         }\r
15874                     } else {\r
15875                         v.rotation = dr;\r
15876                     }\r
15877                 }\r
15878                 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);\r
15879                 if (_supports3D) {\r
15880                     m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);\r
15881                     m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);\r
15882                 }\r
15883                 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);\r
15884 \r
15885                 //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.\r
15886                 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);\r
15887                 if ((skewY = m2.skewY - m1.skewY)) {\r
15888                     m2.skewX += skewY;\r
15889                     m2.rotation += skewY;\r
15890                 }\r
15891             }\r
15892 \r
15893             if (_supports3D && v.force3D != null) {\r
15894                 m1.force3D = v.force3D;\r
15895                 hasChange = true;\r
15896             }\r
15897 \r
15898             m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;\r
15899 \r
15900             has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);\r
15901             if (!has3D && v.scale != null) {\r
15902                 m2.scaleZ = 1; //no need to tween scaleZ.\r
15903             }\r
15904 \r
15905             while (--i > -1) {\r
15906                 p = _transformProps[i];\r
15907                 orig = m2[p] - m1[p];\r
15908                 if (orig > min || orig < -min || _forcePT[p] != null) {\r
15909                     hasChange = true;\r
15910                     pt = new CSSPropTween(m1, p, m1[p], orig, pt);\r
15911                     if (p in endRotations) {\r
15912                         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\r
15913                     }\r
15914                     pt.xs0 = 0; //ensures the value stays numeric in setRatio()\r
15915                     pt.plugin = plugin;\r
15916                     cssp._overwriteProps.push(pt.n);\r
15917                 }\r
15918             }\r
15919 \r
15920             orig = v.transformOrigin;\r
15921             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).\r
15922                 if (_transformProp) {\r
15923                     hasChange = true;\r
15924                     p = _transformOriginProp;\r
15925                     orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors\r
15926                     pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");\r
15927                     pt.b = style[p];\r
15928                     pt.plugin = plugin;\r
15929                     if (_supports3D) {\r
15930                         copy = m1.zOrigin;\r
15931                         orig = orig.split(" ");\r
15932                         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.\r
15933                         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)!\r
15934                         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)\r
15935                         pt.b = copy;\r
15936                         pt.xs0 = pt.e = m1.zOrigin;\r
15937                     } else {\r
15938                         pt.xs0 = pt.e = orig;\r
15939                     }\r
15940 \r
15941                 //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).\r
15942                 } else {\r
15943                     _parsePosition(orig + "", m1);\r
15944                 }\r
15945             }\r
15946 \r
15947             if (hasChange) {\r
15948                 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();\r
15949             }\r
15950             return pt;\r
15951         }, prefix:true});\r
15952 \r
15953         _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});\r
15954 \r
15955         _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {\r
15956             e = this.format(e);\r
15957             var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],\r
15958                 style = t.style,\r
15959                 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;\r
15960             w = parseFloat(t.offsetWidth);\r
15961             h = parseFloat(t.offsetHeight);\r
15962             ea1 = e.split(" ");\r
15963             for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!\r
15964                 if (this.p.indexOf("border")) { //older browsers used a prefix\r
15965                     props[i] = _checkPropPrefix(props[i]);\r
15966                 }\r
15967                 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");\r
15968                 if (bs.indexOf(" ") !== -1) {\r
15969                     bs2 = bs.split(" ");\r
15970                     bs = bs2[0];\r
15971                     bs2 = bs2[1];\r
15972                 }\r
15973                 es = es2 = ea1[i];\r
15974                 bn = parseFloat(bs);\r
15975                 bsfx = bs.substr((bn + "").length);\r
15976                 rel = (es.charAt(1) === "=");\r
15977                 if (rel) {\r
15978                     en = parseInt(es.charAt(0)+"1", 10);\r
15979                     es = es.substr(2);\r
15980                     en *= parseFloat(es);\r
15981                     esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";\r
15982                 } else {\r
15983                     en = parseFloat(es);\r
15984                     esfx = es.substr((en + "").length);\r
15985                 }\r
15986                 if (esfx === "") {\r
15987                     esfx = _suffixMap[p] || bsfx;\r
15988                 }\r
15989                 if (esfx !== bsfx) {\r
15990                     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.\r
15991                     vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number\r
15992                     if (esfx === "%") {\r
15993                         bs = (hn / w * 100) + "%";\r
15994                         bs2 = (vn / h * 100) + "%";\r
15995                     } else if (esfx === "em") {\r
15996                         em = _convertToPixels(t, "borderLeft", 1, "em");\r
15997                         bs = (hn / em) + "em";\r
15998                         bs2 = (vn / em) + "em";\r
15999                     } else {\r
16000                         bs = hn + "px";\r
16001                         bs2 = vn + "px";\r
16002                     }\r
16003                     if (rel) {\r
16004                         es = (parseFloat(bs) + en) + esfx;\r
16005                         es2 = (parseFloat(bs2) + en) + esfx;\r
16006                     }\r
16007                 }\r
16008                 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);\r
16009             }\r
16010             return pt;\r
16011         }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});\r
16012         _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {\r
16013             var bp = "background-position",\r
16014                 cs = (_cs || _getComputedStyle(t, null)),\r
16015                 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\r
16016                 es = this.format(e),\r
16017                 ba, ea, i, pct, overlap, src;\r
16018             if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {\r
16019                 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");\r
16020                 if (src && src !== "none") {\r
16021                     ba = bs.split(" ");\r
16022                     ea = es.split(" ");\r
16023                     _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height\r
16024                     i = 2;\r
16025                     while (--i > -1) {\r
16026                         bs = ba[i];\r
16027                         pct = (bs.indexOf("%") !== -1);\r
16028                         if (pct !== (ea[i].indexOf("%") !== -1)) {\r
16029                             overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;\r
16030                             ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";\r
16031                         }\r
16032                     }\r
16033                     bs = ba.join(" ");\r
16034                 }\r
16035             }\r
16036             return this.parseComplex(t.style, bs, es, pt, plugin);\r
16037         }, formatter:_parsePosition});\r
16038         _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});\r
16039         _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});\r
16040         _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});\r
16041         _registerComplexSpecialProp("transformStyle", {prefix:true});\r
16042         _registerComplexSpecialProp("backfaceVisibility", {prefix:true});\r
16043         _registerComplexSpecialProp("userSelect", {prefix:true});\r
16044         _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});\r
16045         _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});\r
16046         _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){\r
16047             var b, cs, delim;\r
16048             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.\r
16049                 cs = t.currentStyle;\r
16050                 delim = _ieVers < 8 ? " " : ",";\r
16051                 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";\r
16052                 e = this.format(e).split(",").join(delim);\r
16053             } else {\r
16054                 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));\r
16055                 e = this.format(e);\r
16056             }\r
16057             return this.parseComplex(t.style, b, e, pt, plugin);\r
16058         }});\r
16059         _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});\r
16060         _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)\r
16061         _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {\r
16062                 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);\r
16063             }, color:true, formatter:function(v) {\r
16064                 var a = v.split(" ");\r
16065                 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];\r
16066             }});\r
16067         _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).\r
16068         _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {\r
16069             var s = t.style,\r
16070                 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";\r
16071             return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);\r
16072         }});\r
16073 \r
16074         //opacity-related\r
16075         var _setIEOpacityRatio = function(v) {\r
16076                 var t = this.t, //refers to the element's style property\r
16077                     filters = t.filter || _getStyle(this.data, "filter"),\r
16078                     val = (this.s + this.c * v) | 0,\r
16079                     skip;\r
16080                 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.\r
16081                     if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {\r
16082                         t.removeAttribute("filter");\r
16083                         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.\r
16084                     } else {\r
16085                         t.filter = filters.replace(_alphaFilterExp, "");\r
16086                         skip = true;\r
16087                     }\r
16088                 }\r
16089                 if (!skip) {\r
16090                     if (this.xn1) {\r
16091                         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.\r
16092                     }\r
16093                     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\r
16094                         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)\r
16095                             t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.\r
16096                         }\r
16097                     } else {\r
16098                         t.filter = filters.replace(_opacityExp, "opacity=" + val);\r
16099                     }\r
16100                 }\r
16101             };\r
16102         _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {\r
16103             var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),\r
16104                 style = t.style,\r
16105                 isAutoAlpha = (p === "autoAlpha");\r
16106             if (typeof(e) === "string" && e.charAt(1) === "=") {\r
16107                 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;\r
16108             }\r
16109             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)\r
16110                 b = 0;\r
16111             }\r
16112             if (_supportsOpacity) {\r
16113                 pt = new CSSPropTween(style, "opacity", b, e - b, pt);\r
16114             } else {\r
16115                 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);\r
16116                 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.\r
16117                 style.zoom = 1; //helps correct an IE issue.\r
16118                 pt.type = 2;\r
16119                 pt.b = "alpha(opacity=" + pt.s + ")";\r
16120                 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";\r
16121                 pt.data = t;\r
16122                 pt.plugin = plugin;\r
16123                 pt.setRatio = _setIEOpacityRatio;\r
16124             }\r
16125             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\r
16126                 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));\r
16127                 pt.xs0 = "inherit";\r
16128                 cssp._overwriteProps.push(pt.n);\r
16129                 cssp._overwriteProps.push(p);\r
16130             }\r
16131             return pt;\r
16132         }});\r
16133 \r
16134 \r
16135         var _removeProp = function(s, p) {\r
16136                 if (p) {\r
16137                     if (s.removeProperty) {\r
16138                         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)\r
16139                             p = "M" + p.substr(1);\r
16140                         }\r
16141                         s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());\r
16142                     } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"\r
16143                         s.removeAttribute(p);\r
16144                     }\r
16145                 }\r
16146             },\r
16147             _setClassNameRatio = function(v) {\r
16148                 this.t._gsClassPT = this;\r
16149                 if (v === 1 || v === 0) {\r
16150                     this.t.setAttribute("class", (v === 0) ? this.b : this.e);\r
16151                     var mpt = this.data, //first MiniPropTween\r
16152                         s = this.t.style;\r
16153                     while (mpt) {\r
16154                         if (!mpt.v) {\r
16155                             _removeProp(s, mpt.p);\r
16156                         } else {\r
16157                             s[mpt.p] = mpt.v;\r
16158                         }\r
16159                         mpt = mpt._next;\r
16160                     }\r
16161                     if (v === 1 && this.t._gsClassPT === this) {\r
16162                         this.t._gsClassPT = null;\r
16163                     }\r
16164                 } else if (this.t.getAttribute("class") !== this.e) {\r
16165                     this.t.setAttribute("class", this.e);\r
16166                 }\r
16167             };\r
16168         _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {\r
16169             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.\r
16170                 cssText = t.style.cssText,\r
16171                 difData, bs, cnpt, cnptLookup, mpt;\r
16172             pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);\r
16173             pt.setRatio = _setClassNameRatio;\r
16174             pt.pr = -11;\r
16175             _hasPriority = true;\r
16176             pt.b = b;\r
16177             bs = _getAllStyles(t, _cs);\r
16178             //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)\r
16179             cnpt = t._gsClassPT;\r
16180             if (cnpt) {\r
16181                 cnptLookup = {};\r
16182                 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.\r
16183                 while (mpt) {\r
16184                     cnptLookup[mpt.p] = 1;\r
16185                     mpt = mpt._next;\r
16186                 }\r
16187                 cnpt.setRatio(1);\r
16188             }\r
16189             t._gsClassPT = pt;\r
16190             pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");\r
16191             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.\r
16192                 t.setAttribute("class", pt.e);\r
16193                 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);\r
16194                 t.setAttribute("class", b);\r
16195                 pt.data = difData.firstMPT;\r
16196                 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).\r
16197                 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)\r
16198             }\r
16199             return pt;\r
16200         }});\r
16201 \r
16202 \r
16203         var _setClearPropsRatio = function(v) {\r
16204             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).\r
16205                 var s = this.t.style,\r
16206                     transformParse = _specialProps.transform.parse,\r
16207                     a, p, i, clearTransform;\r
16208                 if (this.e === "all") {\r
16209                     s.cssText = "";\r
16210                     clearTransform = true;\r
16211                 } else {\r
16212                     a = this.e.split(",");\r
16213                     i = a.length;\r
16214                     while (--i > -1) {\r
16215                         p = a[i];\r
16216                         if (_specialProps[p]) {\r
16217                             if (_specialProps[p].parse === transformParse) {\r
16218                                 clearTransform = true;\r
16219                             } else {\r
16220                                 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"\r
16221                             }\r
16222                         }\r
16223                         _removeProp(s, p);\r
16224                     }\r
16225                 }\r
16226                 if (clearTransform) {\r
16227                     _removeProp(s, _transformProp);\r
16228                     if (this.t._gsTransform) {\r
16229                         delete this.t._gsTransform;\r
16230                     }\r
16231                 }\r
16232 \r
16233             }\r
16234         };\r
16235         _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {\r
16236             pt = new CSSPropTween(t, p, 0, 0, pt, 2);\r
16237             pt.setRatio = _setClearPropsRatio;\r
16238             pt.e = e;\r
16239             pt.pr = -10;\r
16240             pt.data = cssp._tween;\r
16241             _hasPriority = true;\r
16242             return pt;\r
16243         }});\r
16244 \r
16245         p = "bezier,throwProps,physicsProps,physics2D".split(",");\r
16246         i = p.length;\r
16247         while (i--) {\r
16248             _registerPluginProp(p[i]);\r
16249         }\r
16250 \r
16251 \r
16252 \r
16253 \r
16254 \r
16255 \r
16256 \r
16257 \r
16258         p = CSSPlugin.prototype;\r
16259         p._firstPT = null;\r
16260 \r
16261         //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.\r
16262         p._onInitTween = function(target, vars, tween) {\r
16263             if (!target.nodeType) { //css is only for dom elements\r
16264                 return false;\r
16265             }\r
16266             this._target = target;\r
16267             this._tween = tween;\r
16268             this._vars = vars;\r
16269             _autoRound = vars.autoRound;\r
16270             _hasPriority = false;\r
16271             _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;\r
16272             _cs = _getComputedStyle(target, "");\r
16273             _overwriteProps = this._overwriteProps;\r
16274             var style = target.style,\r
16275                 v, pt, pt2, first, last, next, zIndex, tpt, threeD;\r
16276             if (_reqSafariFix) if (style.zIndex === "") {\r
16277                 v = _getStyle(target, "zIndex", _cs);\r
16278                 if (v === "auto" || v === "") {\r
16279                     //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.\r
16280                     this._addLazySet(style, "zIndex", 0);\r
16281                 }\r
16282             }\r
16283 \r
16284             if (typeof(vars) === "string") {\r
16285                 first = style.cssText;\r
16286                 v = _getAllStyles(target, _cs);\r
16287                 style.cssText = first + ";" + vars;\r
16288                 v = _cssDif(target, v, _getAllStyles(target)).difs;\r
16289                 if (!_supportsOpacity && _opacityValExp.test(vars)) {\r
16290                     v.opacity = parseFloat( RegExp.$1 );\r
16291                 }\r
16292                 vars = v;\r
16293                 style.cssText = first;\r
16294             }\r
16295             this._firstPT = pt = this.parse(target, vars, null);\r
16296 \r
16297             if (this._transformType) {\r
16298                 threeD = (this._transformType === 3);\r
16299                 if (!_transformProp) {\r
16300                     style.zoom = 1; //helps correct an IE issue.\r
16301                 } else if (_isSafari) {\r
16302                     _reqSafariFix = true;\r
16303                     //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).\r
16304                     if (style.zIndex === "") {\r
16305                         zIndex = _getStyle(target, "zIndex", _cs);\r
16306                         if (zIndex === "auto" || zIndex === "") {\r
16307                             this._addLazySet(style, "zIndex", 0);\r
16308                         }\r
16309                     }\r
16310                     //Setting WebkitBackfaceVisibility corrects 3 bugs:\r
16311                     // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.\r
16312                     // 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.\r
16313                     // 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.\r
16314                     //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.\r
16315                     if (_isSafariLT6) {\r
16316                         this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));\r
16317                     }\r
16318                 }\r
16319                 pt2 = pt;\r
16320                 while (pt2 && pt2._next) {\r
16321                     pt2 = pt2._next;\r
16322                 }\r
16323                 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);\r
16324                 this._linkCSSP(tpt, null, pt2);\r
16325                 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;\r
16326                 tpt.data = this._transform || _getTransform(target, _cs, true);\r
16327                 _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.\r
16328             }\r
16329 \r
16330             if (_hasPriority) {\r
16331                 //reorders the linked list in order of pr (priority)\r
16332                 while (pt) {\r
16333                     next = pt._next;\r
16334                     pt2 = first;\r
16335                     while (pt2 && pt2.pr > pt.pr) {\r
16336                         pt2 = pt2._next;\r
16337                     }\r
16338                     if ((pt._prev = pt2 ? pt2._prev : last)) {\r
16339                         pt._prev._next = pt;\r
16340                     } else {\r
16341                         first = pt;\r
16342                     }\r
16343                     if ((pt._next = pt2)) {\r
16344                         pt2._prev = pt;\r
16345                     } else {\r
16346                         last = pt;\r
16347                     }\r
16348                     pt = next;\r
16349                 }\r
16350                 this._firstPT = first;\r
16351             }\r
16352             return true;\r
16353         };\r
16354 \r
16355 \r
16356         p.parse = function(target, vars, pt, plugin) {\r
16357             var style = target.style,\r
16358                 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;\r
16359             for (p in vars) {\r
16360                 es = vars[p]; //ending value string\r
16361                 sp = _specialProps[p]; //SpecialProp lookup.\r
16362                 if (sp) {\r
16363                     pt = sp.parse(target, es, p, this, pt, plugin, vars);\r
16364 \r
16365                 } else {\r
16366                     bs = _getStyle(target, p, _cs) + "";\r
16367                     isStr = (typeof(es) === "string");\r
16368                     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:\r
16369                         if (!isStr) {\r
16370                             es = _parseColor(es);\r
16371                             es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";\r
16372                         }\r
16373                         pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);\r
16374 \r
16375                     } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {\r
16376                         pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);\r
16377 \r
16378                     } else {\r
16379                         bn = parseFloat(bs);\r
16380                         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.\r
16381 \r
16382                         if (bs === "" || bs === "auto") {\r
16383                             if (p === "width" || p === "height") {\r
16384                                 bn = _getDimension(target, p, _cs);\r
16385                                 bsfx = "px";\r
16386                             } else if (p === "left" || p === "top") {\r
16387                                 bn = _calculateOffset(target, p, _cs);\r
16388                                 bsfx = "px";\r
16389                             } else {\r
16390                                 bn = (p !== "opacity") ? 0 : 1;\r
16391                                 bsfx = "";\r
16392                             }\r
16393                         }\r
16394 \r
16395                         rel = (isStr && es.charAt(1) === "=");\r
16396                         if (rel) {\r
16397                             en = parseInt(es.charAt(0) + "1", 10);\r
16398                             es = es.substr(2);\r
16399                             en *= parseFloat(es);\r
16400                             esfx = es.replace(_suffixExp, "");\r
16401                         } else {\r
16402                             en = parseFloat(es);\r
16403                             esfx = isStr ? es.substr((en + "").length) || "" : "";\r
16404                         }\r
16405 \r
16406                         if (esfx === "") {\r
16407                             esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.\r
16408                         }\r
16409 \r
16410                         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.\r
16411 \r
16412                         //if the beginning/ending suffixes don't match, normalize them...\r
16413                         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!\r
16414                             bn = _convertToPixels(target, p, bn, bsfx);\r
16415                             if (esfx === "%") {\r
16416                                 bn /= _convertToPixels(target, p, 100, "%") / 100;\r
16417                                 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.\r
16418                                     bs = bn + "%";\r
16419                                 }\r
16420 \r
16421                             } else if (esfx === "em") {\r
16422                                 bn /= _convertToPixels(target, p, 1, "em");\r
16423 \r
16424                             //otherwise convert to pixels.\r
16425                             } else if (esfx !== "px") {\r
16426                                 en = _convertToPixels(target, p, en, esfx);\r
16427                                 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.\r
16428                             }\r
16429                             if (rel) if (en || en === 0) {\r
16430                                 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.\r
16431                             }\r
16432                         }\r
16433 \r
16434                         if (rel) {\r
16435                             en += bn;\r
16436                         }\r
16437 \r
16438                         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.\r
16439                             pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);\r
16440                             pt.xs0 = esfx;\r
16441                             //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);\r
16442                         } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {\r
16443                             _log("invalid " + p + " tween value: " + vars[p]);\r
16444                         } else {\r
16445                             pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);\r
16446                             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.\r
16447                             //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);\r
16448                         }\r
16449                     }\r
16450                 }\r
16451                 if (plugin) if (pt && !pt.plugin) {\r
16452                     pt.plugin = plugin;\r
16453                 }\r
16454             }\r
16455             return pt;\r
16456         };\r
16457 \r
16458 \r
16459         //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.\r
16460         p.setRatio = function(v) {\r
16461             var pt = this._firstPT,\r
16462                 min = 0.000001,\r
16463                 val, str, i;\r
16464 \r
16465             //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).\r
16466             if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {\r
16467                 while (pt) {\r
16468                     if (pt.type !== 2) {\r
16469                         pt.t[pt.p] = pt.e;\r
16470                     } else {\r
16471                         pt.setRatio(v);\r
16472                     }\r
16473                     pt = pt._next;\r
16474                 }\r
16475 \r
16476             } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {\r
16477                 while (pt) {\r
16478                     val = pt.c * v + pt.s;\r
16479                     if (pt.r) {\r
16480                         val = Math.round(val);\r
16481                     } else if (val < min) if (val > -min) {\r
16482                         val = 0;\r
16483                     }\r
16484                     if (!pt.type) {\r
16485                         pt.t[pt.p] = val + pt.xs0;\r
16486                     } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"\r
16487                         i = pt.l;\r
16488                         if (i === 2) {\r
16489                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;\r
16490                         } else if (i === 3) {\r
16491                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;\r
16492                         } else if (i === 4) {\r
16493                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;\r
16494                         } else if (i === 5) {\r
16495                             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;\r
16496                         } else {\r
16497                             str = pt.xs0 + val + pt.xs1;\r
16498                             for (i = 1; i < pt.l; i++) {\r
16499                                 str += pt["xn"+i] + pt["xs"+(i+1)];\r
16500                             }\r
16501                             pt.t[pt.p] = str;\r
16502                         }\r
16503 \r
16504                     } else if (pt.type === -1) { //non-tweening value\r
16505                         pt.t[pt.p] = pt.xs0;\r
16506 \r
16507                     } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.\r
16508                         pt.setRatio(v);\r
16509                     }\r
16510                     pt = pt._next;\r
16511                 }\r
16512 \r
16513             //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).\r
16514             } else {\r
16515                 while (pt) {\r
16516                     if (pt.type !== 2) {\r
16517                         pt.t[pt.p] = pt.b;\r
16518                     } else {\r
16519                         pt.setRatio(v);\r
16520                     }\r
16521                     pt = pt._next;\r
16522                 }\r
16523             }\r
16524         };\r
16525 \r
16526         /**\r
16527          * @private\r
16528          * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.\r
16529          * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked\r
16530          * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call\r
16531          * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin\r
16532          * doesn't have any transform-related properties of its own. You can call this method as many times as you\r
16533          * want and it won't create duplicate CSSPropTweens.\r
16534          *\r
16535          * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)\r
16536          */\r
16537         p._enableTransforms = function(threeD) {\r
16538             this._transformType = (threeD || this._transformType === 3) ? 3 : 2;\r
16539             this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.\r
16540         };\r
16541 \r
16542         var lazySet = function(v) {\r
16543             this.t[this.p] = this.e;\r
16544             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.\r
16545         };\r
16546         /** @private Gives us a way to set a value on the first render (and only the first render). **/\r
16547         p._addLazySet = function(t, p, v) {\r
16548             var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);\r
16549             pt.e = v;\r
16550             pt.setRatio = lazySet;\r
16551             pt.data = this;\r
16552         };\r
16553 \r
16554         /** @private **/\r
16555         p._linkCSSP = function(pt, next, prev, remove) {\r
16556             if (pt) {\r
16557                 if (next) {\r
16558                     next._prev = pt;\r
16559                 }\r
16560                 if (pt._next) {\r
16561                     pt._next._prev = pt._prev;\r
16562                 }\r
16563                 if (pt._prev) {\r
16564                     pt._prev._next = pt._next;\r
16565                 } else if (this._firstPT === pt) {\r
16566                     this._firstPT = pt._next;\r
16567                     remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)\r
16568                 }\r
16569                 if (prev) {\r
16570                     prev._next = pt;\r
16571                 } else if (!remove && this._firstPT === null) {\r
16572                     this._firstPT = pt;\r
16573                 }\r
16574                 pt._next = next;\r
16575                 pt._prev = prev;\r
16576             }\r
16577             return pt;\r
16578         };\r
16579 \r
16580         //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.\r
16581         p._kill = function(lookup) {\r
16582             var copy = lookup,\r
16583                 pt, p, xfirst;\r
16584             if (lookup.autoAlpha || lookup.alpha) {\r
16585                 copy = {};\r
16586                 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.\r
16587                     copy[p] = lookup[p];\r
16588                 }\r
16589                 copy.opacity = 1;\r
16590                 if (copy.autoAlpha) {\r
16591                     copy.visibility = 1;\r
16592                 }\r
16593             }\r
16594             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".\r
16595                 xfirst = pt.xfirst;\r
16596                 if (xfirst && xfirst._prev) {\r
16597                     this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev\r
16598                 } else if (xfirst === this._firstPT) {\r
16599                     this._firstPT = pt._next;\r
16600                 }\r
16601                 if (pt._next) {\r
16602                     this._linkCSSP(pt._next, pt._next._next, xfirst._prev);\r
16603                 }\r
16604                 this._classNamePT = null;\r
16605             }\r
16606             return TweenPlugin.prototype._kill.call(this, copy);\r
16607         };\r
16608 \r
16609 \r
16610 \r
16611         //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.\r
16612         var _getChildStyles = function(e, props, targets) {\r
16613                 var children, i, child, type;\r
16614                 if (e.slice) {\r
16615                     i = e.length;\r
16616                     while (--i > -1) {\r
16617                         _getChildStyles(e[i], props, targets);\r
16618                     }\r
16619                     return;\r
16620                 }\r
16621                 children = e.childNodes;\r
16622                 i = children.length;\r
16623                 while (--i > -1) {\r
16624                     child = children[i];\r
16625                     type = child.type;\r
16626                     if (child.style) {\r
16627                         props.push(_getAllStyles(child));\r
16628                         if (targets) {\r
16629                             targets.push(child);\r
16630                         }\r
16631                     }\r
16632                     if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {\r
16633                         _getChildStyles(child, props, targets);\r
16634                     }\r
16635                 }\r
16636             };\r
16637 \r
16638         /**\r
16639          * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite\r
16640          * and then compares the style properties of all the target's child elements at the tween's start and end, and\r
16641          * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting\r
16642          * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is\r
16643          * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens\r
16644          * is because it creates entirely new tweens that may have completely different targets than the original tween,\r
16645          * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API\r
16646          * and it would create other problems. For example:\r
16647          *  - 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)\r
16648          *  - 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.\r
16649          *  - 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.\r
16650          *\r
16651          * @param {Object} target object to be tweened\r
16652          * @param {number} Duration in seconds (or frames for frames-based tweens)\r
16653          * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}\r
16654          * @return {Array} An array of TweenLite instances\r
16655          */\r
16656         CSSPlugin.cascadeTo = function(target, duration, vars) {\r
16657             var tween = TweenLite.to(target, duration, vars),\r
16658                 results = [tween],\r
16659                 b = [],\r
16660                 e = [],\r
16661                 targets = [],\r
16662                 _reservedProps = TweenLite._internals.reservedProps,\r
16663                 i, difs, p;\r
16664             target = tween._targets || tween.target;\r
16665             _getChildStyles(target, b, targets);\r
16666             tween.render(duration, true);\r
16667             _getChildStyles(target, e);\r
16668             tween.render(0, true);\r
16669             tween._enabled(true);\r
16670             i = targets.length;\r
16671             while (--i > -1) {\r
16672                 difs = _cssDif(targets[i], b[i], e[i]);\r
16673                 if (difs.firstMPT) {\r
16674                     difs = difs.difs;\r
16675                     for (p in vars) {\r
16676                         if (_reservedProps[p]) {\r
16677                             difs[p] = vars[p];\r
16678                         }\r
16679                     }\r
16680                     results.push( TweenLite.to(targets[i], duration, difs) );\r
16681                 }\r
16682             }\r
16683             return results;\r
16684         };\r
16685 \r
16686         TweenPlugin.activate([CSSPlugin]);\r
16687         return CSSPlugin;\r
16688 \r
16689     }, true);\r
16690 \r
16691     \r
16692     \r
16693     \r
16694     \r
16695     \r
16696     \r
16697     \r
16698     \r
16699     \r
16700     \r
16701 /*\r
16702  * ----------------------------------------------------------------\r
16703  * RoundPropsPlugin\r
16704  * ----------------------------------------------------------------\r
16705  */\r
16706     (function() {\r
16707 \r
16708         var RoundPropsPlugin = window._gsDefine.plugin({\r
16709                 propName: "roundProps",\r
16710                 priority: -1,\r
16711                 API: 2,\r
16712 \r
16713                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
16714                 init: function(target, value, tween) {\r
16715                     this._tween = tween;\r
16716                     return true;\r
16717                 }\r
16718 \r
16719             }),\r
16720             p = RoundPropsPlugin.prototype;\r
16721 \r
16722         p._onInitAllProps = function() {\r
16723             var tween = this._tween,\r
16724                 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),\r
16725                 i = rp.length,\r
16726                 lookup = {},\r
16727                 rpt = tween._propLookup.roundProps,\r
16728                 prop, pt, next;\r
16729             while (--i > -1) {\r
16730                 lookup[rp[i]] = 1;\r
16731             }\r
16732             i = rp.length;\r
16733             while (--i > -1) {\r
16734                 prop = rp[i];\r
16735                 pt = tween._firstPT;\r
16736                 while (pt) {\r
16737                     next = pt._next; //record here, because it may get removed\r
16738                     if (pt.pg) {\r
16739                         pt.t._roundProps(lookup, true);\r
16740                     } else if (pt.n === prop) {\r
16741                         this._add(pt.t, prop, pt.s, pt.c);\r
16742                         //remove from linked list\r
16743                         if (next) {\r
16744                             next._prev = pt._prev;\r
16745                         }\r
16746                         if (pt._prev) {\r
16747                             pt._prev._next = next;\r
16748                         } else if (tween._firstPT === pt) {\r
16749                             tween._firstPT = next;\r
16750                         }\r
16751                         pt._next = pt._prev = null;\r
16752                         tween._propLookup[prop] = rpt;\r
16753                     }\r
16754                     pt = next;\r
16755                 }\r
16756             }\r
16757             return false;\r
16758         };\r
16759 \r
16760         p._add = function(target, p, s, c) {\r
16761             this._addTween(target, p, s, s + c, p, true);\r
16762             this._overwriteProps.push(p);\r
16763         };\r
16764 \r
16765     }());\r
16766 \r
16767 \r
16768 \r
16769 \r
16770 \r
16771 \r
16772 \r
16773 \r
16774 \r
16775 \r
16776 /*\r
16777  * ----------------------------------------------------------------\r
16778  * AttrPlugin\r
16779  * ----------------------------------------------------------------\r
16780  */\r
16781     window._gsDefine.plugin({\r
16782         propName: "attr",\r
16783         API: 2,\r
16784         version: "0.3.2",\r
16785 \r
16786         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
16787         init: function(target, value, tween) {\r
16788             var p, start, end;\r
16789             if (typeof(target.setAttribute) !== "function") {\r
16790                 return false;\r
16791             }\r
16792             this._target = target;\r
16793             this._proxy = {};\r
16794             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.\r
16795             this._end = {};\r
16796             for (p in value) {\r
16797                 this._start[p] = this._proxy[p] = start = target.getAttribute(p);\r
16798                 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);\r
16799                 this._end[p] = end ? end.s + end.c : value[p];\r
16800                 this._overwriteProps.push(p);\r
16801             }\r
16802             return true;\r
16803         },\r
16804 \r
16805         //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.)\r
16806         set: function(ratio) {\r
16807             this._super.setRatio.call(this, ratio);\r
16808             var props = this._overwriteProps,\r
16809                 i = props.length,\r
16810                 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,\r
16811                 p;\r
16812             while (--i > -1) {\r
16813                 p = props[i];\r
16814                 this._target.setAttribute(p, lookup[p] + "");\r
16815             }\r
16816         }\r
16817 \r
16818     });\r
16819 \r
16820 \r
16821 \r
16822 \r
16823 \r
16824 \r
16825 \r
16826 \r
16827 \r
16828 \r
16829 /*\r
16830  * ----------------------------------------------------------------\r
16831  * DirectionalRotationPlugin\r
16832  * ----------------------------------------------------------------\r
16833  */\r
16834     window._gsDefine.plugin({\r
16835         propName: "directionalRotation",\r
16836         API: 2,\r
16837         version: "0.2.0",\r
16838 \r
16839         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
16840         init: function(target, value, tween) {\r
16841             if (typeof(value) !== "object") {\r
16842                 value = {rotation:value};\r
16843             }\r
16844             this.finals = {};\r
16845             var cap = (value.useRadians === true) ? Math.PI * 2 : 360,\r
16846                 min = 0.000001,\r
16847                 p, v, start, end, dif, split;\r
16848             for (p in value) {\r
16849                 if (p !== "useRadians") {\r
16850                     split = (value[p] + "").split("_");\r
16851                     v = split[0];\r
16852                     start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );\r
16853                     end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;\r
16854                     dif = end - start;\r
16855                     if (split.length) {\r
16856                         v = split.join("_");\r
16857                         if (v.indexOf("short") !== -1) {\r
16858                             dif = dif % cap;\r
16859                             if (dif !== dif % (cap / 2)) {\r
16860                                 dif = (dif < 0) ? dif + cap : dif - cap;\r
16861                             }\r
16862                         }\r
16863                         if (v.indexOf("_cw") !== -1 && dif < 0) {\r
16864                             dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
16865                         } else if (v.indexOf("ccw") !== -1 && dif > 0) {\r
16866                             dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
16867                         }\r
16868                     }\r
16869                     if (dif > min || dif < -min) {\r
16870                         this._addTween(target, p, start, start + dif, p);\r
16871                         this._overwriteProps.push(p);\r
16872                     }\r
16873                 }\r
16874             }\r
16875             return true;\r
16876         },\r
16877 \r
16878         //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.)\r
16879         set: function(ratio) {\r
16880             var pt;\r
16881             if (ratio !== 1) {\r
16882                 this._super.setRatio.call(this, ratio);\r
16883             } else {\r
16884                 pt = this._firstPT;\r
16885                 while (pt) {\r
16886                     if (pt.f) {\r
16887                         pt.t[pt.p](this.finals[pt.p]);\r
16888                     } else {\r
16889                         pt.t[pt.p] = this.finals[pt.p];\r
16890                     }\r
16891                     pt = pt._next;\r
16892                 }\r
16893             }\r
16894         }\r
16895 \r
16896     })._autoCSS = true;\r
16897 \r
16898 \r
16899 \r
16900 \r
16901 \r
16902 \r
16903 \r
16904     \r
16905     \r
16906     \r
16907     \r
16908 /*\r
16909  * ----------------------------------------------------------------\r
16910  * EasePack\r
16911  * ----------------------------------------------------------------\r
16912  */\r
16913     window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {\r
16914         \r
16915         var w = (window.GreenSockGlobals || window),\r
16916             gs = w.com.greensock,\r
16917             _2PI = Math.PI * 2,\r
16918             _HALF_PI = Math.PI / 2,\r
16919             _class = gs._class,\r
16920             _create = function(n, f) {\r
16921                 var C = _class("easing." + n, function(){}, true),\r
16922                     p = C.prototype = new Ease();\r
16923                 p.constructor = C;\r
16924                 p.getRatio = f;\r
16925                 return C;\r
16926             },\r
16927             _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.\r
16928             _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {\r
16929                 var C = _class("easing."+name, {\r
16930                     easeOut:new EaseOut(),\r
16931                     easeIn:new EaseIn(),\r
16932                     easeInOut:new EaseInOut()\r
16933                 }, true);\r
16934                 _easeReg(C, name);\r
16935                 return C;\r
16936             },\r
16937             EasePoint = function(time, value, next) {\r
16938                 this.t = time;\r
16939                 this.v = value;\r
16940                 if (next) {\r
16941                     this.next = next;\r
16942                     next.prev = this;\r
16943                     this.c = next.v - value;\r
16944                     this.gap = next.t - time;\r
16945                 }\r
16946             },\r
16947 \r
16948             //Back\r
16949             _createBack = function(n, f) {\r
16950                 var C = _class("easing." + n, function(overshoot) {\r
16951                         this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;\r
16952                         this._p2 = this._p1 * 1.525;\r
16953                     }, true),\r
16954                     p = C.prototype = new Ease();\r
16955                 p.constructor = C;\r
16956                 p.getRatio = f;\r
16957                 p.config = function(overshoot) {\r
16958                     return new C(overshoot);\r
16959                 };\r
16960                 return C;\r
16961             },\r
16962 \r
16963             Back = _wrap("Back",\r
16964                 _createBack("BackOut", function(p) {\r
16965                     return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);\r
16966                 }),\r
16967                 _createBack("BackIn", function(p) {\r
16968                     return p * p * ((this._p1 + 1) * p - this._p1);\r
16969                 }),\r
16970                 _createBack("BackInOut", function(p) {\r
16971                     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);\r
16972                 })\r
16973             ),\r
16974 \r
16975 \r
16976             //SlowMo\r
16977             SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {\r
16978                 power = (power || power === 0) ? power : 0.7;\r
16979                 if (linearRatio == null) {\r
16980                     linearRatio = 0.7;\r
16981                 } else if (linearRatio > 1) {\r
16982                     linearRatio = 1;\r
16983                 }\r
16984                 this._p = (linearRatio !== 1) ? power : 0;\r
16985                 this._p1 = (1 - linearRatio) / 2;\r
16986                 this._p2 = linearRatio;\r
16987                 this._p3 = this._p1 + this._p2;\r
16988                 this._calcEnd = (yoyoMode === true);\r
16989             }, true),\r
16990             p = SlowMo.prototype = new Ease(),\r
16991             SteppedEase, RoughEase, _createElastic;\r
16992 \r
16993         p.constructor = SlowMo;\r
16994         p.getRatio = function(p) {\r
16995             var r = p + (0.5 - p) * this._p;\r
16996             if (p < this._p1) {\r
16997                 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);\r
16998             } else if (p > this._p3) {\r
16999                 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);\r
17000             }\r
17001             return this._calcEnd ? 1 : r;\r
17002         };\r
17003         SlowMo.ease = new SlowMo(0.7, 0.7);\r
17004 \r
17005         p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {\r
17006             return new SlowMo(linearRatio, power, yoyoMode);\r
17007         };\r
17008 \r
17009 \r
17010         //SteppedEase\r
17011         SteppedEase = _class("easing.SteppedEase", function(steps) {\r
17012                 steps = steps || 1;\r
17013                 this._p1 = 1 / steps;\r
17014                 this._p2 = steps + 1;\r
17015             }, true);\r
17016         p = SteppedEase.prototype = new Ease();\r
17017         p.constructor = SteppedEase;\r
17018         p.getRatio = function(p) {\r
17019             if (p < 0) {\r
17020                 p = 0;\r
17021             } else if (p >= 1) {\r
17022                 p = 0.999999999;\r
17023             }\r
17024             return ((this._p2 * p) >> 0) * this._p1;\r
17025         };\r
17026         p.config = SteppedEase.config = function(steps) {\r
17027             return new SteppedEase(steps);\r
17028         };\r
17029 \r
17030 \r
17031         //RoughEase\r
17032         RoughEase = _class("easing.RoughEase", function(vars) {\r
17033             vars = vars || {};\r
17034             var taper = vars.taper || "none",\r
17035                 a = [],\r
17036                 cnt = 0,\r
17037                 points = (vars.points || 20) | 0,\r
17038                 i = points,\r
17039                 randomize = (vars.randomize !== false),\r
17040                 clamp = (vars.clamp === true),\r
17041                 template = (vars.template instanceof Ease) ? vars.template : null,\r
17042                 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,\r
17043                 x, y, bump, invX, obj, pnt;\r
17044             while (--i > -1) {\r
17045                 x = randomize ? Math.random() : (1 / points) * i;\r
17046                 y = template ? template.getRatio(x) : x;\r
17047                 if (taper === "none") {\r
17048                     bump = strength;\r
17049                 } else if (taper === "out") {\r
17050                     invX = 1 - x;\r
17051                     bump = invX * invX * strength;\r
17052                 } else if (taper === "in") {\r
17053                     bump = x * x * strength;\r
17054                 } else if (x < 0.5) {  //"both" (start)\r
17055                     invX = x * 2;\r
17056                     bump = invX * invX * 0.5 * strength;\r
17057                 } else {                //"both" (end)\r
17058                     invX = (1 - x) * 2;\r
17059                     bump = invX * invX * 0.5 * strength;\r
17060                 }\r
17061                 if (randomize) {\r
17062                     y += (Math.random() * bump) - (bump * 0.5);\r
17063                 } else if (i % 2) {\r
17064                     y += bump * 0.5;\r
17065                 } else {\r
17066                     y -= bump * 0.5;\r
17067                 }\r
17068                 if (clamp) {\r
17069                     if (y > 1) {\r
17070                         y = 1;\r
17071                     } else if (y < 0) {\r
17072                         y = 0;\r
17073                     }\r
17074                 }\r
17075                 a[cnt++] = {x:x, y:y};\r
17076             }\r
17077             a.sort(function(a, b) {\r
17078                 return a.x - b.x;\r
17079             });\r
17080 \r
17081             pnt = new EasePoint(1, 1, null);\r
17082             i = points;\r
17083             while (--i > -1) {\r
17084                 obj = a[i];\r
17085                 pnt = new EasePoint(obj.x, obj.y, pnt);\r
17086             }\r
17087 \r
17088             this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);\r
17089         }, true);\r
17090         p = RoughEase.prototype = new Ease();\r
17091         p.constructor = RoughEase;\r
17092         p.getRatio = function(p) {\r
17093             var pnt = this._prev;\r
17094             if (p > pnt.t) {\r
17095                 while (pnt.next && p >= pnt.t) {\r
17096                     pnt = pnt.next;\r
17097                 }\r
17098                 pnt = pnt.prev;\r
17099             } else {\r
17100                 while (pnt.prev && p <= pnt.t) {\r
17101                     pnt = pnt.prev;\r
17102                 }\r
17103             }\r
17104             this._prev = pnt;\r
17105             return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);\r
17106         };\r
17107         p.config = function(vars) {\r
17108             return new RoughEase(vars);\r
17109         };\r
17110         RoughEase.ease = new RoughEase();\r
17111 \r
17112 \r
17113         //Bounce\r
17114         _wrap("Bounce",\r
17115             _create("BounceOut", function(p) {\r
17116                 if (p < 1 / 2.75) {\r
17117                     return 7.5625 * p * p;\r
17118                 } else if (p < 2 / 2.75) {\r
17119                     return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;\r
17120                 } else if (p < 2.5 / 2.75) {\r
17121                     return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;\r
17122                 }\r
17123                 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;\r
17124             }),\r
17125             _create("BounceIn", function(p) {\r
17126                 if ((p = 1 - p) < 1 / 2.75) {\r
17127                     return 1 - (7.5625 * p * p);\r
17128                 } else if (p < 2 / 2.75) {\r
17129                     return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);\r
17130                 } else if (p < 2.5 / 2.75) {\r
17131                     return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);\r
17132                 }\r
17133                 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);\r
17134             }),\r
17135             _create("BounceInOut", function(p) {\r
17136                 var invert = (p < 0.5);\r
17137                 if (invert) {\r
17138                     p = 1 - (p * 2);\r
17139                 } else {\r
17140                     p = (p * 2) - 1;\r
17141                 }\r
17142                 if (p < 1 / 2.75) {\r
17143                     p = 7.5625 * p * p;\r
17144                 } else if (p < 2 / 2.75) {\r
17145                     p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;\r
17146                 } else if (p < 2.5 / 2.75) {\r
17147                     p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;\r
17148                 } else {\r
17149                     p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;\r
17150                 }\r
17151                 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;\r
17152             })\r
17153         );\r
17154 \r
17155 \r
17156         //CIRC\r
17157         _wrap("Circ",\r
17158             _create("CircOut", function(p) {\r
17159                 return Math.sqrt(1 - (p = p - 1) * p);\r
17160             }),\r
17161             _create("CircIn", function(p) {\r
17162                 return -(Math.sqrt(1 - (p * p)) - 1);\r
17163             }),\r
17164             _create("CircInOut", function(p) {\r
17165                 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);\r
17166             })\r
17167         );\r
17168 \r
17169 \r
17170         //Elastic\r
17171         _createElastic = function(n, f, def) {\r
17172             var C = _class("easing." + n, function(amplitude, period) {\r
17173                     this._p1 = amplitude || 1;\r
17174                     this._p2 = period || def;\r
17175                     this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);\r
17176                 }, true),\r
17177                 p = C.prototype = new Ease();\r
17178             p.constructor = C;\r
17179             p.getRatio = f;\r
17180             p.config = function(amplitude, period) {\r
17181                 return new C(amplitude, period);\r
17182             };\r
17183             return C;\r
17184         };\r
17185         _wrap("Elastic",\r
17186             _createElastic("ElasticOut", function(p) {\r
17187                 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;\r
17188             }, 0.3),\r
17189             _createElastic("ElasticIn", function(p) {\r
17190                 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));\r
17191             }, 0.3),\r
17192             _createElastic("ElasticInOut", function(p) {\r
17193                 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;\r
17194             }, 0.45)\r
17195         );\r
17196 \r
17197 \r
17198         //Expo\r
17199         _wrap("Expo",\r
17200             _create("ExpoOut", function(p) {\r
17201                 return 1 - Math.pow(2, -10 * p);\r
17202             }),\r
17203             _create("ExpoIn", function(p) {\r
17204                 return Math.pow(2, 10 * (p - 1)) - 0.001;\r
17205             }),\r
17206             _create("ExpoInOut", function(p) {\r
17207                 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));\r
17208             })\r
17209         );\r
17210 \r
17211 \r
17212         //Sine\r
17213         _wrap("Sine",\r
17214             _create("SineOut", function(p) {\r
17215                 return Math.sin(p * _HALF_PI);\r
17216             }),\r
17217             _create("SineIn", function(p) {\r
17218                 return -Math.cos(p * _HALF_PI) + 1;\r
17219             }),\r
17220             _create("SineInOut", function(p) {\r
17221                 return -0.5 * (Math.cos(Math.PI * p) - 1);\r
17222             })\r
17223         );\r
17224 \r
17225         _class("easing.EaseLookup", {\r
17226                 find:function(s) {\r
17227                     return Ease.map[s];\r
17228                 }\r
17229             }, true);\r
17230 \r
17231         //register the non-standard eases\r
17232         _easeReg(w.SlowMo, "SlowMo", "ease,");\r
17233         _easeReg(RoughEase, "RoughEase", "ease,");\r
17234         _easeReg(SteppedEase, "SteppedEase", "ease,");\r
17235 \r
17236         return Back;\r
17237         \r
17238     }, true);\r
17239 \r
17240 \r
17241 }); \r
17242 \r
17243 \r
17244 \r
17245 \r
17246 \r
17247 \r
17248 \r
17249 \r
17250 \r
17251 \r
17252 \r
17253 /*\r
17254  * ----------------------------------------------------------------\r
17255  * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.\r
17256  * ----------------------------------------------------------------\r
17257  */\r
17258 (function(window) {\r
17259 \r
17260         "use strict";\r
17261         var _globals = window.GreenSockGlobals || window;\r
17262         if (_globals.TweenLite) {\r
17263             return; //in case the core set of classes is already loaded, don't instantiate twice.\r
17264         }\r
17265         var _namespace = function(ns) {\r
17266                 var a = ns.split("."),\r
17267                     p = _globals, i;\r
17268                 for (i = 0; i < a.length; i++) {\r
17269                     p[a[i]] = p = p[a[i]] || {};\r
17270                 }\r
17271                 return p;\r
17272             },\r
17273             gs = _namespace("com.greensock"),\r
17274             _tinyNum = 0.0000000001,\r
17275             _slice = [].slice,\r
17276             _emptyFunc = function() {},\r
17277             _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)\r
17278                 var toString = Object.prototype.toString,\r
17279                     array = toString.call([]);\r
17280                 return function(obj) {\r
17281                     return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));\r
17282                 };\r
17283             }()),\r
17284             a, i, p, _ticker, _tickerActive,\r
17285             _defLookup = {},\r
17286 \r
17287             /**\r
17288              * @constructor\r
17289              * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.\r
17290              * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is\r
17291              * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin\r
17292              * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.\r
17293              *\r
17294              * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,\r
17295              * 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,\r
17296              * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so\r
17297              * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything\r
17298              * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock\r
17299              * 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\r
17300              * sandbox the banner one like:\r
17301              *\r
17302              * <script>\r
17303              *     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.\r
17304              * </script>\r
17305              * <script src="js/greensock/v1.7/TweenMax.js"></script>\r
17306              * <script>\r
17307              *     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(...)\r
17308              * </script>\r
17309              * <script src="js/greensock/v1.6/TweenMax.js"></script>\r
17310              * <script>\r
17311              *     gs.TweenLite.to(...); //would use v1.7\r
17312              *     TweenLite.to(...); //would use v1.6\r
17313              * </script>\r
17314              *\r
17315              * @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".\r
17316              * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]\r
17317              * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.\r
17318              * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)\r
17319              */\r
17320             Definition = function(ns, dependencies, func, global) {\r
17321                 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses\r
17322                 _defLookup[ns] = this;\r
17323                 this.gsClass = null;\r
17324                 this.func = func;\r
17325                 var _classes = [];\r
17326                 this.check = function(init) {\r
17327                     var i = dependencies.length,\r
17328                         missing = i,\r
17329                         cur, a, n, cl;\r
17330                     while (--i > -1) {\r
17331                         if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {\r
17332                             _classes[i] = cur.gsClass;\r
17333                             missing--;\r
17334                         } else if (init) {\r
17335                             cur.sc.push(this);\r
17336                         }\r
17337                     }\r
17338                     if (missing === 0 && func) {\r
17339                         a = ("com.greensock." + ns).split(".");\r
17340                         n = a.pop();\r
17341                         cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);\r
17342 \r
17343                         //exports to multiple environments\r
17344                         if (global) {\r
17345                             _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.)\r
17346                             if (typeof(define) === "function" && define.amd){ //AMD\r
17347                                 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });\r
17348                             } else if (typeof(module) !== "undefined" && module.exports){ //node\r
17349                                 module.exports = cl;\r
17350                             }\r
17351                         }\r
17352                         for (i = 0; i < this.sc.length; i++) {\r
17353                             this.sc[i].check();\r
17354                         }\r
17355                     }\r
17356                 };\r
17357                 this.check(true);\r
17358             },\r
17359 \r
17360             //used to create Definition instances (which basically registers a class that has dependencies).\r
17361             _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {\r
17362                 return new Definition(ns, dependencies, func, global);\r
17363             },\r
17364 \r
17365             //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).\r
17366             _class = gs._class = function(ns, func, global) {\r
17367                 func = func || function() {};\r
17368                 _gsDefine(ns, [], function(){ return func; }, global);\r
17369                 return func;\r
17370             };\r
17371 \r
17372         _gsDefine.globals = _globals;\r
17373 \r
17374 \r
17375 \r
17376 /*\r
17377  * ----------------------------------------------------------------\r
17378  * Ease\r
17379  * ----------------------------------------------------------------\r
17380  */\r
17381         var _baseParams = [0, 0, 1, 1],\r
17382             _blankArray = [],\r
17383             Ease = _class("easing.Ease", function(func, extraParams, type, power) {\r
17384                 this._func = func;\r
17385                 this._type = type || 0;\r
17386                 this._power = power || 0;\r
17387                 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;\r
17388             }, true),\r
17389             _easeMap = Ease.map = {},\r
17390             _easeReg = Ease.register = function(ease, names, types, create) {\r
17391                 var na = names.split(","),\r
17392                     i = na.length,\r
17393                     ta = (types || "easeIn,easeOut,easeInOut").split(","),\r
17394                     e, name, j, type;\r
17395                 while (--i > -1) {\r
17396                     name = na[i];\r
17397                     e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};\r
17398                     j = ta.length;\r
17399                     while (--j > -1) {\r
17400                         type = ta[j];\r
17401                         _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();\r
17402                     }\r
17403                 }\r
17404             };\r
17405 \r
17406         p = Ease.prototype;\r
17407         p._calcEnd = false;\r
17408         p.getRatio = function(p) {\r
17409             if (this._func) {\r
17410                 this._params[0] = p;\r
17411                 return this._func.apply(null, this._params);\r
17412             }\r
17413             var t = this._type,\r
17414                 pw = this._power,\r
17415                 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;\r
17416             if (pw === 1) {\r
17417                 r *= r;\r
17418             } else if (pw === 2) {\r
17419                 r *= r * r;\r
17420             } else if (pw === 3) {\r
17421                 r *= r * r * r;\r
17422             } else if (pw === 4) {\r
17423                 r *= r * r * r * r;\r
17424             }\r
17425             return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);\r
17426         };\r
17427 \r
17428         //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)\r
17429         a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];\r
17430         i = a.length;\r
17431         while (--i > -1) {\r
17432             p = a[i]+",Power"+i;\r
17433             _easeReg(new Ease(null,null,1,i), p, "easeOut", true);\r
17434             _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));\r
17435             _easeReg(new Ease(null,null,3,i), p, "easeInOut");\r
17436         }\r
17437         _easeMap.linear = gs.easing.Linear.easeIn;\r
17438         _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks\r
17439 \r
17440 \r
17441 /*\r
17442  * ----------------------------------------------------------------\r
17443  * EventDispatcher\r
17444  * ----------------------------------------------------------------\r
17445  */\r
17446         var EventDispatcher = _class("events.EventDispatcher", function(target) {\r
17447             this._listeners = {};\r
17448             this._eventTarget = target || this;\r
17449         });\r
17450         p = EventDispatcher.prototype;\r
17451 \r
17452         p.addEventListener = function(type, callback, scope, useParam, priority) {\r
17453             priority = priority || 0;\r
17454             var list = this._listeners[type],\r
17455                 index = 0,\r
17456                 listener, i;\r
17457             if (list == null) {\r
17458                 this._listeners[type] = list = [];\r
17459             }\r
17460             i = list.length;\r
17461             while (--i > -1) {\r
17462                 listener = list[i];\r
17463                 if (listener.c === callback && listener.s === scope) {\r
17464                     list.splice(i, 1);\r
17465                 } else if (index === 0 && listener.pr < priority) {\r
17466                     index = i + 1;\r
17467                 }\r
17468             }\r
17469             list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});\r
17470             if (this === _ticker && !_tickerActive) {\r
17471                 _ticker.wake();\r
17472             }\r
17473         };\r
17474 \r
17475         p.removeEventListener = function(type, callback) {\r
17476             var list = this._listeners[type], i;\r
17477             if (list) {\r
17478                 i = list.length;\r
17479                 while (--i > -1) {\r
17480                     if (list[i].c === callback) {\r
17481                         list.splice(i, 1);\r
17482                         return;\r
17483                     }\r
17484                 }\r
17485             }\r
17486         };\r
17487 \r
17488         p.dispatchEvent = function(type) {\r
17489             var list = this._listeners[type],\r
17490                 i, t, listener;\r
17491             if (list) {\r
17492                 i = list.length;\r
17493                 t = this._eventTarget;\r
17494                 while (--i > -1) {\r
17495                     listener = list[i];\r
17496                     if (listener.up) {\r
17497                         listener.c.call(listener.s || t, {type:type, target:t});\r
17498                     } else {\r
17499                         listener.c.call(listener.s || t);\r
17500                     }\r
17501                 }\r
17502             }\r
17503         };\r
17504 \r
17505 \r
17506 /*\r
17507  * ----------------------------------------------------------------\r
17508  * Ticker\r
17509  * ----------------------------------------------------------------\r
17510  */\r
17511         var _reqAnimFrame = window.requestAnimationFrame,\r
17512             _cancelAnimFrame = window.cancelAnimationFrame,\r
17513             _getTime = Date.now || function() {return new Date().getTime();},\r
17514             _lastUpdate = _getTime();\r
17515 \r
17516         //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.\r
17517         a = ["ms","moz","webkit","o"];\r
17518         i = a.length;\r
17519         while (--i > -1 && !_reqAnimFrame) {\r
17520             _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];\r
17521             _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];\r
17522         }\r
17523 \r
17524         _class("Ticker", function(fps, useRAF) {\r
17525             var _self = this,\r
17526                 _startTime = _getTime(),\r
17527                 _useRAF = (useRAF !== false && _reqAnimFrame),\r
17528                 _lagThreshold = 500,\r
17529                 _adjustedLag = 33,\r
17530                 _fps, _req, _id, _gap, _nextTime,\r
17531                 _tick = function(manual) {\r
17532                     var elapsed = _getTime() - _lastUpdate,\r
17533                         overlap, dispatch;\r
17534                     if (elapsed > _lagThreshold) {\r
17535                         _startTime += elapsed - _adjustedLag;\r
17536                     }\r
17537                     _lastUpdate += elapsed;\r
17538                     _self.time = (_lastUpdate - _startTime) / 1000;\r
17539                     overlap = _self.time - _nextTime;\r
17540                     if (!_fps || overlap > 0 || manual === true) {\r
17541                         _self.frame++;\r
17542                         _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);\r
17543                         dispatch = true;\r
17544                     }\r
17545                     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.\r
17546                         _id = _req(_tick);\r
17547                     }\r
17548                     if (dispatch) {\r
17549                         _self.dispatchEvent("tick");\r
17550                     }\r
17551                 };\r
17552 \r
17553             EventDispatcher.call(_self);\r
17554             _self.time = _self.frame = 0;\r
17555             _self.tick = function() {\r
17556                 _tick(true);\r
17557             };\r
17558 \r
17559             _self.lagSmoothing = function(threshold, adjustedLag) {\r
17560                 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited\r
17561                 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);\r
17562             };\r
17563 \r
17564             _self.sleep = function() {\r
17565                 if (_id == null) {\r
17566                     return;\r
17567                 }\r
17568                 if (!_useRAF || !_cancelAnimFrame) {\r
17569                     clearTimeout(_id);\r
17570                 } else {\r
17571                     _cancelAnimFrame(_id);\r
17572                 }\r
17573                 _req = _emptyFunc;\r
17574                 _id = null;\r
17575                 if (_self === _ticker) {\r
17576                     _tickerActive = false;\r
17577                 }\r
17578             };\r
17579 \r
17580             _self.wake = function() {\r
17581                 if (_id !== null) {\r
17582                     _self.sleep();\r
17583                 } 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().\r
17584                     _lastUpdate = _getTime() - _lagThreshold + 5;\r
17585                 }\r
17586                 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;\r
17587                 if (_self === _ticker) {\r
17588                     _tickerActive = true;\r
17589                 }\r
17590                 _tick(2);\r
17591             };\r
17592 \r
17593             _self.fps = function(value) {\r
17594                 if (!arguments.length) {\r
17595                     return _fps;\r
17596                 }\r
17597                 _fps = value;\r
17598                 _gap = 1 / (_fps || 60);\r
17599                 _nextTime = this.time + _gap;\r
17600                 _self.wake();\r
17601             };\r
17602 \r
17603             _self.useRAF = function(value) {\r
17604                 if (!arguments.length) {\r
17605                     return _useRAF;\r
17606                 }\r
17607                 _self.sleep();\r
17608                 _useRAF = value;\r
17609                 _self.fps(_fps);\r
17610             };\r
17611             _self.fps(fps);\r
17612 \r
17613             //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.\r
17614             setTimeout(function() {\r
17615                 if (_useRAF && (!_id || _self.frame < 5)) {\r
17616                     _self.useRAF(false);\r
17617                 }\r
17618             }, 1500);\r
17619         });\r
17620 \r
17621         p = gs.Ticker.prototype = new gs.events.EventDispatcher();\r
17622         p.constructor = gs.Ticker;\r
17623 \r
17624 \r
17625 /*\r
17626  * ----------------------------------------------------------------\r
17627  * Animation\r
17628  * ----------------------------------------------------------------\r
17629  */\r
17630         var Animation = _class("core.Animation", function(duration, vars) {\r
17631                 this.vars = vars = vars || {};\r
17632                 this._duration = this._totalDuration = duration || 0;\r
17633                 this._delay = Number(vars.delay) || 0;\r
17634                 this._timeScale = 1;\r
17635                 this._active = (vars.immediateRender === true);\r
17636                 this.data = vars.data;\r
17637                 this._reversed = (vars.reversed === true);\r
17638 \r
17639                 if (!_rootTimeline) {\r
17640                     return;\r
17641                 }\r
17642                 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.\r
17643                     _ticker.wake();\r
17644                 }\r
17645 \r
17646                 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;\r
17647                 tl.add(this, tl._time);\r
17648 \r
17649                 if (this.vars.paused) {\r
17650                     this.paused(true);\r
17651                 }\r
17652             });\r
17653 \r
17654         _ticker = Animation.ticker = new gs.Ticker();\r
17655         p = Animation.prototype;\r
17656         p._dirty = p._gc = p._initted = p._paused = false;\r
17657         p._totalTime = p._time = 0;\r
17658         p._rawPrevTime = -1;\r
17659         p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;\r
17660         p._paused = false;\r
17661 \r
17662 \r
17663         //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.\r
17664         var _checkTimeout = function() {\r
17665                 if (_tickerActive && _getTime() - _lastUpdate > 2000) {\r
17666                     _ticker.wake();\r
17667                 }\r
17668                 setTimeout(_checkTimeout, 2000);\r
17669             };\r
17670         _checkTimeout();\r
17671 \r
17672 \r
17673         p.play = function(from, suppressEvents) {\r
17674             if (from != null) {\r
17675                 this.seek(from, suppressEvents);\r
17676             }\r
17677             return this.reversed(false).paused(false);\r
17678         };\r
17679 \r
17680         p.pause = function(atTime, suppressEvents) {\r
17681             if (atTime != null) {\r
17682                 this.seek(atTime, suppressEvents);\r
17683             }\r
17684             return this.paused(true);\r
17685         };\r
17686 \r
17687         p.resume = function(from, suppressEvents) {\r
17688             if (from != null) {\r
17689                 this.seek(from, suppressEvents);\r
17690             }\r
17691             return this.paused(false);\r
17692         };\r
17693 \r
17694         p.seek = function(time, suppressEvents) {\r
17695             return this.totalTime(Number(time), suppressEvents !== false);\r
17696         };\r
17697 \r
17698         p.restart = function(includeDelay, suppressEvents) {\r
17699             return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);\r
17700         };\r
17701 \r
17702         p.reverse = function(from, suppressEvents) {\r
17703             if (from != null) {\r
17704                 this.seek((from || this.totalDuration()), suppressEvents);\r
17705             }\r
17706             return this.reversed(true).paused(false);\r
17707         };\r
17708 \r
17709         p.render = function(time, suppressEvents, force) {\r
17710             //stub - we override this method in subclasses.\r
17711         };\r
17712 \r
17713         p.invalidate = function() {\r
17714             return this;\r
17715         };\r
17716 \r
17717         p.isActive = function() {\r
17718             var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.\r
17719                 startTime = this._startTime,\r
17720                 rawTime;\r
17721             return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));\r
17722         };\r
17723 \r
17724         p._enabled = function (enabled, ignoreTimeline) {\r
17725             if (!_tickerActive) {\r
17726                 _ticker.wake();\r
17727             }\r
17728             this._gc = !enabled;\r
17729             this._active = this.isActive();\r
17730             if (ignoreTimeline !== true) {\r
17731                 if (enabled && !this.timeline) {\r
17732                     this._timeline.add(this, this._startTime - this._delay);\r
17733                 } else if (!enabled && this.timeline) {\r
17734                     this._timeline._remove(this, true);\r
17735                 }\r
17736             }\r
17737             return false;\r
17738         };\r
17739 \r
17740 \r
17741         p._kill = function(vars, target) {\r
17742             return this._enabled(false, false);\r
17743         };\r
17744 \r
17745         p.kill = function(vars, target) {\r
17746             this._kill(vars, target);\r
17747             return this;\r
17748         };\r
17749 \r
17750         p._uncache = function(includeSelf) {\r
17751             var tween = includeSelf ? this : this.timeline;\r
17752             while (tween) {\r
17753                 tween._dirty = true;\r
17754                 tween = tween.timeline;\r
17755             }\r
17756             return this;\r
17757         };\r
17758 \r
17759         p._swapSelfInParams = function(params) {\r
17760             var i = params.length,\r
17761                 copy = params.concat();\r
17762             while (--i > -1) {\r
17763                 if (params[i] === "{self}") {\r
17764                     copy[i] = this;\r
17765                 }\r
17766             }\r
17767             return copy;\r
17768         };\r
17769 \r
17770 //----Animation getters/setters --------------------------------------------------------\r
17771 \r
17772         p.eventCallback = function(type, callback, params, scope) {\r
17773             if ((type || "").substr(0,2) === "on") {\r
17774                 var v = this.vars;\r
17775                 if (arguments.length === 1) {\r
17776                     return v[type];\r
17777                 }\r
17778                 if (callback == null) {\r
17779                     delete v[type];\r
17780                 } else {\r
17781                     v[type] = callback;\r
17782                     v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;\r
17783                     v[type + "Scope"] = scope;\r
17784                 }\r
17785                 if (type === "onUpdate") {\r
17786                     this._onUpdate = callback;\r
17787                 }\r
17788             }\r
17789             return this;\r
17790         };\r
17791 \r
17792         p.delay = function(value) {\r
17793             if (!arguments.length) {\r
17794                 return this._delay;\r
17795             }\r
17796             if (this._timeline.smoothChildTiming) {\r
17797                 this.startTime( this._startTime + value - this._delay );\r
17798             }\r
17799             this._delay = value;\r
17800             return this;\r
17801         };\r
17802 \r
17803         p.duration = function(value) {\r
17804             if (!arguments.length) {\r
17805                 this._dirty = false;\r
17806                 return this._duration;\r
17807             }\r
17808             this._duration = this._totalDuration = value;\r
17809             this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.\r
17810             if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {\r
17811                 this.totalTime(this._totalTime * (value / this._duration), true);\r
17812             }\r
17813             return this;\r
17814         };\r
17815 \r
17816         p.totalDuration = function(value) {\r
17817             this._dirty = false;\r
17818             return (!arguments.length) ? this._totalDuration : this.duration(value);\r
17819         };\r
17820 \r
17821         p.time = function(value, suppressEvents) {\r
17822             if (!arguments.length) {\r
17823                 return this._time;\r
17824             }\r
17825             if (this._dirty) {\r
17826                 this.totalDuration();\r
17827             }\r
17828             return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);\r
17829         };\r
17830 \r
17831         p.totalTime = function(time, suppressEvents, uncapped) {\r
17832             if (!_tickerActive) {\r
17833                 _ticker.wake();\r
17834             }\r
17835             if (!arguments.length) {\r
17836                 return this._totalTime;\r
17837             }\r
17838             if (this._timeline) {\r
17839                 if (time < 0 && !uncapped) {\r
17840                     time += this.totalDuration();\r
17841                 }\r
17842                 if (this._timeline.smoothChildTiming) {\r
17843                     if (this._dirty) {\r
17844                         this.totalDuration();\r
17845                     }\r
17846                     var totalDuration = this._totalDuration,\r
17847                         tl = this._timeline;\r
17848                     if (time > totalDuration && !uncapped) {\r
17849                         time = totalDuration;\r
17850                     }\r
17851                     this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);\r
17852                     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.\r
17853                         this._uncache(false);\r
17854                     }\r
17855                     //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.\r
17856                     if (tl._timeline) {\r
17857                         while (tl._timeline) {\r
17858                             if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {\r
17859                                 tl.totalTime(tl._totalTime, true);\r
17860                             }\r
17861                             tl = tl._timeline;\r
17862                         }\r
17863                     }\r
17864                 }\r
17865                 if (this._gc) {\r
17866                     this._enabled(true, false);\r
17867                 }\r
17868                 if (this._totalTime !== time || this._duration === 0) {\r
17869                     this.render(time, suppressEvents, false);\r
17870                     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.\r
17871                         _lazyRender();\r
17872                     }\r
17873                 }\r
17874             }\r
17875             return this;\r
17876         };\r
17877 \r
17878         p.progress = p.totalProgress = function(value, suppressEvents) {\r
17879             return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);\r
17880         };\r
17881 \r
17882         p.startTime = function(value) {\r
17883             if (!arguments.length) {\r
17884                 return this._startTime;\r
17885             }\r
17886             if (value !== this._startTime) {\r
17887                 this._startTime = value;\r
17888                 if (this.timeline) if (this.timeline._sortChildren) {\r
17889                     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.\r
17890                 }\r
17891             }\r
17892             return this;\r
17893         };\r
17894 \r
17895         p.timeScale = function(value) {\r
17896             if (!arguments.length) {\r
17897                 return this._timeScale;\r
17898             }\r
17899             value = value || _tinyNum; //can't allow zero because it'll throw the math off\r
17900             if (this._timeline && this._timeline.smoothChildTiming) {\r
17901                 var pauseTime = this._pauseTime,\r
17902                     t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();\r
17903                 this._startTime = t - ((t - this._startTime) * this._timeScale / value);\r
17904             }\r
17905             this._timeScale = value;\r
17906             return this._uncache(false);\r
17907         };\r
17908 \r
17909         p.reversed = function(value) {\r
17910             if (!arguments.length) {\r
17911                 return this._reversed;\r
17912             }\r
17913             if (value != this._reversed) {\r
17914                 this._reversed = value;\r
17915                 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);\r
17916             }\r
17917             return this;\r
17918         };\r
17919 \r
17920         p.paused = function(value) {\r
17921             if (!arguments.length) {\r
17922                 return this._paused;\r
17923             }\r
17924             if (value != this._paused) if (this._timeline) {\r
17925                 if (!_tickerActive && !value) {\r
17926                     _ticker.wake();\r
17927                 }\r
17928                 var tl = this._timeline,\r
17929                     raw = tl.rawTime(),\r
17930                     elapsed = raw - this._pauseTime;\r
17931                 if (!value && tl.smoothChildTiming) {\r
17932                     this._startTime += elapsed;\r
17933                     this._uncache(false);\r
17934                 }\r
17935                 this._pauseTime = value ? raw : null;\r
17936                 this._paused = value;\r
17937                 this._active = this.isActive();\r
17938                 if (!value && elapsed !== 0 && this._initted && this.duration()) {\r
17939                     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.\r
17940                 }\r
17941             }\r
17942             if (this._gc && !value) {\r
17943                 this._enabled(true, false);\r
17944             }\r
17945             return this;\r
17946         };\r
17947 \r
17948 \r
17949 /*\r
17950  * ----------------------------------------------------------------\r
17951  * SimpleTimeline\r
17952  * ----------------------------------------------------------------\r
17953  */\r
17954         var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {\r
17955             Animation.call(this, 0, vars);\r
17956             this.autoRemoveChildren = this.smoothChildTiming = true;\r
17957         });\r
17958 \r
17959         p = SimpleTimeline.prototype = new Animation();\r
17960         p.constructor = SimpleTimeline;\r
17961         p.kill()._gc = false;\r
17962         p._first = p._last = null;\r
17963         p._sortChildren = false;\r
17964 \r
17965         p.add = p.insert = function(child, position, align, stagger) {\r
17966             var prevTween, st;\r
17967             child._startTime = Number(position || 0) + child._delay;\r
17968             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).\r
17969                 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);\r
17970             }\r
17971             if (child.timeline) {\r
17972                 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.\r
17973             }\r
17974             child.timeline = child._timeline = this;\r
17975             if (child._gc) {\r
17976                 child._enabled(true, true);\r
17977             }\r
17978             prevTween = this._last;\r
17979             if (this._sortChildren) {\r
17980                 st = child._startTime;\r
17981                 while (prevTween && prevTween._startTime > st) {\r
17982                     prevTween = prevTween._prev;\r
17983                 }\r
17984             }\r
17985             if (prevTween) {\r
17986                 child._next = prevTween._next;\r
17987                 prevTween._next = child;\r
17988             } else {\r
17989                 child._next = this._first;\r
17990                 this._first = child;\r
17991             }\r
17992             if (child._next) {\r
17993                 child._next._prev = child;\r
17994             } else {\r
17995                 this._last = child;\r
17996             }\r
17997             child._prev = prevTween;\r
17998             if (this._timeline) {\r
17999                 this._uncache(true);\r
18000             }\r
18001             return this;\r
18002         };\r
18003 \r
18004         p._remove = function(tween, skipDisable) {\r
18005             if (tween.timeline === this) {\r
18006                 if (!skipDisable) {\r
18007                     tween._enabled(false, true);\r
18008                 }\r
18009                 tween.timeline = null;\r
18010 \r
18011                 if (tween._prev) {\r
18012                     tween._prev._next = tween._next;\r
18013                 } else if (this._first === tween) {\r
18014                     this._first = tween._next;\r
18015                 }\r
18016                 if (tween._next) {\r
18017                     tween._next._prev = tween._prev;\r
18018                 } else if (this._last === tween) {\r
18019                     this._last = tween._prev;\r
18020                 }\r
18021 \r
18022                 if (this._timeline) {\r
18023                     this._uncache(true);\r
18024                 }\r
18025             }\r
18026             return this;\r
18027         };\r
18028 \r
18029         p.render = function(time, suppressEvents, force) {\r
18030             var tween = this._first,\r
18031                 next;\r
18032             this._totalTime = this._time = this._rawPrevTime = time;\r
18033             while (tween) {\r
18034                 next = tween._next; //record it here because the value could change after rendering...\r
18035                 if (tween._active || (time >= tween._startTime && !tween._paused)) {\r
18036                     if (!tween._reversed) {\r
18037                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
18038                     } else {\r
18039                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
18040                     }\r
18041                 }\r
18042                 tween = next;\r
18043             }\r
18044         };\r
18045 \r
18046         p.rawTime = function() {\r
18047             if (!_tickerActive) {\r
18048                 _ticker.wake();\r
18049             }\r
18050             return this._totalTime;\r
18051         };\r
18052 \r
18053 /*\r
18054  * ----------------------------------------------------------------\r
18055  * TweenLite\r
18056  * ----------------------------------------------------------------\r
18057  */\r
18058         var TweenLite = _class("TweenLite", function(target, duration, vars) {\r
18059                 Animation.call(this, duration, vars);\r
18060                 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)\r
18061 \r
18062                 if (target == null) {\r
18063                     throw "Cannot tween a null target.";\r
18064                 }\r
18065 \r
18066                 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;\r
18067 \r
18068                 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),\r
18069                     overwrite = this.vars.overwrite,\r
18070                     i, targ, targets;\r
18071 \r
18072                 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];\r
18073 \r
18074                 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {\r
18075                     this._targets = targets = _slice.call(target, 0);\r
18076                     this._propLookup = [];\r
18077                     this._siblings = [];\r
18078                     for (i = 0; i < targets.length; i++) {\r
18079                         targ = targets[i];\r
18080                         if (!targ) {\r
18081                             targets.splice(i--, 1);\r
18082                             continue;\r
18083                         } else if (typeof(targ) === "string") {\r
18084                             targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings\r
18085                             if (typeof(targ) === "string") {\r
18086                                 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)\r
18087                             }\r
18088                             continue;\r
18089                         } 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.\r
18090                             targets.splice(i--, 1);\r
18091                             this._targets = targets = targets.concat(_slice.call(targ, 0));\r
18092                             continue;\r
18093                         }\r
18094                         this._siblings[i] = _register(targ, this, false);\r
18095                         if (overwrite === 1) if (this._siblings[i].length > 1) {\r
18096                             _applyOverwrite(targ, this, null, 1, this._siblings[i]);\r
18097                         }\r
18098                     }\r
18099 \r
18100                 } else {\r
18101                     this._propLookup = {};\r
18102                     this._siblings = _register(target, this, false);\r
18103                     if (overwrite === 1) if (this._siblings.length > 1) {\r
18104                         _applyOverwrite(target, this, null, 1, this._siblings);\r
18105                     }\r
18106                 }\r
18107                 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {\r
18108                     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)\r
18109                     this.render(-this._delay);\r
18110                 }\r
18111             }, true),\r
18112             _isSelector = function(v) {\r
18113                 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.\r
18114             },\r
18115             _autoCSS = function(vars, target) {\r
18116                 var css = {},\r
18117                     p;\r
18118                 for (p in vars) {\r
18119                     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.\r
18120                         css[p] = vars[p];\r
18121                         delete vars[p];\r
18122                     }\r
18123                 }\r
18124                 vars.css = css;\r
18125             };\r
18126 \r
18127         p = TweenLite.prototype = new Animation();\r
18128         p.constructor = TweenLite;\r
18129         p.kill()._gc = false;\r
18130 \r
18131 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------\r
18132 \r
18133         p.ratio = 0;\r
18134         p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;\r
18135         p._notifyPluginsOfEnabled = p._lazy = false;\r
18136 \r
18137         TweenLite.version = "1.12.1";\r
18138         TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);\r
18139         TweenLite.defaultOverwrite = "auto";\r
18140         TweenLite.ticker = _ticker;\r
18141         TweenLite.autoSleep = true;\r
18142         TweenLite.lagSmoothing = function(threshold, adjustedLag) {\r
18143             _ticker.lagSmoothing(threshold, adjustedLag);\r
18144         };\r
18145         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; };\r
18146 \r
18147         var _lazyTweens = [],\r
18148             _lazyLookup = {},\r
18149             _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.\r
18150             _plugins = TweenLite._plugins = {},\r
18151             _tweenLookup = _internals.tweenLookup = {},\r
18152             _tweenLookupNum = 0,\r
18153             _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},\r
18154             _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},\r
18155             _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),\r
18156             _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),\r
18157             _lazyRender = function() {\r
18158                 var i = _lazyTweens.length;\r
18159                 _lazyLookup = {};\r
18160                 while (--i > -1) {\r
18161                     a = _lazyTweens[i];\r
18162                     if (a && a._lazy !== false) {\r
18163                         a.render(a._lazy, false, true);\r
18164                         a._lazy = false;\r
18165                     }\r
18166                 }\r
18167                 _lazyTweens.length = 0;\r
18168             };\r
18169 \r
18170         _rootTimeline._startTime = _ticker.time;\r
18171         _rootFramesTimeline._startTime = _ticker.frame;\r
18172         _rootTimeline._active = _rootFramesTimeline._active = true;\r
18173         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".\r
18174 \r
18175         Animation._updateRoot = TweenLite.render = function() {\r
18176                 var i, a, p;\r
18177                 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.\r
18178                     _lazyRender();\r
18179                 }\r
18180                 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);\r
18181                 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);\r
18182                 if (_lazyTweens.length) {\r
18183                     _lazyRender();\r
18184                 }\r
18185                 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...\r
18186                     for (p in _tweenLookup) {\r
18187                         a = _tweenLookup[p].tweens;\r
18188                         i = a.length;\r
18189                         while (--i > -1) {\r
18190                             if (a[i]._gc) {\r
18191                                 a.splice(i, 1);\r
18192                             }\r
18193                         }\r
18194                         if (a.length === 0) {\r
18195                             delete _tweenLookup[p];\r
18196                         }\r
18197                     }\r
18198                     //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\r
18199                     p = _rootTimeline._first;\r
18200                     if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {\r
18201                         while (p && p._paused) {\r
18202                             p = p._next;\r
18203                         }\r
18204                         if (!p) {\r
18205                             _ticker.sleep();\r
18206                         }\r
18207                     }\r
18208                 }\r
18209             };\r
18210 \r
18211         _ticker.addEventListener("tick", Animation._updateRoot);\r
18212 \r
18213         var _register = function(target, tween, scrub) {\r
18214                 var id = target._gsTweenID, a, i;\r
18215                 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {\r
18216                     _tweenLookup[id] = {target:target, tweens:[]};\r
18217                 }\r
18218                 if (tween) {\r
18219                     a = _tweenLookup[id].tweens;\r
18220                     a[(i = a.length)] = tween;\r
18221                     if (scrub) {\r
18222                         while (--i > -1) {\r
18223                             if (a[i] === tween) {\r
18224                                 a.splice(i, 1);\r
18225                             }\r
18226                         }\r
18227                     }\r
18228                 }\r
18229                 return _tweenLookup[id].tweens;\r
18230             },\r
18231 \r
18232             _applyOverwrite = function(target, tween, props, mode, siblings) {\r
18233                 var i, changed, curTween, l;\r
18234                 if (mode === 1 || mode >= 4) {\r
18235                     l = siblings.length;\r
18236                     for (i = 0; i < l; i++) {\r
18237                         if ((curTween = siblings[i]) !== tween) {\r
18238                             if (!curTween._gc) if (curTween._enabled(false, false)) {\r
18239                                 changed = true;\r
18240                             }\r
18241                         } else if (mode === 5) {\r
18242                             break;\r
18243                         }\r
18244                     }\r
18245                     return changed;\r
18246                 }\r
18247                 //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)\r
18248                 var startTime = tween._startTime + _tinyNum,\r
18249                     overlaps = [],\r
18250                     oCount = 0,\r
18251                     zeroDur = (tween._duration === 0),\r
18252                     globalStart;\r
18253                 i = siblings.length;\r
18254                 while (--i > -1) {\r
18255                     if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {\r
18256                         //ignore\r
18257                     } else if (curTween._timeline !== tween._timeline) {\r
18258                         globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);\r
18259                         if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {\r
18260                             overlaps[oCount++] = curTween;\r
18261                         }\r
18262                     } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {\r
18263                         overlaps[oCount++] = curTween;\r
18264                     }\r
18265                 }\r
18266 \r
18267                 i = oCount;\r
18268                 while (--i > -1) {\r
18269                     curTween = overlaps[i];\r
18270                     if (mode === 2) if (curTween._kill(props, target)) {\r
18271                         changed = true;\r
18272                     }\r
18273                     if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {\r
18274                         if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.\r
18275                             changed = true;\r
18276                         }\r
18277                     }\r
18278                 }\r
18279                 return changed;\r
18280             },\r
18281 \r
18282             _checkOverlap = function(tween, reference, zeroDur) {\r
18283                 var tl = tween._timeline,\r
18284                     ts = tl._timeScale,\r
18285                     t = tween._startTime;\r
18286                 while (tl._timeline) {\r
18287                     t += tl._startTime;\r
18288                     ts *= tl._timeScale;\r
18289                     if (tl._paused) {\r
18290                         return -100;\r
18291                     }\r
18292                     tl = tl._timeline;\r
18293                 }\r
18294                 t /= ts;\r
18295                 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;\r
18296             };\r
18297 \r
18298 \r
18299 //---- TweenLite instance methods -----------------------------------------------------------------------------\r
18300 \r
18301         p._init = function() {\r
18302             var v = this.vars,\r
18303                 op = this._overwrittenProps,\r
18304                 dur = this._duration,\r
18305                 immediate = !!v.immediateRender,\r
18306                 ease = v.ease,\r
18307                 i, initPlugins, pt, p, startVars;\r
18308             if (v.startAt) {\r
18309                 if (this._startAt) {\r
18310                     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.\r
18311                     this._startAt.kill();\r
18312                 }\r
18313                 startVars = {};\r
18314                 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);\r
18315                     startVars[p] = v.startAt[p];\r
18316                 }\r
18317                 startVars.overwrite = false;\r
18318                 startVars.immediateRender = true;\r
18319                 startVars.lazy = (immediate && v.lazy !== false);\r
18320                 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).\r
18321                 this._startAt = TweenLite.to(this.target, 0, startVars);\r
18322                 if (immediate) {\r
18323                     if (this._time > 0) {\r
18324                         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()).\r
18325                     } else if (dur !== 0) {\r
18326                         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.\r
18327                     }\r
18328                 }\r
18329             } else if (v.runBackwards && dur !== 0) {\r
18330                 //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)\r
18331                 if (this._startAt) {\r
18332                     this._startAt.render(-1, true);\r
18333                     this._startAt.kill();\r
18334                     this._startAt = null;\r
18335                 } else {\r
18336                     pt = {};\r
18337                     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.\r
18338                         if (!_reservedProps[p] || p === "autoCSS") {\r
18339                             pt[p] = v[p];\r
18340                         }\r
18341                     }\r
18342                     pt.overwrite = 0;\r
18343                     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.\r
18344                     pt.lazy = (immediate && v.lazy !== false);\r
18345                     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)\r
18346                     this._startAt = TweenLite.to(this.target, 0, pt);\r
18347                     if (!immediate) {\r
18348                         this._startAt._init(); //ensures that the initial values are recorded\r
18349                         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.\r
18350                     } else if (this._time === 0) {\r
18351                         return;\r
18352                     }\r
18353                 }\r
18354             }\r
18355             if (!ease) {\r
18356                 this._ease = TweenLite.defaultEase;\r
18357             } else if (ease instanceof Ease) {\r
18358                 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;\r
18359             } else {\r
18360                 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;\r
18361             }\r
18362             this._easeType = this._ease._type;\r
18363             this._easePower = this._ease._power;\r
18364             this._firstPT = null;\r
18365 \r
18366             if (this._targets) {\r
18367                 i = this._targets.length;\r
18368                 while (--i > -1) {\r
18369                     if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {\r
18370                         initPlugins = true;\r
18371                     }\r
18372                 }\r
18373             } else {\r
18374                 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);\r
18375             }\r
18376 \r
18377             if (initPlugins) {\r
18378                 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite\r
18379             }\r
18380             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.\r
18381                 this._enabled(false, false);\r
18382             }\r
18383             if (v.runBackwards) {\r
18384                 pt = this._firstPT;\r
18385                 while (pt) {\r
18386                     pt.s += pt.c;\r
18387                     pt.c = -pt.c;\r
18388                     pt = pt._next;\r
18389                 }\r
18390             }\r
18391             this._onUpdate = v.onUpdate;\r
18392             this._initted = true;\r
18393         };\r
18394 \r
18395         p._initProps = function(target, propLookup, siblings, overwrittenProps) {\r
18396             var p, i, initPlugins, plugin, pt, v;\r
18397             if (target == null) {\r
18398                 return false;\r
18399             }\r
18400 \r
18401             if (_lazyLookup[target._gsTweenID]) {\r
18402                 _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)\r
18403             }\r
18404 \r
18405             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.\r
18406                 _autoCSS(this.vars, target);\r
18407             }\r
18408             for (p in this.vars) {\r
18409                 v = this.vars[p];\r
18410                 if (_reservedProps[p]) {\r
18411                     if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {\r
18412                         this.vars[p] = v = this._swapSelfInParams(v, this);\r
18413                     }\r
18414 \r
18415                 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {\r
18416 \r
18417                     //t - target        [object]\r
18418                     //p - property      [string]\r
18419                     //s - start         [number]\r
18420                     //c - change        [number]\r
18421                     //f - isFunction    [boolean]\r
18422                     //n - name          [string]\r
18423                     //pg - isPlugin     [boolean]\r
18424                     //pr - priority     [number]\r
18425                     this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};\r
18426                     i = plugin._overwriteProps.length;\r
18427                     while (--i > -1) {\r
18428                         propLookup[plugin._overwriteProps[i]] = this._firstPT;\r
18429                     }\r
18430                     if (plugin._priority || plugin._onInitAllProps) {\r
18431                         initPlugins = true;\r
18432                     }\r
18433                     if (plugin._onDisable || plugin._onEnable) {\r
18434                         this._notifyPluginsOfEnabled = true;\r
18435                     }\r
18436 \r
18437                 } else {\r
18438                     this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};\r
18439                     pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();\r
18440                     pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;\r
18441                 }\r
18442                 if (pt) if (pt._next) {\r
18443                     pt._next._prev = pt;\r
18444                 }\r
18445             }\r
18446 \r
18447             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)\r
18448                 return this._initProps(target, propLookup, siblings, overwrittenProps);\r
18449             }\r
18450             if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {\r
18451                 this._kill(propLookup, target);\r
18452                 return this._initProps(target, propLookup, siblings, overwrittenProps);\r
18453             }\r
18454             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.\r
18455                 _lazyLookup[target._gsTweenID] = true;\r
18456             }\r
18457             return initPlugins;\r
18458         };\r
18459 \r
18460         p.render = function(time, suppressEvents, force) {\r
18461             var prevTime = this._time,\r
18462                 duration = this._duration,\r
18463                 prevRawPrevTime = this._rawPrevTime,\r
18464                 isComplete, callback, pt, rawPrevTime;\r
18465             if (time >= duration) {\r
18466                 this._totalTime = this._time = duration;\r
18467                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;\r
18468                 if (!this._reversed ) {\r
18469                     isComplete = true;\r
18470                     callback = "onComplete";\r
18471                 }\r
18472                 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.\r
18473                     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.\r
18474                         time = 0;\r
18475                     }\r
18476                     if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {\r
18477                         force = true;\r
18478                         if (prevRawPrevTime > _tinyNum) {\r
18479                             callback = "onReverseComplete";\r
18480                         }\r
18481                     }\r
18482                     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.\r
18483                 }\r
18484 \r
18485             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
18486                 this._totalTime = this._time = 0;\r
18487                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;\r
18488                 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {\r
18489                     callback = "onReverseComplete";\r
18490                     isComplete = this._reversed;\r
18491                 }\r
18492                 if (time < 0) {\r
18493                     this._active = false;\r
18494                     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.\r
18495                         if (prevRawPrevTime >= 0) {\r
18496                             force = true;\r
18497                         }\r
18498                         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.\r
18499                     }\r
18500                 } 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.\r
18501                     force = true;\r
18502                 }\r
18503             } else {\r
18504                 this._totalTime = this._time = time;\r
18505 \r
18506                 if (this._easeType) {\r
18507                     var r = time / duration, type = this._easeType, pow = this._easePower;\r
18508                     if (type === 1 || (type === 3 && r >= 0.5)) {\r
18509                         r = 1 - r;\r
18510                     }\r
18511                     if (type === 3) {\r
18512                         r *= 2;\r
18513                     }\r
18514                     if (pow === 1) {\r
18515                         r *= r;\r
18516                     } else if (pow === 2) {\r
18517                         r *= r * r;\r
18518                     } else if (pow === 3) {\r
18519                         r *= r * r * r;\r
18520                     } else if (pow === 4) {\r
18521                         r *= r * r * r * r;\r
18522                     }\r
18523 \r
18524                     if (type === 1) {\r
18525                         this.ratio = 1 - r;\r
18526                     } else if (type === 2) {\r
18527                         this.ratio = r;\r
18528                     } else if (time / duration < 0.5) {\r
18529                         this.ratio = r / 2;\r
18530                     } else {\r
18531                         this.ratio = 1 - (r / 2);\r
18532                     }\r
18533 \r
18534                 } else {\r
18535                     this.ratio = this._ease.getRatio(time / duration);\r
18536                 }\r
18537             }\r
18538 \r
18539             if (this._time === prevTime && !force) {\r
18540                 return;\r
18541             } else if (!this._initted) {\r
18542                 this._init();\r
18543                 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.\r
18544                     return;\r
18545                 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {\r
18546                     this._time = this._totalTime = prevTime;\r
18547                     this._rawPrevTime = prevRawPrevTime;\r
18548                     _lazyTweens.push(this);\r
18549                     this._lazy = time;\r
18550                     return;\r
18551                 }\r
18552                 //_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.\r
18553                 if (this._time && !isComplete) {\r
18554                     this.ratio = this._ease.getRatio(this._time / duration);\r
18555                 } else if (isComplete && this._ease._calcEnd) {\r
18556                     this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);\r
18557                 }\r
18558             }\r
18559             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.\r
18560                 this._lazy = false;\r
18561             }\r
18562             if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {\r
18563                 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.\r
18564             }\r
18565             if (prevTime === 0) {\r
18566                 if (this._startAt) {\r
18567                     if (time >= 0) {\r
18568                         this._startAt.render(time, suppressEvents, force);\r
18569                     } else if (!callback) {\r
18570                         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.\r
18571                     }\r
18572                 }\r
18573                 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {\r
18574                     this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
18575                 }\r
18576             }\r
18577 \r
18578             pt = this._firstPT;\r
18579             while (pt) {\r
18580                 if (pt.f) {\r
18581                     pt.t[pt.p](pt.c * this.ratio + pt.s);\r
18582                 } else {\r
18583                     pt.t[pt.p] = pt.c * this.ratio + pt.s;\r
18584                 }\r
18585                 pt = pt._next;\r
18586             }\r
18587 \r
18588             if (this._onUpdate) {\r
18589                 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.\r
18590                     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.\r
18591                 }\r
18592                 if (!suppressEvents) if (this._time !== prevTime || isComplete) {\r
18593                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
18594                 }\r
18595             }\r
18596 \r
18597             if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate\r
18598                 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.\r
18599                     this._startAt.render(time, suppressEvents, force);\r
18600                 }\r
18601                 if (isComplete) {\r
18602                     if (this._timeline.autoRemoveChildren) {\r
18603                         this._enabled(false, false);\r
18604                     }\r
18605                     this._active = false;\r
18606                 }\r
18607                 if (!suppressEvents && this.vars[callback]) {\r
18608                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
18609                 }\r
18610                 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.\r
18611                     this._rawPrevTime = 0;\r
18612                 }\r
18613             }\r
18614 \r
18615         };\r
18616 \r
18617         p._kill = function(vars, target) {\r
18618             if (vars === "all") {\r
18619                 vars = null;\r
18620             }\r
18621             if (vars == null) if (target == null || target === this.target) {\r
18622                 this._lazy = false;\r
18623                 return this._enabled(false, false);\r
18624             }\r
18625             target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;\r
18626             var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;\r
18627             if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {\r
18628                 i = target.length;\r
18629                 while (--i > -1) {\r
18630                     if (this._kill(vars, target[i])) {\r
18631                         changed = true;\r
18632                     }\r
18633                 }\r
18634             } else {\r
18635                 if (this._targets) {\r
18636                     i = this._targets.length;\r
18637                     while (--i > -1) {\r
18638                         if (target === this._targets[i]) {\r
18639                             propLookup = this._propLookup[i] || {};\r
18640                             this._overwrittenProps = this._overwrittenProps || [];\r
18641                             overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";\r
18642                             break;\r
18643                         }\r
18644                     }\r
18645                 } else if (target !== this.target) {\r
18646                     return false;\r
18647                 } else {\r
18648                     propLookup = this._propLookup;\r
18649                     overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";\r
18650                 }\r
18651 \r
18652                 if (propLookup) {\r
18653                     killProps = vars || propLookup;\r
18654                     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)\r
18655                     for (p in killProps) {\r
18656                         if ((pt = propLookup[p])) {\r
18657                             if (pt.pg && pt.t._kill(killProps)) {\r
18658                                 changed = true; //some plugins need to be notified so they can perform cleanup tasks first\r
18659                             }\r
18660                             if (!pt.pg || pt.t._overwriteProps.length === 0) {\r
18661                                 if (pt._prev) {\r
18662                                     pt._prev._next = pt._next;\r
18663                                 } else if (pt === this._firstPT) {\r
18664                                     this._firstPT = pt._next;\r
18665                                 }\r
18666                                 if (pt._next) {\r
18667                                     pt._next._prev = pt._prev;\r
18668                                 }\r
18669                                 pt._next = pt._prev = null;\r
18670                             }\r
18671                             delete propLookup[p];\r
18672                         }\r
18673                         if (record) {\r
18674                             overwrittenProps[p] = 1;\r
18675                         }\r
18676                     }\r
18677                     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.\r
18678                         this._enabled(false, false);\r
18679                     }\r
18680                 }\r
18681             }\r
18682             return changed;\r
18683         };\r
18684 \r
18685         p.invalidate = function() {\r
18686             if (this._notifyPluginsOfEnabled) {\r
18687                 TweenLite._onPluginEvent("_onDisable", this);\r
18688             }\r
18689             this._firstPT = null;\r
18690             this._overwrittenProps = null;\r
18691             this._onUpdate = null;\r
18692             this._startAt = null;\r
18693             this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;\r
18694             this._propLookup = (this._targets) ? {} : [];\r
18695             return this;\r
18696         };\r
18697 \r
18698         p._enabled = function(enabled, ignoreTimeline) {\r
18699             if (!_tickerActive) {\r
18700                 _ticker.wake();\r
18701             }\r
18702             if (enabled && this._gc) {\r
18703                 var targets = this._targets,\r
18704                     i;\r
18705                 if (targets) {\r
18706                     i = targets.length;\r
18707                     while (--i > -1) {\r
18708                         this._siblings[i] = _register(targets[i], this, true);\r
18709                     }\r
18710                 } else {\r
18711                     this._siblings = _register(this.target, this, true);\r
18712                 }\r
18713             }\r
18714             Animation.prototype._enabled.call(this, enabled, ignoreTimeline);\r
18715             if (this._notifyPluginsOfEnabled) if (this._firstPT) {\r
18716                 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);\r
18717             }\r
18718             return false;\r
18719         };\r
18720 \r
18721 \r
18722 //----TweenLite static methods -----------------------------------------------------\r
18723 \r
18724         TweenLite.to = function(target, duration, vars) {\r
18725             return new TweenLite(target, duration, vars);\r
18726         };\r
18727 \r
18728         TweenLite.from = function(target, duration, vars) {\r
18729             vars.runBackwards = true;\r
18730             vars.immediateRender = (vars.immediateRender != false);\r
18731             return new TweenLite(target, duration, vars);\r
18732         };\r
18733 \r
18734         TweenLite.fromTo = function(target, duration, fromVars, toVars) {\r
18735             toVars.startAt = fromVars;\r
18736             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
18737             return new TweenLite(target, duration, toVars);\r
18738         };\r
18739 \r
18740         TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {\r
18741             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});\r
18742         };\r
18743 \r
18744         TweenLite.set = function(target, vars) {\r
18745             return new TweenLite(target, 0, vars);\r
18746         };\r
18747 \r
18748         TweenLite.getTweensOf = function(target, onlyActive) {\r
18749             if (target == null) { return []; }\r
18750             target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;\r
18751             var i, a, j, t;\r
18752             if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {\r
18753                 i = target.length;\r
18754                 a = [];\r
18755                 while (--i > -1) {\r
18756                     a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));\r
18757                 }\r
18758                 i = a.length;\r
18759                 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)\r
18760                 while (--i > -1) {\r
18761                     t = a[i];\r
18762                     j = i;\r
18763                     while (--j > -1) {\r
18764                         if (t === a[j]) {\r
18765                             a.splice(i, 1);\r
18766                         }\r
18767                     }\r
18768                 }\r
18769             } else {\r
18770                 a = _register(target).concat();\r
18771                 i = a.length;\r
18772                 while (--i > -1) {\r
18773                     if (a[i]._gc || (onlyActive && !a[i].isActive())) {\r
18774                         a.splice(i, 1);\r
18775                     }\r
18776                 }\r
18777             }\r
18778             return a;\r
18779         };\r
18780 \r
18781         TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {\r
18782             if (typeof(onlyActive) === "object") {\r
18783                 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)\r
18784                 onlyActive = false;\r
18785             }\r
18786             var a = TweenLite.getTweensOf(target, onlyActive),\r
18787                 i = a.length;\r
18788             while (--i > -1) {\r
18789                 a[i]._kill(vars, target);\r
18790             }\r
18791         };\r
18792 \r
18793 \r
18794 \r
18795 /*\r
18796  * ----------------------------------------------------------------\r
18797  * 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)\r
18798  * ----------------------------------------------------------------\r
18799  */\r
18800         var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {\r
18801                     this._overwriteProps = (props || "").split(",");\r
18802                     this._propName = this._overwriteProps[0];\r
18803                     this._priority = priority || 0;\r
18804                     this._super = TweenPlugin.prototype;\r
18805                 }, true);\r
18806 \r
18807         p = TweenPlugin.prototype;\r
18808         TweenPlugin.version = "1.10.1";\r
18809         TweenPlugin.API = 2;\r
18810         p._firstPT = null;\r
18811 \r
18812         p._addTween = function(target, prop, start, end, overwriteProp, round) {\r
18813             var c, pt;\r
18814             if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {\r
18815                 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};\r
18816                 if (pt._next) {\r
18817                     pt._next._prev = pt;\r
18818                 }\r
18819                 return pt;\r
18820             }\r
18821         };\r
18822 \r
18823         p.setRatio = function(v) {\r
18824             var pt = this._firstPT,\r
18825                 min = 0.000001,\r
18826                 val;\r
18827             while (pt) {\r
18828                 val = pt.c * v + pt.s;\r
18829                 if (pt.r) {\r
18830                     val = Math.round(val);\r
18831                 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser\r
18832                     val = 0;\r
18833                 }\r
18834                 if (pt.f) {\r
18835                     pt.t[pt.p](val);\r
18836                 } else {\r
18837                     pt.t[pt.p] = val;\r
18838                 }\r
18839                 pt = pt._next;\r
18840             }\r
18841         };\r
18842 \r
18843         p._kill = function(lookup) {\r
18844             var a = this._overwriteProps,\r
18845                 pt = this._firstPT,\r
18846                 i;\r
18847             if (lookup[this._propName] != null) {\r
18848                 this._overwriteProps = [];\r
18849             } else {\r
18850                 i = a.length;\r
18851                 while (--i > -1) {\r
18852                     if (lookup[a[i]] != null) {\r
18853                         a.splice(i, 1);\r
18854                     }\r
18855                 }\r
18856             }\r
18857             while (pt) {\r
18858                 if (lookup[pt.n] != null) {\r
18859                     if (pt._next) {\r
18860                         pt._next._prev = pt._prev;\r
18861                     }\r
18862                     if (pt._prev) {\r
18863                         pt._prev._next = pt._next;\r
18864                         pt._prev = null;\r
18865                     } else if (this._firstPT === pt) {\r
18866                         this._firstPT = pt._next;\r
18867                     }\r
18868                 }\r
18869                 pt = pt._next;\r
18870             }\r
18871             return false;\r
18872         };\r
18873 \r
18874         p._roundProps = function(lookup, value) {\r
18875             var pt = this._firstPT;\r
18876             while (pt) {\r
18877                 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.\r
18878                     pt.r = value;\r
18879                 }\r
18880                 pt = pt._next;\r
18881             }\r
18882         };\r
18883 \r
18884         TweenLite._onPluginEvent = function(type, tween) {\r
18885             var pt = tween._firstPT,\r
18886                 changed, pt2, first, last, next;\r
18887             if (type === "_onInitAllProps") {\r
18888                 //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.\r
18889                 while (pt) {\r
18890                     next = pt._next;\r
18891                     pt2 = first;\r
18892                     while (pt2 && pt2.pr > pt.pr) {\r
18893                         pt2 = pt2._next;\r
18894                     }\r
18895                     if ((pt._prev = pt2 ? pt2._prev : last)) {\r
18896                         pt._prev._next = pt;\r
18897                     } else {\r
18898                         first = pt;\r
18899                     }\r
18900                     if ((pt._next = pt2)) {\r
18901                         pt2._prev = pt;\r
18902                     } else {\r
18903                         last = pt;\r
18904                     }\r
18905                     pt = next;\r
18906                 }\r
18907                 pt = tween._firstPT = first;\r
18908             }\r
18909             while (pt) {\r
18910                 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {\r
18911                     changed = true;\r
18912                 }\r
18913                 pt = pt._next;\r
18914             }\r
18915             return changed;\r
18916         };\r
18917 \r
18918         TweenPlugin.activate = function(plugins) {\r
18919             var i = plugins.length;\r
18920             while (--i > -1) {\r
18921                 if (plugins[i].API === TweenPlugin.API) {\r
18922                     _plugins[(new plugins[i]())._propName] = plugins[i];\r
18923                 }\r
18924             }\r
18925             return true;\r
18926         };\r
18927 \r
18928         //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.\r
18929         _gsDefine.plugin = function(config) {\r
18930             if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }\r
18931             var propName = config.propName,\r
18932                 priority = config.priority || 0,\r
18933                 overwriteProps = config.overwriteProps,\r
18934                 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},\r
18935                 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",\r
18936                     function() {\r
18937                         TweenPlugin.call(this, propName, priority);\r
18938                         this._overwriteProps = overwriteProps || [];\r
18939                     }, (config.global === true)),\r
18940                 p = Plugin.prototype = new TweenPlugin(propName),\r
18941                 prop;\r
18942             p.constructor = Plugin;\r
18943             Plugin.API = config.API;\r
18944             for (prop in map) {\r
18945                 if (typeof(config[prop]) === "function") {\r
18946                     p[map[prop]] = config[prop];\r
18947                 }\r
18948             }\r
18949             Plugin.version = config.version;\r
18950             TweenPlugin.activate([Plugin]);\r
18951             return Plugin;\r
18952         };\r
18953 \r
18954 \r
18955         //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.\r
18956         a = window._gsQueue;\r
18957         if (a) {\r
18958             for (i = 0; i < a.length; i++) {\r
18959                 a[i]();\r
18960             }\r
18961             for (p in _defLookup) {\r
18962                 if (!_defLookup[p].func) {\r
18963                     //window.console.log("GSAP encountered missing dependency: com.greensock." + p);\r
18964                 }\r
18965             }\r
18966         }\r
18967 \r
18968         _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated\r
18969 \r
18970 })(window);\r
18971 \r
18972 angular.module('b2b.att.collapse', ['b2b.att.transition'])\r
18973 \r
18974 // The collapsible directive indicates a block of html that will expand and collapse\r
18975 .directive('b2bCollapse', ['$transition', function($transition) {\r
18976     // CSS transitions don't work with height: auto, so we have to manually change the height to a\r
18977     // specific value and then once the animation completes, we can reset the height to auto.\r
18978     // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class\r
18979     // "collapse") then you trigger a change to height 0 in between.\r
18980     // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!\r
18981 \r
18982     var props = {\r
18983         open: {\r
18984             marginTop: null,\r
18985             marginBottom: null,\r
18986             paddingTop: null,\r
18987             paddingBottom: null,\r
18988             display: 'block'\r
18989         },\r
18990         closed: {\r
18991             marginTop: 0,\r
18992             marginBottom: 0,\r
18993             paddingTop: 0,\r
18994             paddingBottom: 0,\r
18995             display: 'none'\r
18996         }\r
18997     };\r
18998 \r
18999     var fixUpHeight = function(scope, element, height) {\r
19000         // We remove the collapse CSS class to prevent a transition when we change to height: auto\r
19001         element.removeClass('b2bCollapse');\r
19002         element.css({height: height});\r
19003         //adjusting for any margin or padding\r
19004         if (height === 0) {\r
19005             element.css(props.closed);\r
19006         } else {\r
19007             element.css(props.open);\r
19008         }\r
19009         // It appears that  reading offsetWidth makes the browser realise that we have changed the\r
19010         // height already :-/\r
19011         var x = element[0].offsetWidth;\r
19012         element.addClass('b2bCollapse');\r
19013     };\r
19014 \r
19015     return {\r
19016         link: function(scope, element, attrs) {\r
19017             var isCollapsed;\r
19018             var initialAnimSkip = true;\r
19019             scope.$watch(function() {\r
19020                 return element[0].scrollHeight;\r
19021             }, function(value) {\r
19022                 //The listener is called when scrollHeight changes\r
19023                 //It actually does on 2 scenarios: \r
19024                 // 1. Parent is set to display none\r
19025                 // 2. angular bindings inside are resolved\r
19026                 //When we have a change of scrollHeight we are setting again the correct height if the group is opened\r
19027                 if (element[0].scrollHeight !== 0) {\r
19028                     if (!isCollapsed) {\r
19029                         if (initialAnimSkip) {\r
19030                             fixUpHeight(scope, element, element[0].scrollHeight + 'px');\r
19031                         } else {\r
19032                             fixUpHeight(scope, element, 'auto');\r
19033                             element.css({overflow: 'visible'});\r
19034                         }\r
19035                     }\r
19036                 }\r
19037             });\r
19038 \r
19039             scope.$watch(attrs.b2bCollapse, function(value) {\r
19040                 if (value) {\r
19041                     collapse();\r
19042                 } else {\r
19043                     expand();\r
19044                 }\r
19045             });\r
19046 \r
19047 \r
19048             var currentTransition;\r
19049             var doTransition = function(change) {\r
19050                 if (currentTransition) {\r
19051                     currentTransition.cancel();\r
19052                 }\r
19053                 currentTransition = $transition(element, change);\r
19054                 currentTransition.then(\r
19055                         function() {\r
19056                             currentTransition = undefined;\r
19057                         },\r
19058                         function() {\r
19059                             currentTransition = undefined;\r
19060                         }\r
19061                 );\r
19062                 return currentTransition;\r
19063             };\r
19064 \r
19065             var expand = function() {\r
19066                 scope.postTransition = true; \r
19067                 if (initialAnimSkip) {\r
19068                     initialAnimSkip = false;\r
19069                     if (!isCollapsed) {\r
19070                         fixUpHeight(scope, element, 'auto');\r
19071                     }\r
19072                 } else {\r
19073                     //doTransition({ height : element[0].scrollHeight + 'px' })\r
19074                     doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))\r
19075                             .then(function() {\r
19076                                 // This check ensures that we don't accidentally update the height if the user has closed\r
19077                                 // the group while the animation was still running\r
19078                                 if (!isCollapsed) {\r
19079                                     fixUpHeight(scope, element, 'auto');\r
19080                                 }\r
19081                             });\r
19082                 }\r
19083                 isCollapsed = false;\r
19084             };\r
19085 \r
19086             var collapse = function() {\r
19087                 isCollapsed = true;\r
19088                 if (initialAnimSkip) {\r
19089                     initialAnimSkip = false;\r
19090                     fixUpHeight(scope, element, 0);\r
19091                 } else {\r
19092                     fixUpHeight(scope, element, element[0].scrollHeight + 'px');\r
19093                     doTransition(angular.extend({height: 0}, props.closed)).then(function() {\r
19094                         scope.postTransition = false;\r
19095                     });\r
19096                     element.css({overflow: 'hidden'});\r
19097                 }\r
19098             };\r
19099         }\r
19100     };\r
19101 }]);\r
19102 angular.module('b2b.att.position', [])\r
19103 \r
19104 .factory('$position', ['$document', '$window', function ($document, $window) {\r
19105     function getStyle(el, cssprop) {\r
19106         if (el.currentStyle) { //IE\r
19107             return el.currentStyle[cssprop];\r
19108         } else if ($window.getComputedStyle) {\r
19109             return $window.getComputedStyle(el)[cssprop];\r
19110         }\r
19111         // finally try and get inline style\r
19112         return el.style[cssprop];\r
19113     }\r
19114 \r
19115     /**\r
19116      * Checks if a given element is statically positioned\r
19117      * @param element - raw DOM element\r
19118      */\r
19119     function isStaticPositioned(element) {\r
19120         return (getStyle(element, "position") || 'static') === 'static';\r
19121     }\r
19122 \r
19123     /**\r
19124      * returns the closest, non-statically positioned parentOffset of a given element\r
19125      * @param element\r
19126      */\r
19127     var parentOffsetEl = function (element) {\r
19128         var docDomEl = $document[0];\r
19129         var offsetParent = element.offsetParent || docDomEl;\r
19130         while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {\r
19131             offsetParent = offsetParent.offsetParent;\r
19132         }\r
19133         return offsetParent || docDomEl;\r
19134     };\r
19135 \r
19136     return {\r
19137         /**\r
19138          * Provides read-only equivalent of jQuery's position function:\r
19139          * http://api.jquery.com/position/\r
19140          */\r
19141         position: function (element) {\r
19142             var elBCR = this.offset(element);\r
19143             var offsetParentBCR = {\r
19144                 top: 0,\r
19145                 left: 0\r
19146             };\r
19147             var offsetParentEl = parentOffsetEl(element[0]);\r
19148             if (offsetParentEl !== $document[0]) {\r
19149                 offsetParentBCR = this.offset(angular.element(offsetParentEl));\r
19150                 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;\r
19151                 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;\r
19152             }\r
19153 \r
19154             return {\r
19155                 width: element.prop('offsetWidth'),\r
19156                 height: element.prop('offsetHeight'),\r
19157                 top: elBCR.top - offsetParentBCR.top,\r
19158                 left: elBCR.left - offsetParentBCR.left\r
19159             };\r
19160         },\r
19161 \r
19162         /**\r
19163          * Provides read-only equivalent of jQuery's offset function:\r
19164          * http://api.jquery.com/offset/\r
19165          */\r
19166         offset: function (element) {\r
19167             var boundingClientRect = element[0].getBoundingClientRect();\r
19168             return {\r
19169                 width: element.prop('offsetWidth'),\r
19170                 height: element.prop('offsetHeight'),\r
19171                 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),\r
19172                 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)\r
19173             };\r
19174         },\r
19175         \r
19176          /**\r
19177          * Provides functionality to check whether an element is in view port.\r
19178          */\r
19179         isElementInViewport: function (element) {\r
19180             if (element) {\r
19181                 var rect = element[0].getBoundingClientRect();\r
19182                 return (\r
19183                     rect.top >= 0 &&\r
19184                     rect.left >= 0 &&\r
19185                     rect.bottom <= ($window.innerHeight || $document[0].documentElement.clientHeight) &&\r
19186                     rect.right <= ($window.innerWidth || $document[0].documentElement.clientWidth)\r
19187                 );\r
19188             } else {\r
19189                 return false;\r
19190             }\r
19191         }\r
19192     };\r
19193 }])\r
19194 \r
19195 .factory('$isElement', [function () {\r
19196     var isElement = function (currentElem, targetElem, alternateElem) {\r
19197         if (currentElem[0] === targetElem[0]) {\r
19198             return true;\r
19199         } else if (currentElem[0] === alternateElem[0]) {\r
19200             return false;\r
19201         } else {\r
19202             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);\r
19203         }\r
19204     };\r
19205 \r
19206     return isElement;\r
19207 }])\r
19208 \r
19209 .directive('attPosition', ['$position', function ($position) {\r
19210     return {\r
19211         restrict: 'A',\r
19212         link: function (scope, elem, attr) {\r
19213             scope.$watchCollection(function () {\r
19214                 return $position.position(elem);\r
19215             }, function (value) {\r
19216                 scope[attr.attPosition] = value;\r
19217             });\r
19218         }\r
19219     };\r
19220 }]);\r
19221 \r
19222 angular.module('b2b.att.transition', [])\r
19223 \r
19224 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {\r
19225 \r
19226   var $transition = function(element, trigger, options) {\r
19227     options = options || {};\r
19228     var deferred = $q.defer();\r
19229     var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];\r
19230 \r
19231     var transitionEndHandler = function() {\r
19232       $rootScope.$apply(function() {\r
19233         element.unbind(endEventName, transitionEndHandler);\r
19234         deferred.resolve(element);\r
19235       });\r
19236     };\r
19237 \r
19238     if (endEventName) {\r
19239       element.bind(endEventName, transitionEndHandler);\r
19240     }\r
19241 \r
19242     // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur\r
19243     $timeout(function() {\r
19244       if ( angular.isString(trigger) ) {\r
19245         element.addClass(trigger);\r
19246       } else if ( angular.isFunction(trigger) ) {\r
19247         trigger(element);\r
19248       } else if ( angular.isObject(trigger) ) {\r
19249         element.css(trigger);\r
19250       }\r
19251       //If browser does not support transitions, instantly resolve\r
19252       if ( !endEventName ) {\r
19253         deferred.resolve(element);\r
19254       }\r
19255     }, 100);\r
19256 \r
19257     // Add our custom cancel function to the promise that is returned\r
19258     // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,\r
19259     // i.e. it will therefore never raise a transitionEnd event for that transition\r
19260     deferred.promise.cancel = function() {\r
19261       if ( endEventName ) {\r
19262         element.unbind(endEventName, transitionEndHandler);\r
19263       }\r
19264       deferred.reject('Transition cancelled');\r
19265     };\r
19266 \r
19267     return deferred.promise;\r
19268   };\r
19269 \r
19270   // Work out the name of the transitionEnd event\r
19271   var transElement = document.createElement('trans');\r
19272   var transitionEndEventNames = {\r
19273     'WebkitTransition': 'webkitTransitionEnd',\r
19274     'MozTransition': 'transitionend',\r
19275     'OTransition': 'oTransitionEnd',\r
19276     'transition': 'transitionend'\r
19277   };\r
19278   var animationEndEventNames = {\r
19279     'WebkitTransition': 'webkitAnimationEnd',\r
19280     'MozTransition': 'animationend',\r
19281     'OTransition': 'oAnimationEnd',\r
19282     'transition': 'animationend'\r
19283   };\r
19284   function findEndEventName(endEventNames) {\r
19285     for (var name in endEventNames){\r
19286       if (transElement.style[name] !== undefined) {\r
19287         return endEventNames[name];\r
19288       }\r
19289     }\r
19290   }\r
19291   $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);\r
19292   $transition.animationEndEventName = findEndEventName(animationEndEventNames);\r
19293   return $transition;\r
19294 }])\r
19295 \r
19296 .factory('$scrollTo', ['$window', function($window) {\r
19297     var $scrollTo = function(offsetLeft, offsetTop, duration) {\r
19298         TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});\r
19299     };\r
19300     return $scrollTo;\r
19301 }])\r
19302 .factory('animation', function(){\r
19303     return TweenMax;\r
19304 })\r
19305 .factory('$progressBar', function(){\r
19306 \r
19307    //Provides a function to pass in code for closure purposes\r
19308    var loadingAnimationCreator = function(onUpdateCallback){\r
19309 \r
19310       //Use closure to setup some resuable code\r
19311       var loadingAnimation = function(callback, duration){\r
19312           TweenMax.to({}, duration, {\r
19313               onUpdateParams: ["{self}"],\r
19314               onUpdate: onUpdateCallback,\r
19315               onComplete: callback\r
19316           });\r
19317       };\r
19318       //Returns a function that takes a callback function and a duration for the animation\r
19319       return (function(){\r
19320         return loadingAnimation;\r
19321       })();\r
19322     };\r
19323 \r
19324   return loadingAnimationCreator;\r
19325 })\r
19326 .factory('$height', function(){\r
19327   var heightAnimation = function(element,duration,height,alpha){\r
19328     TweenMax.to(element,\r
19329       duration,\r
19330       {height:height, autoAlpha:alpha},\r
19331       0);\r
19332   };\r
19333   return heightAnimation;\r
19334 });\r
19335 angular.module('b2b.att.utilities', ['ngSanitize'])\r
19336 .constant('b2bUtilitiesConfig', {\r
19337     prev: '37',\r
19338     up: '38',\r
19339     next: '39',\r
19340     down: '40',\r
19341     type: 'list',\r
19342     columns: 1,\r
19343     enableSearch: false,\r
19344     searchTimer: 200,\r
19345     circularTraversal: false\r
19346 })\r
19347 .constant('b2bWhenScrollEndsConstants', {\r
19348     'threshold': 100,\r
19349     'width': 0,\r
19350     'height': 0\r
19351 })\r
19352 // All breakpoints ranges from >= min and < max\r
19353 .constant('b2bAwdBreakpoints', {\r
19354     breakpoints: {\r
19355         mobile: {\r
19356             min: 1,\r
19357             max: 768\r
19358         },\r
19359         tablet: {\r
19360             min: 768,\r
19361             max: 1025\r
19362         },\r
19363         desktop: {\r
19364             min: 1025,\r
19365             max: 1920\r
19366         }\r
19367     }\r
19368 })\r
19369 .filter('groupBy', function ($timeout) {\r
19370     //Custom GroupBy Filter for treeNav, returns key string and value.childarray as set of grouped elements\r
19371     return function (data, key) {\r
19372         if (!key) return data;\r
19373         var outputPropertyName = '__groupBy__' + key;\r
19374         if (!data[outputPropertyName]) {\r
19375             var result = {};\r
19376             for (var i = 0; i < data.length; i++) {\r
19377                 if (!result[data[i][key]])\r
19378                     result[data[i][key]] = {};\r
19379                 if (!result[data[i][key]].childArray) {\r
19380                     result[data[i][key]].childArray = [];\r
19381                 }\r
19382                 result[data[i][key]].childArray.push(data[i]);\r
19383                 if (data[i].activeGrp && data[i].activeGrp == true) {\r
19384                     console.log('make ' + data[i].grpChild + ' active');\r
19385                     result[data[i][key]].showGroup = true;\r
19386                 }\r
19387             }\r
19388             Object.defineProperty(result, 'length', {enumerable: false,value: Object.keys(result).length});\r
19389             Object.defineProperty(data, outputPropertyName, {enumerable: false,configurable: true,writable:false,value:result});\r
19390             $timeout(function(){delete data[outputPropertyName];},0,false);\r
19391         }\r
19392         return data[outputPropertyName];\r
19393     };\r
19394 })\r
19395 .filter('searchObjectPropertiesFilter', [function() {\r
19396     return function(items, searchText, attrs) {\r
19397         if(!searchText){\r
19398             return items;\r
19399         }\r
19400         var filtered = [];\r
19401         searchText = searchText.toLowerCase();\r
19402         angular.forEach(items, function(item) {\r
19403             angular.forEach(attrs, function(attr) {\r
19404                 if (item.hasOwnProperty(attr) && item[attr].toLowerCase().includes(searchText)) {\r
19405                     filtered.push(item);\r
19406                     return;\r
19407                 }\r
19408             });\r
19409         });\r
19410         return filtered;\r
19411     };\r
19412 }])\r
19413 .filter('unsafe',[ '$sce', function ($sce) { \r
19414     return function(val){ \r
19415        return $sce.trustAsHtml(val); \r
19416     }; \r
19417 }])\r
19418 .filter('b2bHighlight', function () {\r
19419     function escapeRegexp(queryToEscape) {\r
19420         return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');\r
19421     }\r
19422     return function (matchItem, query, className) {\r
19423         return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;\r
19424     }\r
19425 })\r
19426 /*License (MIT)\r
19427 Copyright Â© 2013 Matt Diamond\r
19428 https://github.com/cwilso/AudioRecorder/blob/master/js/recorderjs/recorder.js\r
19429 */\r
19430 .factory('b2bRecorder', function() {\r
19431 \r
19432     var Recorder = function(source, cfg) {\r
19433         var WORKER_PATH = 'recorderWorker.js';\r
19434         var config = cfg || {};\r
19435         var bufferLen = config.bufferLen || 4096;\r
19436         this.context = source.context;\r
19437         if(!this.context.createScriptProcessor) {\r
19438             this.node = this.context.createJavacriptProcessor(bufferLen, 2, 2);\r
19439         } else {\r
19440             this.node = this.context.createScriptProcessor(bufferLen, 2, 2);\r
19441         }\r
19442         var workerCode = 'function init(a){sampleRate=a.sampleRate}function record(a){recBuffersL.push(a[0]),recBuffersR.push(a[1]),recLength+=a[0].length}function exportWAV(a){var b=mergeBuffers(recBuffersL,recLength),c=mergeBuffers(recBuffersR,recLength),d=interleave(b,c),e=encodeWAV(d),f=new Blob([e],{type:a});this.postMessage(f)}function exportMonoWAV(a){var b=mergeBuffers(recBuffersL,recLength),c=encodeWAV(b,!0),d=new Blob([c],{type:a});this.postMessage(d)}function getBuffers(){var a=[];a.push(mergeBuffers(recBuffersL,recLength)),a.push(mergeBuffers(recBuffersR,recLength)),this.postMessage(a)}function clear(){recLength=0,recBuffersL=[],recBuffersR=[]}function mergeBuffers(a,b){for(var c=new Float32Array(b),d=0,e=0;e<a.length;e++)c.set(a[e],d),d+=a[e].length;return c}function interleave(a,b){for(var c=a.length+b.length,d=new Float32Array(c),e=0,f=0;e<c;)d[e++]=a[f],d[e++]=b[f],f++;return d}function floatTo16BitPCM(a,b,c){for(var d=0;d<c.length;d++,b+=2){var e=Math.max(-1,Math.min(1,c[d]));a.setInt16(b,e<0?32768*e:32767*e,!0)}}function writeString(a,b,c){for(var d=0;d<c.length;d++)a.setUint8(b+d,c.charCodeAt(d))}function encodeWAV(a,b){var c=new ArrayBuffer(44+2*a.length),d=new DataView(c);return writeString(d,0,"RIFF"),d.setUint32(4,32+2*a.length,!0),writeString(d,8,"WAVE"),writeString(d,12,"fmt "),d.setUint32(16,16,!0),d.setUint16(20,1,!0),d.setUint16(22,b?1:2,!0),d.setUint32(24,sampleRate,!0),d.setUint32(28,4*sampleRate,!0),d.setUint16(32,4,!0),d.setUint16(34,16,!0),writeString(d,36,"data"),d.setUint32(40,2*a.length,!0),floatTo16BitPCM(d,44,a),d}var recLength=0,recBuffersL=[],recBuffersR=[],sampleRate;this.onmessage=function(a){switch(a.data.command){case"init":init(a.data.config);break;case"record":record(a.data.buffer);break;case"exportWAV":exportWAV(a.data.type);break;case"exportMonoWAV":exportMonoWAV(a.data.type);break;case"getBuffers":getBuffers();break;case"clear":clear()}};';\r
19443         var blob = new Blob([workerCode]);\r
19444 \r
19445         var worker = new Worker(window.URL.createObjectURL(blob)); //TODO: Use a blob instead\r
19446         worker.postMessage({\r
19447             command: 'init',\r
19448             config: {\r
19449                 sampleRate: this.context.sampleRate\r
19450             }\r
19451         });\r
19452         var recording = false,\r
19453             currCallback;\r
19454 \r
19455         this.node.onaudioprocess = function(e) {\r
19456             if (!recording) return;\r
19457             worker.postMessage({\r
19458                 command: 'record',\r
19459                 buffer: [\r
19460                     e.inputBuffer.getChannelData(0),\r
19461                     e.inputBuffer.getChannelData(1)\r
19462                 ]\r
19463             });\r
19464         };\r
19465 \r
19466         this.configure = function(cfg) {\r
19467             for (var prop in cfg) {//TODO: look into using angular.extend() here\r
19468                 if (cfg.hasOwnProperty(prop)) {\r
19469                     config[prop] = cfg[prop];\r
19470                 }\r
19471             }\r
19472         };\r
19473 \r
19474         this.record = function() {\r
19475             recording = true;\r
19476         };\r
19477 \r
19478         this.stop = function() {\r
19479             recording = false;\r
19480         };\r
19481 \r
19482         this.clear = function() {\r
19483             worker.postMessage({ command: 'clear' });\r
19484             window.URL.revokeObjectURL(blob);\r
19485         };\r
19486 \r
19487         this.getBuffers = function(cb) {\r
19488             currCallback = cb || config.callback;\r
19489             worker.postMessage({ command: 'getBuffers' });\r
19490         };\r
19491 \r
19492         this.exportWAV = function(cb, type) {\r
19493             currCallback = cb || config.callback;\r
19494             type = type || config.type || 'audio/wav';\r
19495             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');\r
19496             worker.postMessage({\r
19497                 command: 'exportWAV',\r
19498                 type: type\r
19499             });\r
19500         };\r
19501 \r
19502         this.exportMonoWAV = function(cb, type) {\r
19503             currCallback = cb || config.callback;\r
19504             type = type || config.type || 'audio/wav';\r
19505             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');\r
19506             worker.postMessage({\r
19507                 command: 'exportMonoWAV',\r
19508                 type: type\r
19509             });\r
19510         };\r
19511 \r
19512         worker.onmessage = function(e) {\r
19513             var blob = e.data;\r
19514             currCallback(blob);\r
19515         };\r
19516 \r
19517         source.connect(this.node);\r
19518         this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggerd in Chrome\r
19519 \r
19520     };\r
19521 \r
19522     return Recorder;\r
19523 \r
19524 })\r
19525 .factory('b2bViewport', function() {\r
19526   /* Source: https://gist.github.com/bjankord/2399828 */\r
19527   var _viewportWidth = function() {\r
19528     var vpw;\r
19529     var webkit = (!(window.webkitConvertPointFromNodeToPage == null));\r
19530     \r
19531     // Webkit:\r
19532     if ( webkit ) {\r
19533       var vpwtest = document.createElement( "div" );\r
19534       // Sets test div to width 100%, !important overrides any other misc. box model styles that may be set in the CSS\r
19535       vpwtest.style.cssText = "width:100% !important; margin:0 !important; padding:0 !important; border:none !important;";\r
19536       document.documentElement.insertBefore( vpwtest, document.documentElement.firstChild );\r
19537       vpw = vpwtest.offsetWidth;\r
19538       document.documentElement.removeChild( vpwtest );\r
19539     }\r
19540     // IE 6-8:\r
19541     else if ( window.innerWidth === undefined ) { \r
19542       vpw = document.documentElement.clientWidth; \r
19543     }\r
19544     // Other:\r
19545     else{\r
19546       vpw =  window.innerWidth;\r
19547     }\r
19548 \r
19549     return (vpw);\r
19550   }\r
19551   return {\r
19552     viewportWidth: _viewportWidth\r
19553   };\r
19554 })\r
19555 .directive('b2bWhenScrollEnds', function(b2bWhenScrollEndsConstants, $log) {\r
19556     return {\r
19557         restrict: 'A',\r
19558         link: function (scope, element, attrs) {\r
19559             /**\r
19560             * Exposed Attributes:\r
19561             *       threshold - integer - number of pixels before scrollbar hits end that callback is called\r
19562             *       width - integer - override for element's width (px)\r
19563             *       height - integer - override for element's height (px)\r
19564             *       axis - string - x/y for scroll bar axis\r
19565             */\r
19566             var threshold = parseInt(attrs.threshold, 10) || b2bWhenScrollEndsConstants.threshold;\r
19567 \r
19568             if (!attrs.axis || attrs.axis === '') {\r
19569                 $log.warn('axis attribute must be defined for b2bWhenScrollEnds.');\r
19570                 return;\r
19571             }\r
19572 \r
19573             if (attrs.axis === 'x') {\r
19574                 visibleWidth = parseInt(attrs.width, 10) || b2bWhenScrollEndsConstants.width;\r
19575                 if (element.css('width')) {\r
19576                     visibleWidth = element.css('width').split('px')[0];  \r
19577                 }\r
19578 \r
19579                 element[0].addEventListener('scroll', function() {\r
19580                     var scrollableWidth = element.prop('scrollWidth');\r
19581                     if (scrollableWidth === undefined) {\r
19582                         scrollableWidth = 1;\r
19583                     }\r
19584                     var hiddenContentWidth = scrollableWidth - visibleWidth;\r
19585 \r
19586                     if (hiddenContentWidth - element[0].scrollLeft <= threshold) {\r
19587                         /* Scroll almost at bottom, load more rows */\r
19588                         scope.$apply(attrs.b2bWhenScrollEnds);\r
19589                     }\r
19590                 });\r
19591             } else if (attrs.axis === 'y') {\r
19592                 visibleHeight = parseInt(attrs.height, 10) || b2bWhenScrollEndsConstants.height;\r
19593                 if (element.css('width')) {\r
19594                     visibleHeight = element.css('height').split('px')[0]; \r
19595                 }\r
19596 \r
19597                 element[0].addEventListener('scroll', function() {\r
19598                     var scrollableHeight = element.prop('scrollHeight');\r
19599                     if (scrollableHeight === undefined) {\r
19600                         scrollableHeight = 1;\r
19601                     }\r
19602                     var hiddenContentHeight = scrollableHeight - visibleHeight;\r
19603 \r
19604                     if (hiddenContentHeight - element[0].scrollTop <= threshold) {\r
19605                         /* Scroll almost at bottom, load more rows */\r
19606                         scope.$apply(attrs.b2bWhenScrollEnds);\r
19607                     }\r
19608                 });\r
19609             }\r
19610         }\r
19611     };\r
19612 })\r
19613 \r
19614 .factory('$windowBind', ['$window', '$timeout', function($window, $timeout) {\r
19615     var win = angular.element($window);\r
19616     var _scroll = function (flag, callbackFunc, scope) {\r
19617         scope.$watch(flag, function (val) {\r
19618             $timeout(function () {\r
19619                 if (val) {\r
19620                     win.bind('scroll', callbackFunc);\r
19621                 } else {\r
19622                     win.unbind('scroll', callbackFunc);\r
19623                 }\r
19624             });\r
19625         });\r
19626     };\r
19627 \r
19628     var throttle = function(type, name, obj) {\r
19629         obj = obj || window;\r
19630         var running = false;\r
19631         var func = function() {\r
19632             if (running) { return; }\r
19633             running = true;\r
19634              requestAnimationFrame(function() {\r
19635                 obj.dispatchEvent(new CustomEvent(name));\r
19636                 running = false;\r
19637             });\r
19638         };\r
19639         obj.addEventListener(type, func);\r
19640     };\r
19641 \r
19642     var _resize = function(callbackFunc, scope) {\r
19643         throttle("resize", "optimizedResize");\r
19644         window.addEventListener("optimizedResize", function(event) {\r
19645             callbackFunc();\r
19646             //win.bind(event, callbackFunc);\r
19647             if (!scope.$$phase) {\r
19648                 scope.$digest();\r
19649             }\r
19650         });\r
19651     };\r
19652 \r
19653     var _click = function (flag, callbackFunc, scope) {\r
19654         scope.$watch(flag, function (val) {\r
19655             $timeout(function () {\r
19656                 if (val) {\r
19657                     win.bind('click', callbackFunc);\r
19658                 } else {\r
19659                     win.unbind('click', callbackFunc);\r
19660                 }\r
19661             });\r
19662         });\r
19663     };\r
19664 \r
19665     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {\r
19666         if (timeoutFlag) {\r
19667             if (!(timeoutValue)) {\r
19668                 timeoutValue = 0;\r
19669             }\r
19670             scope.$watch(flag, function (newVal, oldVal) {\r
19671                 if (newVal !== oldVal) {\r
19672                     $timeout(function () {\r
19673                         if (newVal) {\r
19674                             win.bind(event, callbackFunc);\r
19675                         } else {\r
19676                             win.unbind(event, callbackFunc);\r
19677                         }\r
19678                     }, timeoutValue);\r
19679                 }\r
19680             });\r
19681         } else {\r
19682             scope.$watch(flag, function (newVal, oldVal) {\r
19683                 if (newVal !== oldVal) {\r
19684                     if (newVal) {\r
19685                         win.bind(event, callbackFunc);\r
19686                     } else {\r
19687                         win.unbind(event, callbackFunc);\r
19688                     }\r
19689                 }\r
19690             });\r
19691         }\r
19692     };\r
19693 \r
19694     return {\r
19695         click: _click,\r
19696         scroll: _scroll,\r
19697         event: _event, \r
19698         resize: _resize\r
19699     };\r
19700 }])\r
19701 \r
19702 .factory('keymap', function () {\r
19703     return {\r
19704         KEY: {\r
19705             TAB: 9,\r
19706             ENTER: 13,\r
19707             ESC: 27,\r
19708             SPACE: 32,\r
19709             LEFT: 37,\r
19710             UP: 38,\r
19711             RIGHT: 39,\r
19712             DOWN: 40,\r
19713             SHIFT: 16,\r
19714             CTRL: 17,\r
19715             ALT: 18,\r
19716             PAGE_UP: 33,\r
19717             PAGE_DOWN: 34,\r
19718             HOME: 36,\r
19719             END: 35,\r
19720             BACKSPACE: 8,\r
19721             DELETE: 46,\r
19722             COMMAND: 91\r
19723         },\r
19724         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 : "'"\r
19725         },\r
19726         isControl: function (e) {\r
19727             var k = e.keyCode;\r
19728             switch (k) {\r
19729             case this.KEY.COMMAND:\r
19730             case this.KEY.SHIFT:\r
19731             case this.KEY.CTRL:\r
19732             case this.KEY.ALT:\r
19733                 return true;\r
19734             default:;\r
19735             }\r
19736 \r
19737             if (e.metaKey) {\r
19738                 return true;\r
19739             }\r
19740 \r
19741             return false;\r
19742         },\r
19743         isFunctionKey: function (k) {\r
19744             k = k.keyCode ? k.keyCode : k;\r
19745             return k >= 112 && k <= 123;\r
19746         },\r
19747         isVerticalMovement: function (k) {\r
19748             return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);\r
19749         },\r
19750         isHorizontalMovement: function (k) {\r
19751             return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);\r
19752         },\r
19753         isAllowedKey: function (k) {\r
19754             return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);\r
19755         },\r
19756         isNumericKey: function (e) {\r
19757             var k = e.keyCode;\r
19758             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105)) {\r
19759                 return true;\r
19760             } else {\r
19761                 return false;\r
19762             }\r
19763         },\r
19764         isAlphaNumericKey: function (e) {\r
19765             var k = e.keyCode;\r
19766             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105) || (k >= 65 && k <= 90)) {\r
19767                 return true;\r
19768             } else {\r
19769                 return false;\r
19770             }\r
19771         }\r
19772     };\r
19773 })\r
19774 \r
19775 .factory('$isElement', [function () {\r
19776     var isElement = function (currentElem, targetElem, alternateElem) {\r
19777         if (currentElem[0] === targetElem[0]) {\r
19778             return true;\r
19779         } else if (currentElem[0] === alternateElem[0]) {\r
19780             return false;\r
19781         } else {\r
19782             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);\r
19783         }\r
19784     };\r
19785 \r
19786     return isElement;\r
19787 }])\r
19788 \r
19789 .factory('events', function () {\r
19790     var _stopPropagation = function (evt) {\r
19791         if (evt.stopPropagation) {\r
19792             evt.stopPropagation();\r
19793         } else {\r
19794             evt.returnValue = false;\r
19795         }\r
19796     };\r
19797     var _preventDefault = function (evt) {\r
19798         if (evt.preventDefault) {\r
19799             evt.preventDefault();\r
19800         } else {\r
19801             evt.returnValue = false;\r
19802         }\r
19803     }\r
19804     return {\r
19805         stopPropagation: _stopPropagation,\r
19806         preventDefault: _preventDefault\r
19807     };\r
19808 })\r
19809 \r
19810 \r
19811 .factory('$documentBind', ['$document', '$timeout', function ($document, $timeout) {\r
19812     var _click = function (flag, callbackFunc, scope) {\r
19813         scope.$watch(flag, function (val) {\r
19814             $timeout(function () {\r
19815                 if (val) {\r
19816                     $document.bind('click', callbackFunc);\r
19817                 } else {\r
19818                     $document.unbind('click', callbackFunc);\r
19819                 }\r
19820             });\r
19821         });\r
19822     };\r
19823 \r
19824     var _scroll = function (flag, callbackFunc, scope) {\r
19825         scope.$watch(flag, function (val) {\r
19826             $timeout(function () {\r
19827                 if (val) {\r
19828                     $document.bind('scroll', callbackFunc);\r
19829                 } else {\r
19830                     $document.unbind('scroll', callbackFunc);\r
19831                 }\r
19832             });\r
19833         });\r
19834     };\r
19835 \r
19836     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {\r
19837         if (timeoutFlag) {\r
19838             if (!(timeoutValue)) {\r
19839                 timeoutValue = 0;\r
19840             }\r
19841             scope.$watch(flag, function (newVal, oldVal) {\r
19842                 if (newVal !== oldVal) {\r
19843                     $timeout(function () {\r
19844                         if (newVal) {\r
19845                             $document.bind(event, callbackFunc);\r
19846                         } else {\r
19847                             $document.unbind(event, callbackFunc);\r
19848                         }\r
19849                     }, timeoutValue);\r
19850                 }\r
19851             });\r
19852         } else {\r
19853             scope.$watch(flag, function (newVal, oldVal) {\r
19854                 if (newVal !== oldVal) {\r
19855                     if (newVal) {\r
19856                         $document.bind(event, callbackFunc);\r
19857                     } else {\r
19858                         $document.unbind(event, callbackFunc);\r
19859                     }\r
19860                 }\r
19861             });\r
19862         }\r
19863     };\r
19864 \r
19865     return {\r
19866         click: _click,\r
19867         scroll: _scroll,\r
19868         event: _event\r
19869     };\r
19870 }])\r
19871 \r
19872 .directive('b2bOnlyNums', function (keymap) {\r
19873     return {\r
19874         restrict: 'A',\r
19875         require: 'ngModel',\r
19876         link: function (scope, elm, attrs, ctrl) {\r
19877             var maxChars = attrs.b2bOnlyNums ? attrs.b2bOnlyNums : 4;\r
19878             elm.on('keydown', function (event) {\r
19879                 if ((event.which >= 48 && event.which <= 57) || (event.which >= 96 && event.which <= 105)) {\r
19880                     // check for maximum characters allowed\r
19881                     if (elm.val().length < maxChars){\r
19882                         return true;\r
19883                     } else {\r
19884                         event.preventDefault();\r
19885                         return false;\r
19886                     }\r
19887                 } else if ([8, 9, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {\r
19888                     // to allow backspace, tab, enter, escape, arrows\r
19889                     return true;\r
19890                 } else if (event.altKey || event.ctrlKey) {\r
19891                     // to allow alter, control, and shift keys\r
19892                     return true;\r
19893                 } else {\r
19894                     // to stop others\r
19895                     event.preventDefault();\r
19896                     return false;\r
19897                 }\r
19898             });\r
19899 \r
19900             var validateString = function (value) {\r
19901                 if (angular.isUndefined(value) || value === null || value === '') {\r
19902                     return ctrl.$modelValue;\r
19903                 }\r
19904                 return value;\r
19905             };\r
19906             ctrl.$parsers.unshift(validateString);\r
19907         }\r
19908     }\r
19909 })\r
19910 \r
19911 .directive('b2bKeyupClick', [ function () {\r
19912     return {\r
19913         restrict: 'A',\r
19914         link: function (scope, elem, attr) {\r
19915             var keyCode = [];\r
19916             attr.$observe('b2bKeyupClick', function (value) {\r
19917                 if (value) {\r
19918                     keyCode = value.split(',');\r
19919                 }\r
19920             });\r
19921             elem.bind('keydown keyup', function (ev) {\r
19922                 var keyCodeCondition = function () {\r
19923                     var flag = false;\r
19924                     if (!(ev.keyCode)) {\r
19925                         if (ev.which) {\r
19926                             ev.keyCode = ev.which;\r
19927                         } else if (ev.charCode) {\r
19928                             ev.keyCode = ev.charCode;\r
19929                         }\r
19930                     }\r
19931                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {\r
19932                         flag = true;\r
19933                     }\r
19934                     return flag;\r
19935                 };\r
19936                 if (ev.type === 'keydown' && keyCodeCondition()) {\r
19937                     ev.preventDefault();\r
19938                 }\r
19939                 else if (ev.type === 'keyup' && keyCodeCondition()) {\r
19940                     elem[0].click();\r
19941                 }\r
19942             });\r
19943         }\r
19944     };\r
19945 }])\r
19946 \r
19947 .factory('b2bDOMHelper', function() {\r
19948 \r
19949     var _isTabable = function(node) {\r
19950         var element = angular.element(node);\r
19951         var tagName = element[0].tagName.toUpperCase();\r
19952 \r
19953         if (isHidden(element)) {\r
19954             return false;\r
19955         }\r
19956         if (element.attr('tabindex') !== undefined) {\r
19957             return (parseInt(element.attr('tabindex'), 10) >= 0);\r
19958         }\r
19959         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {\r
19960             if (tagName === 'A' || tagName === 'AREA') {\r
19961                 // anchors/areas without href are not focusable\r
19962                 return (element[0].href !== '');\r
19963             }\r
19964             return !(element[0].disabled || element[0].readOnly);\r
19965         }\r
19966         return false;\r
19967     };\r
19968 \r
19969     function isValidChild(child) {\r
19970         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';\r
19971     }\r
19972     \r
19973     function isHidden(obj) {\r
19974         var elem = angular.element(obj);\r
19975         var elemStyle = undefined;\r
19976         if(obj instanceof HTMLElement){\r
19977             elemStyle = window.getComputedStyle(obj);\r
19978         }\r
19979         else {\r
19980             elemStyle = window.getComputedStyle(obj[0]);\r
19981         }\r
19982         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || elemStyle.display === 'none' || elemStyle.visibility === 'hidden' || elem.css('visibility') === 'hidden';\r
19983     }\r
19984 \r
19985     function hasValidParent(obj) {\r
19986         return (isValidChild(obj) && obj.parentElement.nodeName !== 'BODY');\r
19987     }\r
19988 \r
19989     function traverse(obj, fromTop) {\r
19990         var obj = obj || document.getElementsByTagName('body')[0];\r
19991         if (isValidChild(obj) && _isTabable(obj)) {\r
19992             return obj;\r
19993         }\r
19994         // If object is hidden, skip it's children\r
19995         if (isValidChild(obj) && isHidden(obj)) {\r
19996             return undefined;\r
19997         } \r
19998         // If object is hidden, skip it's children\r
19999         if (angular.element(obj).hasClass('ng-hide')) {\r
20000             return undefined;\r
20001         }  \r
20002         if (obj.hasChildNodes()) {\r
20003             var child;\r
20004             if (fromTop) {\r
20005                 child = obj.firstChild;\r
20006             } else {\r
20007                 child = obj.lastChild;\r
20008             }\r
20009             while(child) {\r
20010                 var res =  traverse(child, fromTop);\r
20011                 if(res){\r
20012                     return res;\r
20013                 }\r
20014                 else{\r
20015                     if (fromTop) {\r
20016                         child = child.nextSibling;\r
20017                     } else {\r
20018                         child = child.previousSibling;\r
20019                     }\r
20020                 }\r
20021             }\r
20022         }\r
20023         else{\r
20024             return undefined;\r
20025         }\r
20026     }\r
20027 \r
20028     var _previousElement = function(el, isFocusable){\r
20029 \r
20030         var elem = el;\r
20031         if (el.hasOwnProperty('length')) {\r
20032             elem = el[0];\r
20033         }\r
20034 \r
20035         var parent = elem.parentElement;\r
20036         var previousElem = undefined;\r
20037 \r
20038         if(isFocusable) {\r
20039             if (hasValidParent(elem)) {\r
20040                 var siblings = angular.element(parent).children();\r
20041                 if (siblings.length > 0) {\r
20042                     // Good practice to splice out the elem from siblings if there, saving some time.\r
20043                     // We allow for a quick check for jumping to parent first before removing. \r
20044                     if (siblings[0] === elem) {\r
20045                         // If we are looking at immidiate parent and elem is first child, we need to go higher\r
20046                         var e = _previousElement(angular.element(elem).parent(), isFocusable);\r
20047                         if (_isTabable(e)) {\r
20048                             return e;\r
20049                         }\r
20050                     } else {\r
20051                         // I need to filter myself and any nodes next to me from the siblings\r
20052                         var indexOfElem = Array.prototype.indexOf.call(siblings, elem);\r
20053                         siblings = Array.prototype.filter.call(siblings, function(item, itemIndex) {\r
20054                             if (!angular.equals(elem, item) && itemIndex < indexOfElem) {\r
20055                                 return true;\r
20056                             }\r
20057                         });\r
20058                     }\r
20059                     // We need to search backwards\r
20060                     for (var i = 0; i <= siblings.length-1; i++) {//for (var i = siblings.length-1; i >= 0; i--) {\r
20061                         var ret = traverse(siblings[i], false);\r
20062                         if (ret !== undefined) {\r
20063                             return ret;\r
20064                         }\r
20065                     }\r
20066 \r
20067                     var e = _previousElement(angular.element(elem).parent(), isFocusable);\r
20068                     if (_isTabable(e)) {\r
20069                         return e;\r
20070                     }\r
20071                 }\r
20072             }\r
20073         } else {\r
20074             var siblings = angular.element(parent).children();\r
20075             if (siblings.length > 1) {\r
20076                 // Since indexOf is on Array.prototype and parent.children is a NodeList, we have to use call()\r
20077                 var index = Array.prototype.indexOf.call(siblings, elem);\r
20078                 previousElem = siblings[index-1];\r
20079             }\r
20080         }\r
20081         return previousElem;\r
20082     };\r
20083 \r
20084     var _lastTabableElement = function(el) {\r
20085         /* This will return the first tabable element from the parent el */\r
20086         var elem = el;\r
20087         if (el.hasOwnProperty('length')) {\r
20088             elem = el[0];\r
20089         }\r
20090 \r
20091         return traverse(elem, false);\r
20092     };\r
20093 \r
20094     var _firstTabableElement = function(el) {\r
20095         /* This will return the first tabable element from the parent el */\r
20096         var elem = el;\r
20097         if (el.hasOwnProperty('length')) {\r
20098             elem = el[0];\r
20099         }\r
20100 \r
20101         return traverse(elem, true);\r
20102     };\r
20103 \r
20104     var _isInDOM = function(obj) {\r
20105       return document.documentElement.contains(obj);\r
20106     }\r
20107 \r
20108     return {\r
20109         firstTabableElement: _firstTabableElement,\r
20110         lastTabableElement: _lastTabableElement,\r
20111         previousElement: _previousElement,\r
20112         isInDOM: _isInDOM,\r
20113         isTabable: _isTabable,\r
20114         isHidden: isHidden\r
20115     };\r
20116 })\r
20117 \r
20118 .factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', function ($document, $isElement, DOMHelper, keymap) {\r
20119     var elementStack = [];\r
20120     var stackHead = undefined;\r
20121     var trapFocusInElement = function (flag) {\r
20122         var bodyElements = $document.find('body').children();\r
20123 \r
20124         var firstTabableElement = angular.element(DOMHelper.firstTabableElement(stackHead));\r
20125         var lastTabableElement = angular.element(DOMHelper.lastTabableElement(stackHead));\r
20126 \r
20127         var trapKeyboardFocusInFirstElement = function (e) {\r
20128             if (!e.keyCode) {\r
20129                 e.keyCode = e.which;\r
20130             }\r
20131 \r
20132             if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {\r
20133                 lastTabableElement[0].focus();\r
20134                 e.preventDefault(e);\r
20135                 e.stopPropagation(e);\r
20136             }\r
20137 \r
20138         };\r
20139 \r
20140         var trapKeyboardFocusInLastElement = function (e) {\r
20141             if (!e.keyCode) {\r
20142                 e.keyCode = e.which;\r
20143             }\r
20144 \r
20145             if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {\r
20146                 firstTabableElement[0].focus();\r
20147                 e.preventDefault(e);\r
20148                 e.stopPropagation(e);\r
20149             }\r
20150         };\r
20151 \r
20152         if (flag) {\r
20153             for (var i = 0; i < bodyElements.length; i++) {\r
20154                 if (bodyElements[i] !== stackHead[0]) {\r
20155                     bodyElements.eq(i).attr('aria-hidden', true);\r
20156                 }\r
20157             }\r
20158             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);\r
20159             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);\r
20160         } else {\r
20161             for (var j = 0; j < bodyElements.length; j++) {\r
20162                 if (bodyElements[j] !== stackHead[0]) {\r
20163                     bodyElements.eq(j).removeAttr('aria-hidden');\r
20164                 }\r
20165             }\r
20166             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);\r
20167             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);\r
20168         }\r
20169     };\r
20170     var toggleTrapFocusInElement = function (flag, element) {\r
20171         if (angular.isDefined(flag) && angular.isDefined(element)) {\r
20172             if (angular.isUndefined(stackHead)) {\r
20173                 stackHead = element;\r
20174                 trapFocusInElement(flag);\r
20175             } else {\r
20176                 if (flag) {\r
20177                     trapFocusInElement(false);\r
20178                     elementStack.push(stackHead);\r
20179                     stackHead = element;\r
20180                     trapFocusInElement(true);\r
20181                 } else {\r
20182                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {\r
20183                         trapFocusInElement(false);\r
20184                         stackHead = elementStack.pop();\r
20185                         if (angular.isDefined(stackHead)) {\r
20186                             trapFocusInElement(true);\r
20187                         }\r
20188                     }\r
20189                 }\r
20190             }\r
20191         }\r
20192     };\r
20193 \r
20194     return toggleTrapFocusInElement;\r
20195 }])\r
20196 \r
20197 .factory('DOMHelper', function () {\r
20198 \r
20199     var _isTabable = function (node) {\r
20200         var element = angular.element(node);\r
20201         var tagName = element[0].tagName.toUpperCase();\r
20202 \r
20203         if (isHidden(element)) {\r
20204             return false;\r
20205         }\r
20206         if (element.attr('tabindex') !== undefined) {\r
20207             return (parseInt(element.attr('tabindex'), 10) >= 0);\r
20208         }\r
20209         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {\r
20210             if (tagName === 'A' || tagName === 'AREA') {\r
20211                 // anchors/areas without href are not focusable\r
20212                 return (element[0].href !== '');\r
20213             }\r
20214             return !(element[0].disabled || element[0].readOnly);\r
20215         }\r
20216         return false;\r
20217     };\r
20218 \r
20219     function isValidChild(child) {\r
20220         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';\r
20221     }\r
20222 \r
20223     function isHidden(obj) {\r
20224         var elem = angular.element(obj);\r
20225         var style;\r
20226         try {\r
20227             style = window.getComputedStyle(obj);\r
20228         }\r
20229         catch(err) {\r
20230             style = window.getComputedStyle(obj[0]);\r
20231         }\r
20232 \r
20233         // getComputedStyle() for Zepto object returns null\r
20234         if (style === null){\r
20235             return elem.hasClass('ng-hide') || elem.css('display') === 'none';\r
20236         }\r
20237 \r
20238         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || style.display === 'none' || style.display === 'hidden';\r
20239     }\r
20240 \r
20241     function traverse(obj, fromTop) {\r
20242         var obj = obj || document.getElementsByTagName('body')[0];\r
20243 \r
20244         if (isValidChild(obj) && _isTabable(obj)) {\r
20245             return obj;\r
20246         }\r
20247 \r
20248         // If object is hidden, skip it's children\r
20249         if (isValidChild(obj) && isHidden(obj)) {\r
20250             return undefined;\r
20251         }\r
20252         // If object is hidden, skip it's children\r
20253         if (angular.element(obj).hasClass('ng-hide')) {\r
20254             return undefined;\r
20255         }\r
20256 \r
20257         if (obj.hasChildNodes()) {\r
20258             var child;\r
20259             if (fromTop) {\r
20260                 child = obj.firstChild;\r
20261             } else {\r
20262                 child = obj.lastChild;\r
20263             }\r
20264             while (child) {\r
20265                 var res = traverse(child, fromTop);\r
20266                 if (res) {\r
20267                     return res;\r
20268                 } else {\r
20269                     if (fromTop) {\r
20270                         child = child.nextSibling;\r
20271                     } else {\r
20272                         child = child.previousSibling;\r
20273                     }\r
20274                 }\r
20275             }\r
20276         } else {\r
20277             return undefined;\r
20278         }\r
20279     }\r
20280 \r
20281     var _lastTabableElement = function (el) {\r
20282         /* This will return the last tabable element from the parent el */\r
20283         var elem = el;\r
20284         if (el.hasOwnProperty('length')) {\r
20285             elem = el[0];\r
20286         }\r
20287 \r
20288         return traverse(elem, false);\r
20289     };\r
20290 \r
20291     var _firstTabableElement = function (el) {\r
20292         /* This will return the first tabable element from the parent el */\r
20293         var elem = el;\r
20294         if (el.hasOwnProperty('length')) {\r
20295             elem = el[0];\r
20296         }\r
20297 \r
20298         return traverse(elem, true);\r
20299     };\r
20300 \r
20301     return {\r
20302         firstTabableElement: _firstTabableElement,\r
20303         lastTabableElement: _lastTabableElement,\r
20304         isTabable: _isTabable\r
20305     };\r
20306 })\r
20307 \r
20308 .factory('windowOrientation', ['$window', function ($window) {\r
20309     var _isPotrait = function () {\r
20310         if ($window.innerHeight > $window.innerWidth) {\r
20311             return true;\r
20312         } else {\r
20313             return false;\r
20314         }\r
20315     };\r
20316     var _isLandscape = function () {\r
20317         if ($window.innerHeight < $window.innerWidth) {\r
20318             return true;\r
20319         } else {\r
20320             return false;\r
20321         }\r
20322     };\r
20323 \r
20324     return {\r
20325         isPotrait: _isPotrait,\r
20326         isLandscape: _isLandscape\r
20327     };\r
20328 }])\r
20329 \r
20330 .directive('b2bNextElement', function() {\r
20331   return {\r
20332     restrict: 'A',\r
20333     transclude: false,\r
20334     link: function (scope, elem, attr, ctrls) {\r
20335 \r
20336         var keys = attr.b2bNextElement.split(',');\r
20337 \r
20338         elem.bind('keydown', function (e) {\r
20339             var nextElement = elem.next();\r
20340             if(e.keyCode == 39 || e.keyCode == 40){ // if e.keyCode in keys\r
20341                 if(nextElement.length) {\r
20342                     e.preventDefault();\r
20343                     nextElement[0].focus();\r
20344                 }\r
20345             }\r
20346         });\r
20347     }\r
20348   }\r
20349 })\r
20350 \r
20351 .directive('b2bAccessibilityClick', [function () {\r
20352     return {\r
20353         restrict: 'A',\r
20354         link: function (scope, elem, attr, ctrl) {\r
20355             var keyCode = [];\r
20356             attr.$observe('b2bAccessibilityClick', function (value) {\r
20357                 if (value) {\r
20358                     keyCode = value.split(',');\r
20359                 }\r
20360             });\r
20361             elem.bind('keydown keypress', function (ev) {\r
20362                 var keyCodeCondition = function () {\r
20363                     var flag = false;\r
20364                     if (!(ev.keyCode)) {\r
20365                         if (ev.which) {\r
20366                             ev.keyCode = ev.which; \r
20367                         } else if (ev.charCode) {\r
20368                             ev.keyCode = ev.charCode;\r
20369                         }\r
20370                     }\r
20371                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {\r
20372                         flag = true;\r
20373                     }\r
20374                     return flag;\r
20375                 };\r
20376                 if (keyCode.length > 0 && keyCodeCondition()) {\r
20377                     elem[0].click();\r
20378                     ev.preventDefault();\r
20379                 }\r
20380             });\r
20381         }\r
20382     };\r
20383 }])\r
20384 \r
20385 .directive('b2bReset', ['$compile', function ($compile) {\r
20386         return {\r
20387             restrict: 'A',\r
20388             require: ['?ngModel', 'b2bReset'],\r
20389             controller: ['$scope', function ($scope) {\r
20390                 var resetButton = angular.element('<button type="button" class="reset-field" tabindex="-1" aria-label="Click to reset" aria-hidden="true" role="button"></button>');\r
20391 \r
20392                 this.getResetButton = function () {\r
20393                     return resetButton;\r
20394                 };\r
20395             }],\r
20396             link: function (scope, element, attrs, ctrls) {\r
20397 \r
20398                 var ngModelCtrl = ctrls[0];\r
20399                 var ctrl = ctrls[1];\r
20400 \r
20401                 var resetButton = ctrl.getResetButton();\r
20402 \r
20403 \r
20404                 resetButton.on('click', function () {\r
20405                     element[0].value = '';\r
20406 \r
20407                     if (ngModelCtrl) {\r
20408                         if (attrs.b2bReset) {\r
20409                             ngModelCtrl.$setViewValue(attrs.b2bReset);\r
20410                         } else {\r
20411                             ngModelCtrl.$setViewValue('');\r
20412                         }\r
20413                         element[0].value = ngModelCtrl.$viewValue;\r
20414                         ngModelCtrl.$render();\r
20415                         scope.$digest();\r
20416                     }\r
20417                     element[0].focus();\r
20418                     element[0].select();\r
20419                 });\r
20420 \r
20421                 var addResetButton = function () {\r
20422                     element.after(resetButton);\r
20423                     element.unbind('focus input', addResetButton);\r
20424                 };\r
20425 \r
20426                 element.bind('focus input', addResetButton);\r
20427             }\r
20428         };\r
20429     }])\r
20430 \r
20431 .directive('b2bPrevElement', ['b2bDOMHelper', 'keymap', function (b2bDOMHelper, keymap) {\r
20432   return {\r
20433     restrict: 'A',\r
20434     transclude: false,\r
20435     link: function (scope, elem, attr) {\r
20436 \r
20437         elem.bind('keydown', function (e) {\r
20438             if(e.keyCode == 37 || e.keyCode == 38){\r
20439                 var prev = b2bDOMHelper.previousElement(elem, false);\r
20440                 if(prev !== undefined) {\r
20441                     e.preventDefault();\r
20442                     prev.focus();\r
20443                 }\r
20444             }\r
20445         });\r
20446     }\r
20447   }\r
20448 }])\r
20449 /**\r
20450  * @param {integer} delay - Timeout before first and last focusable elements are found\r
20451  * @param {boolean} trigger - A variable on scope that will trigger refinding first/last focusable elements \r
20452  */\r
20453 .directive('b2bTrapFocusInsideElement', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {\r
20454     return {\r
20455         restrict: 'A',\r
20456         transclude: false,\r
20457         link: function (scope, elem, attr) {\r
20458 \r
20459             var delay = parseInt(attr.delay, 10) || 10;\r
20460 \r
20461             /* Before opening modal, find the focused element */\r
20462             var firstTabableElement = undefined,\r
20463                 lastTabableElement = undefined;\r
20464                 \r
20465             function init() {\r
20466                 $timeout(function () {\r
20467                     firstTabableElement = b2bDOMHelper.firstTabableElement(elem);\r
20468                     lastTabableElement = b2bDOMHelper.lastTabableElement(elem);\r
20469                     angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);\r
20470                     angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);\r
20471                 }, delay, false);\r
20472             }\r
20473 \r
20474             if (attr.trigger !== undefined) {\r
20475                 scope.$watch('trigger', function() {\r
20476                     if (scope.trigger) {\r
20477                         init();\r
20478                     }\r
20479                 });\r
20480             }\r
20481 \r
20482             var firstTabableElementKeyhandler = function(e) {\r
20483                 if (!e.keyCode) {\r
20484                     e.keyCode = e.which;\r
20485                 }\r
20486                 if (e.keyCode === keymap.KEY.TAB && e.shiftKey) {\r
20487                     if (attr.trapFocusInsideElement === 'true') {\r
20488                         var temp = b2bDOMHelper.lastTabableElement(elem);\r
20489                         if (lastTabableElement !== temp) {\r
20490                             // Unbind keydown handler on lastTabableElement\r
20491                             angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);\r
20492                             lastTabableElement = temp;\r
20493                             angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);\r
20494                         }\r
20495                     }\r
20496                     lastTabableElement.focus();\r
20497                     events.preventDefault(e);\r
20498                     events.stopPropagation(e);\r
20499                 }\r
20500             };\r
20501 \r
20502             var lastTabableElementKeyhandler = function(e) {\r
20503                 if (!e.keyCode) {\r
20504                     e.keyCode = e.which;\r
20505                 }\r
20506                 if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {\r
20507                     if (attr.trapFocusInsideElement === 'true') {\r
20508                         var temp = b2bDOMHelper.firstTabableElement(elem);\r
20509                         if (firstTabableElement !== temp) {\r
20510                             // Unbind keydown handler on firstTabableElement\r
20511                             angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);\r
20512                             firstTabableElement = temp;\r
20513                             angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);\r
20514                         }\r
20515                     }\r
20516                     firstTabableElement.focus();\r
20517                     events.preventDefault(e);\r
20518                     events.stopPropagation(e);\r
20519                 }\r
20520             };\r
20521 \r
20522             init();\r
20523         }\r
20524     };\r
20525 }])\r
20526 \r
20527 .factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', '$interval', function ($document, $isElement, DOMHelper, keymap, $interval) {\r
20528     var elementStack = [];\r
20529     var stackHead = undefined;\r
20530     var stopInterval = undefined;\r
20531     var intervalRequired = false;\r
20532     var interval = 1000;\r
20533     var firstTabableElement, lastTabableElement;\r
20534 \r
20535     var trapKeyboardFocusInFirstElement = function (e) {\r
20536         if (!e.keyCode) {\r
20537             e.keyCode = e.which;\r
20538         }\r
20539 \r
20540         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {\r
20541             lastTabableElement[0].focus();\r
20542             e.preventDefault(e);\r
20543             e.stopPropagation(e);\r
20544         }\r
20545 \r
20546     };\r
20547 \r
20548     var trapKeyboardFocusInLastElement = function (e) {\r
20549         if (!e.keyCode) {\r
20550             e.keyCode = e.which;\r
20551         }\r
20552 \r
20553         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {\r
20554             firstTabableElement[0].focus();\r
20555             e.preventDefault(e);\r
20556             e.stopPropagation(e);\r
20557         }\r
20558     };\r
20559 \r
20560     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {\r
20561         var bodyElements = $document.find('body').children();\r
20562 \r
20563         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(DOMHelper.firstTabableElement(stackHead));\r
20564         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(DOMHelper.lastTabableElement(stackHead));\r
20565 \r
20566         if (flag) {\r
20567             for (var i = 0; i < bodyElements.length; i++) {\r
20568                 if (bodyElements[i] !== stackHead[0]) {\r
20569                     bodyElements.eq(i).attr('aria-hidden', true);\r
20570                 }\r
20571             }\r
20572             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);\r
20573             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);\r
20574         } else {\r
20575             for (var j = 0; j < bodyElements.length; j++) {\r
20576                 if (bodyElements[j] !== stackHead[0]) {\r
20577                     bodyElements.eq(j).removeAttr('aria-hidden');\r
20578                 }\r
20579             }\r
20580             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);\r
20581             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);\r
20582         }\r
20583 \r
20584         if (intervalRequired && flag) {\r
20585             stopInterval = $interval(function () {\r
20586                 var firstTabableElementTemp = angular.element(DOMHelper.firstTabableElement(stackHead));\r
20587                 var lastTabableElementTemp = angular.element(DOMHelper.lastTabableElement(stackHead));\r
20588                 if (firstTabableElementTemp[0] !== firstTabableElement[0] || lastTabableElementTemp[0] !== lastTabableElement[0]) {\r
20589                     $interval.cancel(stopInterval);\r
20590                     stopInterval = undefined;\r
20591                     trapFocusInElement(false, firstTabableElement, lastTabableElement);\r
20592                     trapFocusInElement(true, firstTabableElementTemp, lastTabableElementTemp);\r
20593                 }\r
20594             }, interval);\r
20595         } else {\r
20596             if (stopInterval) {\r
20597                 $interval.cancel(stopInterval);\r
20598                 stopInterval = undefined;\r
20599             }\r
20600         }\r
20601     };\r
20602     var toggleTrapFocusInElement = function (flag, element, intervalRequiredParam, intervalParam) {\r
20603         intervalRequired = intervalRequiredParam ? intervalRequiredParam : intervalRequired;\r
20604         interval = intervalParam ? intervalParam : interval;\r
20605         if (angular.isDefined(flag) && angular.isDefined(element)) {\r
20606             if (flag && angular.isUndefined(stackHead)) {\r
20607                 stackHead = element;\r
20608                 trapFocusInElement(flag);\r
20609             } else {\r
20610                 if (flag) {\r
20611                     trapFocusInElement(false);\r
20612                     elementStack.push(stackHead);\r
20613                     stackHead = element;\r
20614                     trapFocusInElement(true);\r
20615                 } else {\r
20616                     if (angular.isDefined(stackHead) && (stackHead[0] === element[0])) {\r
20617                         trapFocusInElement(false);\r
20618                         stackHead = elementStack.pop();\r
20619                         if (angular.isDefined(stackHead)) {\r
20620                             trapFocusInElement(true);\r
20621                         }\r
20622                     }\r
20623                 }\r
20624             }\r
20625         } else {\r
20626             if (angular.isDefined(stackHead)) {\r
20627                 trapFocusInElement(false, firstTabableElement, lastTabableElement);\r
20628                 trapFocusInElement(true);\r
20629             }\r
20630         }\r
20631     };\r
20632 \r
20633     return toggleTrapFocusInElement;\r
20634 }])\r
20635 \r
20636 .directive('b2bSetNextFocusOn', ['b2bDOMHelper', '$timeout', function(b2bDOMHelper, $timeout) {\r
20637     return {\r
20638         restrict: 'A',\r
20639         scope: true,\r
20640         link: function (scope, elem, attr) {\r
20641             elem.bind('click', function(){\r
20642                 var firstFocusableElement = undefined; \r
20643                 var containerElem = undefined; \r
20644                 var containerArray = [];\r
20645                 var timeout = parseInt(attr.setNextFocusTimeout, 0) | 100;\r
20646                 var index = parseInt(attr.b2bSetNextFocusIndex, 0) | 0;\r
20647 \r
20648                  /*\r
20649                   *Fix for IE7 and lower \r
20650                   *polyfill src: https://github.com/HubSpot/pace/issues/102\r
20651                   */\r
20652                 if (!document.querySelectorAll) {\r
20653                     document.querySelectorAll = function (selectors) {\r
20654                         var style = document.createElement('style'), elements = [], element;\r
20655                         document.documentElement.firstChild.appendChild(style);\r
20656                         document._qsa = [];\r
20657 \r
20658                         style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';\r
20659                         window.scrollBy(0, 0);\r
20660                         style.parentNode.removeChild(style);\r
20661 \r
20662                         while (document._qsa.length) {\r
20663                             element = document._qsa.shift();\r
20664                             element.style.removeAttribute('x-qsa');\r
20665                             elements.push(element);\r
20666                         }\r
20667                         document._qsa = null;\r
20668                         return elements;\r
20669                     };\r
20670                 }\r
20671 \r
20672                 if (attr.b2bSetNextFocusOn === '') {\r
20673                     return;\r
20674                 } else {\r
20675                     containerArray = attr.b2bSetNextFocusOn.split(' ');\r
20676                 }\r
20677                 $timeout(function(){\r
20678                     var i = 0;\r
20679                     do { // cycles thru containerArray until finds a match in DOM to set focus to\r
20680                         containerElem = document.querySelectorAll(containerArray[i])[index]; \r
20681                         i++;\r
20682                     } while ( (!containerElem) && (i < containerArray.length) );\r
20683                     if(containerElem){\r
20684                         if (!angular.isDefined(firstFocusableElement)) { \r
20685                             firstFocusableElement = b2bDOMHelper.firstTabableElement(containerElem); \r
20686                         }\r
20687                         firstFocusableElement.focus(); \r
20688                     }\r
20689                 }, timeout, false)\r
20690             });\r
20691         }\r
20692 \r
20693     };\r
20694 }])\r
20695 \r
20696 .directive('b2bInputAllow', [function() {\r
20697     return {\r
20698         restrict: 'A',\r
20699         require: 'ngModel',\r
20700         link: function (scope, elem, attr, ctrl) {\r
20701             var regexExpression = null;\r
20702             attr.$observe('b2bInputAllow', function (value) {\r
20703                 if (value) {\r
20704                     regexExpression = new RegExp(value);\r
20705                 }\r
20706             });\r
20707             var isValid = function(str) {\r
20708                 if (regexExpression !== null) {\r
20709                     return regexExpression.test(str);\r
20710                 }\r
20711                 return false;\r
20712             };\r
20713             elem.bind('keypress', function($event) {\r
20714                 var charcode = String.fromCharCode($event.which || $event.keyCode);\r
20715                 if (!isValid(charcode)) {\r
20716                     $event.preventDefault();\r
20717                     $event.stopPropagation();\r
20718                 }\r
20719             });\r
20720             elem.bind('input', function (evt) {\r
20721                 var inputString = ctrl.$viewValue;\r
20722                 if (isValid(inputString)) {\r
20723                     ctrl.$setViewValue(inputString);\r
20724                     ctrl.$render();\r
20725                     scope.$apply();\r
20726                 }\r
20727             });\r
20728         }\r
20729     };\r
20730 }])\r
20731 \r
20732 .directive('b2bInputDeny', [function() {\r
20733     return {\r
20734         restrict: 'A',\r
20735         require: 'ngModel',\r
20736         link: function (scope, elem, attr, ctrl) {\r
20737             var regexExpression = null;\r
20738             attr.$observe('b2bInputDeny', function (value) {\r
20739                 if (value) {\r
20740                     regexExpression = new RegExp(value, 'g');\r
20741                 }\r
20742             });\r
20743             elem.bind('input', function () {\r
20744                 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');\r
20745                 if (inputString !== ctrl.$viewValue) {\r
20746                     ctrl.$setViewValue(inputString);\r
20747                     ctrl.$render();\r
20748                     scope.$apply();\r
20749                 }\r
20750             });\r
20751         }\r
20752     };\r
20753 }])\r
20754 \r
20755 .directive('b2bDragonInput', [function() {\r
20756     return {\r
20757         restrict: 'A',\r
20758         require: 'ngModel',\r
20759         link: function (scope, elem, attr, ctrl) {\r
20760             elem.on('focus keyup', function(){\r
20761                 elem.triggerHandler('change');\r
20762             });\r
20763         }\r
20764     };\r
20765 }])\r
20766 \r
20767 .directive('b2bKey', ['b2bUtilitiesConfig', '$timeout', 'keymap', function (b2bUtilitiesConfig, $timeout, keymap) {\r
20768     return {\r
20769         restrict: 'EA',\r
20770         controller: ['$scope', '$element', '$attrs', function ($scope, $element,attr) {\r
20771             this.childElements = [];\r
20772             this.disableNodes = {};\r
20773             this.enableSearch = attr.enableSearch !== undefined ? true : b2bUtilitiesConfig.enableSearch;\r
20774             this.circularTraversal = attr.circularTraversal !== undefined ? true : b2bUtilitiesConfig.circularTraversal;\r
20775             this.counter = -1;\r
20776             if (this.enableSearch) {\r
20777                 this.searchKeys = [];\r
20778             }\r
20779             var searchString = '';\r
20780 \r
20781             var selfCtrl = this;\r
20782 \r
20783             this.childElementsList = [];\r
20784 \r
20785             this.b2bKeyID = "";\r
20786 \r
20787             if (angular.isDefined(attr.b2bKey)) {\r
20788                 this.b2bKeyID = attr.b2bKey;\r
20789             }\r
20790 \r
20791             this.calculateChildElementsList = function () {\r
20792                 return $element[0].querySelectorAll("[b2b-key-item='" + this.b2bKeyID + "']:not([disabled])");\r
20793             };\r
20794 \r
20795             this.resetChildElementsList = function () {\r
20796                 return $timeout(function () {\r
20797                     selfCtrl.childElementsList = selfCtrl.calculateChildElementsList();\r
20798                 });\r
20799             };\r
20800 \r
20801             this.resetChildElementsList();\r
20802 \r
20803             $scope.$on('b2b-key-reset-child-elements-list', function () {\r
20804                 selfCtrl.resetChildElementsList();\r
20805             });\r
20806 \r
20807 \r
20808             this.registerElement = function (childElement, searchKey) {\r
20809                 this.childElements.push(childElement);\r
20810                 if (this.enableSearch) {\r
20811                     this.searchKeys.push(searchKey);\r
20812                 }\r
20813                 var count = this.childElements.length - 1;\r
20814                 this.maxLength = count + 1;\r
20815                 return count;\r
20816             };\r
20817             this.toggleDisable = function (count, state) {\r
20818                 this.disableNodes[count] = state;\r
20819             };\r
20820             this.searchElement = function (searchExp) {\r
20821                 var regex = new RegExp("\\b" + searchExp, "gi");\r
20822                 var position = this.searchKeys.regexIndexOf(regex, this.counter + 1, true);\r
20823                 if (position > -1) {\r
20824                     this.counter = position;\r
20825                     this.moveFocus(this.counter);\r
20826                 }\r
20827             };\r
20828             this.startTimer = function (time) {\r
20829                 if (searchString === '') {\r
20830                     $timeout(function () {\r
20831                         searchString = '';\r
20832                     }, time);\r
20833                 }\r
20834             };\r
20835             this.resetCounter = function (count) {\r
20836                 this.counter = count;\r
20837             };\r
20838             this.moveNext = function (count) {\r
20839                 this.counter = (this.counter + count) < this.maxLength ? this.counter + count : (this.circularTraversal ? 0 : this.counter);\r
20840                 if (this.disableNodes[this.counter]) {\r
20841                     if ((this.counter + count) < this.maxLength) {\r
20842                         this.moveNext(count);\r
20843                     }\r
20844                 } else {\r
20845                     this.moveFocus(this.counter);\r
20846                 }\r
20847             };\r
20848             this.movePrev = function (count) {\r
20849                 this.counter = (this.counter - count) > -1 ? this.counter - count : (this.circularTraversal ? this.maxLength-1 : this.counter);\r
20850                 if (this.disableNodes[this.counter]) {\r
20851                     if ((this.counter - count) > -1) {\r
20852                         this.movePrev(count);\r
20853                     }\r
20854                 } else {\r
20855                     this.moveFocus(this.counter);\r
20856                 }\r
20857             };\r
20858             this.moveFocus = function (index) {\r
20859                 this.childElements[index][0].focus();\r
20860             };\r
20861 \r
20862             this.keyDownHandler = function (ev, count) {\r
20863                 if (angular.isDefined(count) && !isNaN(count) && count !== this.counter) {\r
20864                     this.resetCounter(count);\r
20865                 }\r
20866                 if (!ev.keyCode) {\r
20867                     if (ev.which) {\r
20868                         ev.keyCode = ev.which;\r
20869                     } else if (ev.charCode) {\r
20870                         ev.keyCode = ev.charCode;\r
20871                     }\r
20872                 }\r
20873                 if (ev.keyCode) {\r
20874                     if (this.prev && this.prev.indexOf(ev.keyCode.toString()) > -1) {\r
20875                         this.movePrev(1);\r
20876                         ev.preventDefault();\r
20877                         ev.stopPropagation();\r
20878                     } else if (this.next && this.next.indexOf(ev.keyCode.toString()) > -1) {\r
20879                         this.moveNext(1);\r
20880                         ev.preventDefault();\r
20881                         ev.stopPropagation();\r
20882                     } else if (this.up && this.up.indexOf(ev.keyCode.toString()) > -1) {\r
20883                         if (this.type === 'table') {\r
20884                             this.movePrev(this.columns);\r
20885                             ev.preventDefault();\r
20886                             ev.stopPropagation();\r
20887                         }\r
20888                     } else if (this.down && this.down.indexOf(ev.keyCode.toString()) > -1) {\r
20889                         if (this.type === 'table') {\r
20890                             this.moveNext(this.columns);\r
20891                             ev.preventDefault();\r
20892                             ev.stopPropagation();\r
20893                         }\r
20894                     } else if (ev.keyCode === keymap.KEY.HOME) {\r
20895                         var firstIndex = 0;\r
20896                         while (this.disableNodes[firstIndex] !== false) {\r
20897                             firstIndex++;\r
20898                         };\r
20899                         var count = this.counter - firstIndex;\r
20900                         this.movePrev(count);\r
20901                         ev.preventDefault();\r
20902                         ev.stopPropagation();\r
20903                     } else if (ev.keyCode === keymap.KEY.END) {\r
20904                         var lastIndex = this.childElements.length - 1;\r
20905                         while (this.disableNodes[lastIndex] !== false) {\r
20906                             lastIndex--;\r
20907                         };\r
20908                         var count = lastIndex - this.counter;\r
20909                         this.moveNext(count);\r
20910                         ev.preventDefault();\r
20911                         ev.stopPropagation();\r
20912                     } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {\r
20913                         if (this.enableSearch) {\r
20914                             this.startTimer(b2bUtilitiesConfig.searchTimer);\r
20915                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');\r
20916                             this.searchElement(searchString);\r
20917                             ev.preventDefault();\r
20918                             ev.stopPropagation();\r
20919                         }\r
20920                     }\r
20921                 }\r
20922             };\r
20923         }],\r
20924         link: function (scope, elem, attr, ctrl) {\r
20925             ctrl.prev = attr.prev ? attr.prev.split(',') : b2bUtilitiesConfig.prev.split(',');\r
20926             ctrl.next = attr.next ? attr.next.split(',') : b2bUtilitiesConfig.next.split(',');\r
20927             ctrl.type = attr.type ? attr.type : b2bUtilitiesConfig.type;\r
20928             if (ctrl.type === 'table') {\r
20929                 ctrl.up = attr.up ? attr.up.split(',') : b2bUtilitiesConfig.up.split(',');\r
20930                 ctrl.down = attr.down ? attr.down.split(',') : b2bUtilitiesConfig.down.split(',');\r
20931                 ctrl.columns = attr.columns ? parseInt(attr.columns, 10) : b2bUtilitiesConfig.columns;\r
20932             }\r
20933 \r
20934             elem.bind('keydown', function (ev) {\r
20935                 ctrl.keyDownHandler(ev);\r
20936             });\r
20937         }\r
20938     };\r
20939 }])\r
20940 \r
20941 .directive('b2bKeyItem', [function () {\r
20942     return {\r
20943         restrict: 'EA',\r
20944         link: function (scope, elem, attr, ctrl) {\r
20945             var parentCtrl = (elem.parent() && elem.parent().controller('b2bKey')) || undefined;\r
20946             if (angular.isDefined(parentCtrl)) {\r
20947                 var count = parentCtrl.registerElement(elem, attr.searchKey);\r
20948                 elem.bind('keydown', function (ev) {\r
20949                     parentCtrl.keyDownHandler(ev, count);\r
20950                 });\r
20951                 scope.$watch(attr.b2bKeyItem, function (value) {\r
20952                     value = value === undefined ? true : value;\r
20953                     parentCtrl.toggleDisable(count, !value); \r
20954                 });\r
20955                 scope.$on('$destroy', function () {\r
20956                     parentCtrl.toggleDisable(count, true);\r
20957                 });\r
20958             }\r
20959         }\r
20960     };\r
20961 }])\r
20962 \r
20963 .directive('b2bElementFocus', [function () {\r
20964     return {\r
20965         restrict: 'A',\r
20966         link: function (scope, elem, attr, ctrl) {\r
20967             scope.$watch(attr.b2bElementFocus, function (value) {\r
20968                 if (value === true) {\r
20969                     elem[0].focus();\r
20970                 }\r
20971             });\r
20972         }\r
20973     };\r
20974 }])\r
20975 \r
20976 \r
20977 .directive('b2bAppendElement', ['$compile', function ($compile) {\r
20978     return {\r
20979         restrict: 'A',\r
20980         link: function (scope, elem, attr, ctrl) {\r
20981             var parameters = attr.b2bAppendElement.split(':');\r
20982             if (parameters.length === 1) {\r
20983                 elem.append(scope.$eval(parameters[0]));\r
20984             } else if (parameters.length === 2) {\r
20985                 if (parameters[1] === 'compile') {\r
20986                     var element = angular.element('<span>' + scope.$eval(parameters[0]) + '</span>');\r
20987                     elem.append($compile(element)(scope));\r
20988                 }\r
20989             }\r
20990 \r
20991         }\r
20992     };\r
20993 }])\r
20994 \r
20995 .directive('b2bKeyItemRefreshInNgRepeat', [function () {\r
20996     return {\r
20997         restrict: 'EA',\r
20998         require: '^^b2bKey',\r
20999         link: function (scope, elem, attr, parentCtrl) {\r
21000             if (angular.isDefined(parentCtrl)) {\r
21001 \r
21002                 var attrToObserve = 'attrToObserve';\r
21003 \r
21004                 if (attr.b2bKeyItemRefreshInNgRepeat) {\r
21005                     attrToObserve = 'b2bKeyItemRefreshInNgRepeat';\r
21006                 }\r
21007 \r
21008                 attr.$observe(attrToObserve, function (newVal, oldVal) {\r
21009                     if (newVal && newVal !== oldVal) {\r
21010                         parentCtrl.resetChildElementsList();\r
21011                     }\r
21012                 });\r
21013             }\r
21014         }\r
21015     };\r
21016 }])\r
21017 \r
21018 .filter('b2bMultiSepartorHighlight', function($sce) {\r
21019         return function(text, searchText, searchSeperator) {\r
21020             var splitText = function(string) {\r
21021                 if(angular.isDefined(searchSeperator)){\r
21022                     if (string.indexOf(searchSeperator) > -1) {\r
21023                         return string.split(searchSeperator);\r
21024                     } else {\r
21025                         return string\r
21026                     }\r
21027                 }else{\r
21028                     return string;\r
21029                 }\r
21030             }\r
21031             if (text) {\r
21032                 var newText = splitText(text);\r
21033                 var newPhrase = splitText(searchText);\r
21034                 if (angular.isArray(newPhrase)) {\r
21035                     for (var i = 0; i < newText.length; i++) {\r
21036                         if (i <= 0) {\r
21037                             text = newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),\r
21038                                 '<span class="b2b-search-hightlight">$1</span>');\r
21039                         } else {\r
21040                             text = text + searchSeperator + ' ' + (newPhrase[i] ? newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),\r
21041                                 '<span class="b2b-search-hightlight">$1</span>') : newText[i]);\r
21042                         }\r
21043                     }\r
21044                 } else {\r
21045                     text = text.replace(new RegExp('(' + searchText + ')', 'gi'),\r
21046                         '<span class="b2b-search-hightlight">$1</span>');\r
21047                 }\r
21048             }\r
21049             return $sce.trustAsHtml(text)\r
21050         }\r
21051     })\r
21052     \r
21053     .factory('b2bUserAgent', [function() {\r
21054         var _isMobile = function() {\r
21055             return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\r
21056         };\r
21057         var _notMobile = function() {\r
21058             return !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\r
21059         };\r
21060         var _isIE = function() {\r
21061             return /msie|trident/i.test(navigator.userAgent);\r
21062         };\r
21063         var _isFF = function() {\r
21064             return /Firefox/.test(navigator.userAgent);\r
21065         };\r
21066         var _isChrome = function() {\r
21067             return /Google Inc/.test(navigator.vendor);\r
21068         };\r
21069         var _isSafari = function() {\r
21070             return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);\r
21071         };\r
21072 \r
21073         return {\r
21074             isMobile: _isMobile,\r
21075             notMobile: _notMobile,\r
21076             isIE: _isIE,\r
21077             isFF: _isFF,\r
21078             isChrome: _isChrome,\r
21079             isSafari: _isSafari\r
21080         };\r
21081     }])\r
21082     .run(['$document', 'b2bUserAgent', function($document, b2bUserAgent) {\r
21083         var html = $document.find('html').eq(0);\r
21084         if (b2bUserAgent.isIE()) {\r
21085             html.addClass('isIE');\r
21086         } else {\r
21087             html.removeClass('isIE');\r
21088         }\r
21089     }]);\r
21090     \r
21091 \r
21092 (function () {\r
21093     String.prototype.toSnakeCase = function () {\r
21094         return this.replace(/([A-Z])/g, function ($1) {\r
21095             return "-" + $1.toLowerCase();\r
21096         });\r
21097     };\r
21098     var concat = function (character, times) {\r
21099         character = character || '';\r
21100         times = (!isNaN(times) && times) || 0;\r
21101         var finalChar = '';\r
21102         for (var i = 0; i < times; i++) {\r
21103             finalChar += character;\r
21104         }\r
21105         return finalChar;\r
21106     };\r
21107 \r
21108     // direction: true for left and false for right\r
21109     var pad = function (actualString, width, character, direction) {\r
21110         actualString = actualString || '';\r
21111         width = (!isNaN(width) && width) || 0;\r
21112         character = character || '';\r
21113         if (width > actualString.length) {\r
21114             if (direction) {\r
21115                 return concat(character, (width - actualString.length)) + actualString;\r
21116             } else {\r
21117                 return actualString + concat(character, (width - actualString.length));\r
21118             }\r
21119         }\r
21120         return actualString;\r
21121     };\r
21122 \r
21123     String.prototype.lPad = function (width, character) {\r
21124         return pad(this, width, character, true);\r
21125     };\r
21126 \r
21127     String.prototype.rPad = function (width, character) {\r
21128         return pad(this, width, character, false);\r
21129     };\r
21130 \r
21131     if (!Array.prototype.indexOf) {\r
21132         Array.prototype.indexOf = function (val) {\r
21133             for (var index = 0; index < this.length; index++) {\r
21134                 if (this[index] === val) {\r
21135                     return index;\r
21136                 }\r
21137             }\r
21138             return -1;\r
21139         };\r
21140     }\r
21141 \r
21142     if (!Array.prototype.regexIndexOf) {\r
21143         Object.defineProperty(Array.prototype, 'regexIndexOf', {\r
21144             enumerable: false,\r
21145             value: function (regex, startIndex, loop) {\r
21146                 startIndex = startIndex && startIndex > -1 ? startIndex : 0;\r
21147                 for (var index = startIndex; index < this.length; index++) {\r
21148                     if (this[index].toString().match(regex)) {\r
21149                         return index;\r
21150                     }\r
21151                 }\r
21152                 if (loop) {\r
21153                     for (var index = 0; index < startIndex; index++) {\r
21154                         if (this[index].toString().match(regex)) {\r
21155                             return index;\r
21156                         }\r
21157                     }\r
21158                 }\r
21159                 return -1;\r
21160             }\r
21161         })\r
21162     }\r
21163 })();\r
21164 angular.module("b2bTemplate/audioPlayer/audioPlayer.html", []).run(["$templateCache", function($templateCache) {\r
21165   $templateCache.put("b2bTemplate/audioPlayer/audioPlayer.html",\r
21166     "<div class=\"b2b-audio\">\n" +\r
21167     "   <audio preload=\"auto\">\n" +\r
21168     "       <source ng-src=\"{{audio.mp3 | trustedAudioUrl}}\" type=\"audio/mp3\"></source>\n" +\r
21169     "       <i>Your browser does not support the audio element.</i>\n" +\r
21170     "    </audio>\n" +\r
21171     "\n" +\r
21172     "    <div audio-play-pause-icon class=\"controls-wrapper\" ng-click=\"toggleAudio()\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" role=\"button\" aria-label=\"{{isPlayInProgress?'pause':'play'}}\">\n" +\r
21173     "       <i class=\"icoControls-pointer\" ng-show='!isPlayInProgress'></i>\n" +\r
21174     "       <i class=\"icoControls-pause\" ng-show='isPlayInProgress'></i>\n" +\r
21175     "    </div>\n" +\r
21176     "\n" +\r
21177     "    <div class=\"seek-bar-container-wrapper\">\n" +\r
21178     "       <b2b-seek-bar min=\"0\" max=\"{{audio.duration}}\" step=\"1\" skip-interval=\"{{audio.timeShiftInSeconds}}\" no-aria-label ng-model=\"audio.currentTime\" on-drag-init=\"isAudioDragging=true\" on-drag-end=\"setAudioPosition(audio.currentTime)\"></b2b-seek-bar>\n" +\r
21179     "       <div class=\"timing-container\">\n" +\r
21180     "           <span class=\"timing-container-left\">{{timeFormatter(audio.currentTime)}}</span>\n" +\r
21181     "           <span class=\"timing-container-right\">{{timeFormatter(audio.duration)}}</span>\n" +\r
21182     "           <div class=\"timing-container-spacer\"></div>\n" +\r
21183     "       </div>\n" +\r
21184     "    </div>\n" +\r
21185     "       \n" +\r
21186     "    <b2b-flyout>\n" +\r
21187     "       <div tabindex=\"0\" b2b-accessibility-click=\"13,32\" role=\"button\" aria-label=\"Volume pop-over. Volume set at {{audio.currentVolume}}%\" class=\"controls-wrapper audio-volume-control\" b2b-flyout-toggler>\n" +\r
21188     "           <i class=\"icoControls-mutespeakers\" ng-show=\"audio.currentVolume === 0\"></i>\n" +\r
21189     "           <i class=\"icoControls-volumedown\" ng-show=\"audio.currentVolume > 0 && audio.currentVolume <= 50\"></i>\n" +\r
21190     "           <i class=\"icoControls-volumeup\" ng-show=\"audio.currentVolume > 50\"></i>\n" +\r
21191     "       </div> \n" +\r
21192     "       \n" +\r
21193     "       <b2b-flyout-content horizontal-placement=\"center\" flyout-style=\"width:70px; height:190px;\" vertical-placement=\"above\">\n" +\r
21194     "           <div class=\"b2b-audio-popover text-center\">\n" +\r
21195     "               <span>Max</span>\n" +\r
21196     "               <b2b-seek-bar min=\"0\" max=\"100\" step=\"1\" skip-interval=\"10\" vertical data-ng-model=\"audio.currentVolume\" class='volume-popover'></b2b-seek-bar>\n" +\r
21197     "               <div class=\"min-label\">Min</div>\n" +\r
21198     "           </div>\n" +\r
21199     "       </b2b-flyout-content>\n" +\r
21200     "   </b2b-flyout>\n" +\r
21201     "</div>");\r
21202 }]);\r
21203 \r
21204 angular.module("b2bTemplate/audioRecorder/audioRecorder.html", []).run(["$templateCache", function($templateCache) {\r
21205   $templateCache.put("b2bTemplate/audioRecorder/audioRecorder.html",\r
21206     "<div class=\"b2b-audio-recorder row\">\n" +\r
21207     "   <div class=\"b2b-elapsed-time span11\">\n" +\r
21208     "       <div ng-if=\"isRecording\">\n" +\r
21209     "           <span style=\"padding-right: 25px;\">{{config.whileRecordingMessage}}</span>\n" +\r
21210     "           <span>{{timeFormatter(elapsedTime)}}</span>\n" +\r
21211     "       </div>\n" +\r
21212     "       <span ng-if=\"!isRecording\">{{config.startRecordingMessage}}</span>\n" +\r
21213     "   </div>      \n" +\r
21214     "   <div class=\"b2b-controls\" title=\"{{isRecording ? 'Stop' : 'REC'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"toggleRecording()\" role=\"button\">\n" +\r
21215     "           <i ng-if=\"isRecording\" class=\"icoControls-stop\" ></i>\n" +\r
21216     "           <i ng-if=\"!isRecording\" class=\"icoControls-record\"></i>\n" +\r
21217     "    </div>\n" +\r
21218     "</div>");\r
21219 }]);\r
21220 \r
21221 angular.module("b2bTemplate/backToTop/backToTop.html", []).run(["$templateCache", function($templateCache) {\r
21222   $templateCache.put("b2bTemplate/backToTop/backToTop.html",\r
21223     "<button class=\"btn-arrow b2b-backtotop-button\" type=\"button\" aria-label=\"Back to top\">\n" +\r
21224     "    <div class=\"btn-secondary b2b-top-btn\">\n" +\r
21225     "        <i class=\"icoControls-upPRIMARY\" role=\"img\"></i>\n" +\r
21226     "    </div>\n" +\r
21227     "</button>\n" +\r
21228     "");\r
21229 }]);\r
21230 \r
21231 angular.module("b2bTemplate/boardstrip/b2bAddBoard.html", []).run(["$templateCache", function($templateCache) {\r
21232   $templateCache.put("b2bTemplate/boardstrip/b2bAddBoard.html",\r
21233     "<div tabindex=\"0\" role=\"menuitem\" b2b-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +\r
21234     "    <div class=\"centered\"><i aria-hidden=\"true\" class=\"icoControls-add-maximize\"></i> Add board</div>\n" +\r
21235     "</div> ");\r
21236 }]);\r
21237 \r
21238 angular.module("b2bTemplate/boardstrip/b2bBoard.html", []).run(["$templateCache", function($templateCache) {\r
21239   $templateCache.put("b2bTemplate/boardstrip/b2bBoard.html",\r
21240     "<li b2b-board-navigation tabindex=\"-1\" role=\"menuitem\" aria-label=\"{{boardLabel}} {{getCurrentIndex()===boardIndex?'selected':''}}\" b2b-accessibility-click=\"13,32\" ng-click=\"selectBoard(boardIndex)\" class=\"board-item\" ng-class=\"{'selected': getCurrentIndex()===boardIndex}\">\n" +\r
21241     "    <div ng-transclude></div>\n" +\r
21242     "    <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +\r
21243     "        <div class=\"board-caret-indicator\"></div>\n" +\r
21244     "        <div class=\"board-caret-arrow-up\"></div>\n" +\r
21245     "    </div>\n" +\r
21246     "</li>");\r
21247 }]);\r
21248 \r
21249 angular.module("b2bTemplate/boardstrip/b2bBoardstrip.html", []).run(["$templateCache", function($templateCache) {\r
21250   $templateCache.put("b2bTemplate/boardstrip/b2bBoardstrip.html",\r
21251     "<div class=\"b2b-boardstrip\">\n" +\r
21252     "   <div class=\"boardstrip-reel\" role=\"menu\">\n" +\r
21253     "       <div class=\"prev-items\">\n" +\r
21254     "           <!-- <i tabindex=\"{{isPrevBoard() ? 0 : -1}}\" ng-class=\"{'disabled': !isPrevBoard()}\" role=\"menuitem\" aria-label=\"See previous boards\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" class=\"arrow icoControls-left\"></i> -->\n" +\r
21255     "           <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" ng-disabled=\"!isPrevBoard()\">\n" +\r
21256     "               <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-left\"></i>\n" +\r
21257     "               </div>\n" +\r
21258     "               <span class=\"offscreen-text\">Previous boards</span>\n" +\r
21259     "           </button>\n" +\r
21260     "       </div>\n" +\r
21261     "       <div b2b-add-board on-add-board=\"onAddBoard()\"></div>\n" +\r
21262     "       <div class=\"board-viewport\"><ul role=\"menu\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +\r
21263     "       <div class=\"next-items\">\n" +\r
21264     "           <!-- <i tabindex=\"{{isNextBoard() ? 0 : -1}}\" ng-class=\"{'disabled': !isNextBoard()}\" role=\"menuitem\" aria-label=\"See next boards\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" class=\"arrow icoControls-right\"></i> -->\n" +\r
21265     "           <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" ng-disabled=\"!isNextBoard()\">\n" +\r
21266     "               <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-right\"></i>\n" +\r
21267     "               </div>\n" +\r
21268     "               <span class=\"offscreen-text\">Next boards</span>\n" +\r
21269     "           </button>\n" +\r
21270     "       </div>\n" +\r
21271     "   </div>\n" +\r
21272     "</div>\n" +\r
21273     "");\r
21274 }]);\r
21275 \r
21276 angular.module("b2bTemplate/calendar/datepicker-popup.html", []).run(["$templateCache", function($templateCache) {\r
21277   $templateCache.put("b2bTemplate/calendar/datepicker-popup.html",\r
21278     "<div id=\"datepicker\" class=\"datepicker dropdown-menu\" ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" style=\"display: block;\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\" b2b-key type=\"table\" columns=\"7\">\n" +\r
21279     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +\r
21280     "        <div ng-repeat=\"header in headers\" class=\"text-left\" style=\"width: 100%;\" b2b-append-element=\"header\"></div>\n" +\r
21281     "        <table class=\"table-condensed\">\n" +\r
21282     "            <thead>\n" +\r
21283     "                <tr>\n" +\r
21284     "                    <th id=\"prev\" class=\"prev\" tabindex=\"0\" b2b-accessibility-click=\"13\" aria-label=\"Previous Month\" role=\"button\" b2b-element-focus=\"!disablePrev && getFocus\" ng-style=\"{visibility: visibilityPrev}\" ng-click=\"!disablePrev && move(-1,$event)\"><i class=\"icon-primary-left\" aria-hidden=\"true\"></i></th>\n" +\r
21285     "                    <th id=\"month\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +\r
21286     "                    <th id=\"next\" class=\"next\" tabindex=\"0\" b2b-accessibility-click=\"13\" b2b-element-focus=\"disablePrev && getFocus\" aria-label=\"Next Month\" role=\"button\" ng-style=\"{visibility: visibilityNext}\" ng-click=\"!disableNext && move(1,$event)\"><i class=\"icon-primary-right\" aria-hidden=\"true\"></i></th>\n" +\r
21287     "                </tr>\n" +\r
21288     "                <tr ng-show=\"labels.length > 0\">\n" +\r
21289     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +\r
21290     "                </tr>\n" +\r
21291     "            </thead>\n" +\r
21292     "            <tbody>\n" +\r
21293     "                <tr ng-repeat=\"row in rows\">\n" +\r
21294     "                    <td headers=\"{{dt.header}}\" b2b-key-item=\"dt.focusable\" b2b-accessibility-click=\"13\" b2b-element-focus=\"disablePrev && disableNext && getFocus && (dt.selected || dt.firstFocus || dt.fromDate || dt.dateRange)\" tabindex=\"{{(!(dt.focusable && (dt.selected || dt.firstFocus || dt.fromDate || currFocus)) && -1) || 0}}\" aria-hidden=\"{{(!dt.focusable && true) || false}}\" role=\"{{(dt.focusable && 'gridcell') || ''}}\" aria-label=\"{{(dt.focusable && dt.date | date : 'EEEE, MMMM d') || ''}}\" aria-selected=\"{{(dt.focusable && (dt.selected || dt.dateRange) && true) || false}}\" ng-repeat=\"dt in row\" class=\"day magic\" ng-class=\"{'active': dt.focusable && dt.selected && !dt.dateRange, 'start-date': dt.focusable && dt.fromDate && dt.dateRange, 'between-date': dt.focusable && !dt.fromDate && !dt.selected && dt.dateRange, 'end-date': dt.focusable && dt.selected && dt.dateRange, 'old': dt.oldMonth, 'new': dt.nextMonth, 'disabled': dt.disabled, 'due-date': dt.dueDate, 'late-fee': dt.pastDue}\" ng-focus=\"currFocus=true; trapFocus();\" ng-blur=\"currFocus=false; trapFocus();\" title=\"{{(dt.focusable && dt.pastDue && legendMessage) || ''}}\" ng-click=\"!ngDisabled && !dt.disabled && select(dt.date)\">\n" +\r
21295     "                        <div aria-hidden=\"true\" tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label}}</div>{{(dt.focusable && dt.date | date : 'EEEE, MMMM d yyyy') || ''}}{{(dt.focusable && dt.dueDate && '. Bill-due-date.. ') || ''}}{{(dt.focusable && dt.pastDue && legendMessage) || ''}}</td>\n" +\r
21296     "                </tr>\n" +\r
21297     "            </tbody>\n" +\r
21298     "            <tfoot>\n" +\r
21299     "                <tr ng-repeat=\"footer in footers\">\n" +\r
21300     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"footer\"></th>\n" +\r
21301     "                </tr>\n" +\r
21302     "            </tfoot>\n" +\r
21303     "        </table>\n" +\r
21304     "    </div>\n" +\r
21305     "</div>");\r
21306 }]);\r
21307 \r
21308 angular.module("b2bTemplate/calendar/datepicker.html", []).run(["$templateCache", function($templateCache) {\r
21309   $templateCache.put("b2bTemplate/calendar/datepicker.html",\r
21310     "<div>\n" +\r
21311     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +\r
21312     "</div>");\r
21313 }]);\r
21314 \r
21315 angular.module("b2bTemplate/coachmark/coachmark.html", []).run(["$templateCache", function($templateCache) {\r
21316   $templateCache.put("b2bTemplate/coachmark/coachmark.html",\r
21317     "<div class=\"b2b-coachmark-container\" tabindex=\"-1\" role=\"dialog\" aria-label=\"{{currentCoachmark.contentHeader}} {{currentCoachmark.content}} {{currentCoachmark.offscreenText}}\" ng-style=\"{'top':coackmarkElPos.top,'left':coackmarkElPos.left}\" aria-describeby=\"{{currentCoachmark}}\">\n" +\r
21318     "   <i class=\"b2b-coachmark-caret\"></i>\n" +\r
21319     "   <div class=\"b2b-coachmark-header\">\n" +\r
21320     "       <div class=\"b2b-coachmark-countlabel\"><span ng-if=\"coachmarkIndex !== 0\">{{coachmarkIndex}} of {{(coachmarks.length-1)}}<span></div>\n" +\r
21321     "       <div class=\"corner-button\">\n" +\r
21322     "           <button type=\"button\" ng-focus=\"closeButtonFocus()\" class=\"close\" title=\"close\" aria-label=\"Close\" ng-click=\"closeCoachmark()\"></button>\n" +\r
21323     "       </div>\n" +\r
21324     "   </div>\n" +\r
21325     "   <div class=\"b2b-coachmark-content\">   \n" +\r
21326     "       <i class=\"icon-misc-dimmer\"></i>\n" +\r
21327     "       <div class=\"b2b-coachmark-content-header\"><span class=\"offscreen-text\">{{currentCoachmark.offscreenText}}</span>{{currentCoachmark.contentHeader}}</div>\n" +\r
21328     "       <div class=\"b2b-coachmark-description\">{{currentCoachmark.content}}</div>\n" +\r
21329     "       <div class=\"b2b-coachmark-btn-group\">\n" +\r
21330     "           <a class=\"b2b-coachmark-link\" href=\"javascript:void(0)\" ng-if=\"currentCoachmark.linkLabel !== '' && currentCoachmark.linkLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.linkLabel)\">{{currentCoachmark.linkLabel}}</a>\n" +\r
21331     "           <button class=\"btn btn-alt\" ng-if=\"currentCoachmark.buttonLabel !== '' && currentCoachmark.buttonLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.buttonLabel)\">{{currentCoachmark.buttonLabel}}</button>\n" +\r
21332     "       </div>  \n" +\r
21333     "   </div>  \n" +\r
21334     "</div>");\r
21335 }]);\r
21336 \r
21337 angular.module("b2bTemplate/dropdowns/b2bDropdownDesktop.html", []).run(["$templateCache", function($templateCache) {\r
21338   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownDesktop.html",\r
21339     "<span b2b-key prev=\"38\" next=\"40\" enable-search ng-class=\"{'large': (dropdownSize === 'large'), 'disabled': (disabled), 'selectWrap': (isInputDropdown), 'selectorModule': (dropdownType === 'menu'), 'linkSelectorModule': (dropdownType === 'link-menu')}\">\n" +\r
21340     "    <input b2b-dropdown-toggle b2b-dropdown-validation ng-disabled=\"disabled\" type=\"text\" id=\"{{dropdownId}}\" name=\"{{dropdownName}}\" class=\"awd-select isWrapped\" ng-required=\"dropdownRequired\" ng-model=\"currentSelected.text\" role=\"combobox\" aria-owns=\"listbox{{$id}}\" aria-expanded=\"{{toggleFlag}}\" ng-click=\"toggleDropdown()\" ng-focus=\"focused=true\" ng-blur=\"setBlur(); focused=false\" ng-class=\"{'active': toggleFlag, 'closed': !toggleFlag, 'large': (dropdownSize === 'large'), 'focused':focused}\" style=\"width:100%;\" value=\"{{currentSelected.text}}\" ng-show=\"isInputDropdown\" aria-describedby=\"{{dropdownDescribedBy}}\" readonly=\"readonly\">\n" +\r
21341     "    <button type=\"button\" b2b-dropdown-toggle ng-disabled=\"disabled\" class=\"selectModule\" aria-label=\"{{labelText}} {{currentSelected.label}}\" aria-expanded=\"{{toggleFlag}}\" aria-haspopup=\"true\" ng-click=\"toggleDropdown()\" ng-blur=\"setBlur()\" ng-class=\"{'active opened': toggleFlag, 'closed': !toggleFlag, 'large': (dropdownSize === 'large')}\" ng-bind-html=\"currentSelected.text\" ng-show=\"!isInputDropdown\"></button>\n" +\r
21342     "    <div ng-class=\"{'selectWrapper': (isInputDropdown), 'moduleWrapper': (!isInputDropdown)}\">\n" +\r
21343     "        <ul id=\"listbox{{$id}}\" role=\"{{isInputDropdown?'listbox':'menu'}}\" ng-class=\"{'awd-select-list': (isInputDropdown), 'awd-module-list': (!isInputDropdown)}\" tabindex=\"-1\" ng-show=\"toggleFlag\" aria-label=\"Choose options\"></ul>\n" +\r
21344     "        <ul class=\"module-optinalcta\" ng-if=\"toggleFlag && optionalCta\" tabindex=\"-1\" aria-hidden=\"false\">\n" +\r
21345     "            <li class=\"module-list-item\" tabindex=\"-1\" role=\"menuitem\" value=\"\" aria-label=\"Optinal CTA\" aria-selected=\"true\">\n" +\r
21346     "                <span class=\"module-data\" b2b-append-element=\"optionalCta\"></span>\n" +\r
21347     "            </li>\n" +\r
21348     "        </ul>\n" +\r
21349     "</div>\n" +\r
21350     "<i class=\"icon-primary-down\" aria-hidden=\"true\"></i>\n" +\r
21351     "</span>    ");\r
21352 }]);\r
21353 \r
21354 angular.module("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html", []).run(["$templateCache", function($templateCache) {\r
21355   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html",\r
21356     "<li b2b-dropdown-group-desktop class=\"optgroup-wrapper\">{{groupHeader}}\n" +\r
21357     "    <ul class=\"optgroup\" role=\"group\" aria-label=\"{{groupHeader}}\"></ul>\n" +\r
21358     "</li>");\r
21359 }]);\r
21360 \r
21361 angular.module("b2bTemplate/dropdowns/b2bDropdownListDesktop.html", []).run(["$templateCache", function($templateCache) {\r
21362   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownListDesktop.html",\r
21363     "<li b2b-dropdown-list-desktop b2b-key-item b2b-accessibility-click=\"13\" aria-selected=\"{{currentSelected.value === dropdownListValue}}\" ng-class=\"{'awd-select-list-item': (isInputDropdown), 'module-list-item': (!isInputDropdown)}\" tabindex=\"0\" role=\"{{isInputDropdown?'option':'menuitem'}}\" ng-click=\"selectDropdownItem()\"></li>");\r
21364 }]);\r
21365 \r
21366 angular.module("b2bTemplate/fileUpload/fileUpload.html", []).run(["$templateCache", function($templateCache) {\r
21367   $templateCache.put("b2bTemplate/fileUpload/fileUpload.html",\r
21368     "<label class=\"b2b-file-container\">\n" +\r
21369     "   <span class=\"b2b-upload-link\" ng-transclude></span>\n" +\r
21370     "   <input type=\"file\" b2b-file-change>\n" +\r
21371     "</label>");\r
21372 }]);\r
21373 \r
21374 angular.module("b2bTemplate/flyout/flyout.html", []).run(["$templateCache", function($templateCache) {\r
21375   $templateCache.put("b2bTemplate/flyout/flyout.html",\r
21376     "<span class=\"b2b-flyout\"  b2b-flyout-trap-focus-inside>\n" +\r
21377     "    <span ng-transclude></span>\n" +\r
21378     "</span>");\r
21379 }]);\r
21380 \r
21381 angular.module("b2bTemplate/flyout/flyoutContent.html", []).run(["$templateCache", function($templateCache) {\r
21382   $templateCache.put("b2bTemplate/flyout/flyoutContent.html",\r
21383     "<div class=\"b2b-flyout-container\" aria-live=\"polite\" aria-atomic=\"false\" ng-class=\"{'b2b-flyout-left':horizontalPlacement==='left',\n" +\r
21384     "                'b2b-flyout-center':horizontalPlacement==='center', \n" +\r
21385     "                'b2b-flyout-right':horizontalPlacement==='right',\n" +\r
21386     "                'b2b-flyout-centerLeft':horizontalPlacement==='centerLeft',\n" +\r
21387     "                'b2b-flyout-centerRight':horizontalPlacement==='centerRight',  \n" +\r
21388     "                'b2b-flyout-above':verticalPlacement==='above', \n" +\r
21389     "                'b2b-flyout-below':verticalPlacement==='below',\n" +\r
21390     "                'open-flyout': openFlyout,\n" +\r
21391     "                'b2b-close-flyout': !openFlyout}\">\n" +\r
21392     "    <i class=\"b2b-flyout-caret\" ng-class=\"{'open-flyout': openFlyout, \n" +\r
21393     "                                   'b2b-flyout-caret-above':verticalPlacement==='above',\n" +\r
21394     "                                   'b2b-flyout-caret-below':verticalPlacement==='below'}\"></i>\n" +\r
21395     "    <span ng-transclude></span>\n" +\r
21396     "</div>");\r
21397 }]);\r
21398 \r
21399 angular.module("b2bTemplate/footer/footer_column_switch_tpl.html", []).run(["$templateCache", function($templateCache) {\r
21400   $templateCache.put("b2bTemplate/footer/footer_column_switch_tpl.html",\r
21401     "<div class=\"footer-columns \" ng-class=\"{'five-column':footerColumns===5, 'four-column':footerColumns===4, 'three-column':footerColumns===3}\" ng-repeat=\"item in footerLinkItems\">\n" +\r
21402     "    <h3 class=\"b2b-footer-header\">{{item.categoryName}}</h3>\n" +\r
21403     "    <ul>\n" +\r
21404     "        <li ng-repeat=\"i in item.values\">\n" +\r
21405     "            <a href=\"{{i.href}}\" title=\"{{item.categoryName}} - {{i.displayLink}}\">{{i.displayLink}}</a>  \n" +\r
21406     "        </li>\n" +\r
21407     "    </ul>\n" +\r
21408     "\n" +\r
21409     "</div>\n" +\r
21410     "\n" +\r
21411     "<div ng-transclude></div>\n" +\r
21412     "");\r
21413 }]);\r
21414 \r
21415 angular.module("b2bTemplate/horizontalTable/horizontalTable.html", []).run(["$templateCache", function($templateCache) {\r
21416   $templateCache.put("b2bTemplate/horizontalTable/horizontalTable.html",\r
21417     "<div class=\"b2b-horizontal-table\">\n" +\r
21418     "    <div class=\"b2b-horizontal-table-arrows row span12\">\n" +\r
21419     "       <div class=\"span4\">\n" +\r
21420     "           <button class=\"btn-arrow left\" type=\"button\" ng-click=\"moveViewportLeft()\" ddh-accessibility-click=\"13,32\" ng-disabled=\"disableLeft\"><div class=\"btn btn-alt\"><i class=\"icon-primary-left\"></i></div>Previous Set</button>\n" +\r
21421     "        </div>\n" +\r
21422     "        \n" +\r
21423     "        <span class=\"span5 b2b-horizontal-table-column-info\" aria-live=\"polite\" tabindex=\"-1\">\n" +\r
21424     "           Displaying {{getColumnSet()[0]}} - {{getColumnSet()[1]}} of {{numOfCols}} (total) columns\n" +\r
21425     "        </span>\n" +\r
21426     "        \n" +\r
21427     "        <div class=\"span3\">\n" +\r
21428     "           <button class=\"btn-arrow right\" ng-click=\"moveViewportRight()\" ddh-accessibility-click=\"13,32\" ng-disabled=\"disableRight\" type=\"button\">Next Set<div class=\"btn btn-alt\"><i class=\"icon-primary-right\"></i></div></button>\n" +\r
21429     "       </div>\n" +\r
21430     "    </div>\n" +\r
21431     "    <div class=\"b2b-horizontal-table-inner-container\">\n" +\r
21432     "        <span ng-transclude></span>\n" +\r
21433     "    </div>\n" +\r
21434     "</div>\n" +\r
21435     "\n" +\r
21436     "");\r
21437 }]);\r
21438 \r
21439 angular.module("b2bTemplate/hourPicker/b2bHourpicker.html", []).run(["$templateCache", function($templateCache) {\r
21440   $templateCache.put("b2bTemplate/hourPicker/b2bHourpicker.html",\r
21441     "<div class=\"hp-container\">\n" +\r
21442     "    <div class=\"hp-selected\">\n" +\r
21443     "        <div b2b-hourpicker-value=\"$index\" days=\"value.days\" start-time=\"value.startTime\" start-meridiem=\"value.startMeridiem\" end-time=\"value.endTime\" end-meridiem=\"value.endMeridiem\" ng-repeat=\"value in finalHourpickerValues\"></div>\n" +\r
21444     "    </div>\n" +\r
21445     "    <div b2b-hourpicker-panel></div>\n" +\r
21446     "</div>");\r
21447 }]);\r
21448 \r
21449 angular.module("b2bTemplate/hourPicker/b2bHourpickerPanel.html", []).run(["$templateCache", function($templateCache) {\r
21450   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerPanel.html",\r
21451     "<form name=\"{{'hourpickerForm' + $id}}\">\n" +\r
21452     "    <div class=\"hp-checkbox\" role=\"group\">\n" +\r
21453     "        <label class=\"checkbox\" for=\"checkbox_{{dayOption.title}}_{{$id}}\" aria-label=\"{{dayOption.title}}\" ng-repeat=\"dayOption in hourpicker.dayOptions\">\n" +\r
21454     "            <input type=\"checkbox\" id=\"checkbox_{{dayOption.title}}_{{$id}}\" name=\"{{'hourpickerDays' + $id}}\" ng-model=\"hourpickerPanelValue.days[$index].value\" ng-disabled=\"dayOption.disabled\" /><i class=\"skin\"></i><span>{{dayOption.label}}</span>\n" +\r
21455     "        </label>\n" +\r
21456     "    </div>\n" +\r
21457     "    <div class=\"row hp-dropdowns\">\n" +\r
21458     "        <div class=\"span4\">\n" +\r
21459     "            <label for=\"{{'hourpickerStartTime' + $id}}\">From</label>\n" +\r
21460     "            <select id=\"{{'hourpickerStartTime' + $parent.$id}}\" b2b-dropdown type=\"\" ng-model=\"hourpickerPanelValue.startTime\">\n" +\r
21461     "                <option b2b-dropdown-list value=\"\">From</option>\n" +\r
21462     "                <option b2b-dropdown-list option-repeat=\"startTimeOption in hourpicker.startTimeOptions\" value=\"{{startTimeOption}}\">{{startTimeOption}}</option>\n" +\r
21463     "            </select>\n" +\r
21464     "        </div>\n" +\r
21465     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +\r
21466     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_AM_{{$id}}\">\n" +\r
21467     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_AM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +\r
21468     "            </label>\n" +\r
21469     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_PM_{{$id}}\">\n" +\r
21470     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_PM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +\r
21471     "            </label>\n" +\r
21472     "        </div>\n" +\r
21473     "    </div>\n" +\r
21474     "    <div class=\"row hp-dropdowns\">\n" +\r
21475     "        <div class=\"span4\">\n" +\r
21476     "            <label for=\"{{'hourpickerEndTime' + $id}}\">To</label>\n" +\r
21477     "            <select id=\"{{'hourpickerEndTime' + $parent.$id}}\" b2b-dropdown ng-model=\"hourpickerPanelValue.endTime\">\n" +\r
21478     "                <option b2b-dropdown-list value=\"\">To</option>\n" +\r
21479     "                <option b2b-dropdown-list option-repeat=\"endTimeOption in hourpicker.endTimeOptions\" value=\"{{endTimeOption}}\">{{endTimeOption}}</option>\n" +\r
21480     "            </select>\n" +\r
21481     "        </div>\n" +\r
21482     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +\r
21483     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_AM_{{$id}}\">\n" +\r
21484     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_AM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +\r
21485     "            </label>\n" +\r
21486     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_PM_{{$id}}\">\n" +\r
21487     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_PM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +\r
21488     "            </label>\n" +\r
21489     "        </div>\n" +\r
21490     "    </div>\n" +\r
21491     "    <div class=\"row hp-buttons\">\n" +\r
21492     "        <div class=\"span12\">\n" +\r
21493     "            <div style=\"float:right\">\n" +\r
21494     "                <button class=\"btn btn-secondary btn-small\" ng-click=\"resetHourpickerPanelValue()\">Clear</button>\n" +\r
21495     "                <button class=\"btn btn-alt btn-small\" ng-disabled = \"disableAddBtn\" ng-click=\"updateHourpickerValue()\">{{hourpicker.editMode > -1 ? 'Update' : 'Add'}}</button>\n" +\r
21496     "            </div>\n" +\r
21497     "        </div>\n" +\r
21498     "    </div>\n" +\r
21499     "</form>");\r
21500 }]);\r
21501 \r
21502 angular.module("b2bTemplate/hourPicker/b2bHourpickerValue.html", []).run(["$templateCache", function($templateCache) {\r
21503   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerValue.html",\r
21504     "<div class=\"selected-days\">\n" +\r
21505     "    <span class=\"day\">{{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}</span>\n" +\r
21506     "    <span style=\"float:right\">\n" +\r
21507     "        <i class=\"icon-misc-pen\" role=\"button\" title=\"Edit {{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"editHourpickerValue(hourpickerValue.index)\"></i>\n" +\r
21508     "        <i class=\"icon-misc-trash\" role=\"button\" title=\"Delete {{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"deleteHourpickerValue(hourpickerValue.index)\"></i>\n" +\r
21509     "    </span>\n" +\r
21510     "    <div style=\"clear:both\"></div>\n" +\r
21511     "</div>");\r
21512 }]);\r
21513 \r
21514 angular.module("b2bTemplate/leftNavigation/leftNavigation.html", []).run(["$templateCache", function($templateCache) {\r
21515   $templateCache.put("b2bTemplate/leftNavigation/leftNavigation.html",\r
21516   "<div class=\"b2b-nav-menu\" ng-init=\"(showmenu = true)\" ng-class=\"{false: 'left-menu-collapsed'}[showmenu]\">\n" +\r
21517     "    <div class=\"b2b-subnav-container\">\n" +\r
21518     "        <ul class=\"b2b-subnav-content\">\n" +\r
21519     "                    <li>" +\r
21520     "                           <div ng-class=\"{true: 'leftmenu-arrow-expand', false: 'leftmenu-arrow-collapse'}[showmenu]\">"+        \r
21521     "                                   <a ng-click=\"toggleDrawer(showmenu);(showmenu = !showmenu) \" class=\"text-right\">" +\r
21522     "                                   <i ng-class=\"{true: 'icon-controls-left', false: 'icon-controls-right'}[showmenu]\">&nbsp;</i></a>" +\r
21523     "                           </div>"+                        \r
21524     "                   </li>" +\r
21525     "            <li ng-repeat=\"menu in menuData\" ui-sref=\"{{menu.state}}\">" +\r
21526     "                           <span ng-class=\"{true: 'menu-icon', false: 'menu-icon-collapse'}[showmenu]\"><span class=\"{{menu.imageSrc}}\"></span>&nbsp;&nbsp;</span>" +\r
21527     "                           <a ng-class=\"{expand: isOpen($index)}\" ng-if=\"showmenu\"  aria-label=\"{{menu.name}}\" title=\" \" aria-expanded=\"{{(idx==$index)?true:false;}}\" href=\"javascript:void(0);\">" +\r
21528     "                                   {{menu.name}}" +\r
21529     "                                   <i aria-hidden=\"true\" ng-if=\"(menu.menuItems.length > 0)\" class=\"b2b-icon-primary-plus-minus\"ng-class=\"idx==$index ? 'icon-primary-expanded' : 'icon-primary-collapsed'\"></i>" +\r
21530     "                           </a>\n" +\r
21531     "                           <div role=\"region\" aria-hidden=\"{{(isOpen($index))?false:true;}}\">\n" +\r
21532     "                   <ul ng-class=\"{expand: idx==$index}\">\n" +\r
21533     "                     <li ng-repeat=\"menuItem in menu.menuItems\" ng-click=\"liveLink($event, $index, $parent.$index)\"><a aria-hidden=\"{{!(idx==$parent.$index)}}\" aria-label=\"{{menuItem.name}}\" title=\" \" href=\"{{menuItem.href}}\" tabindex=\"{{(idx==$parent.$index)?0:-1;}}\" ng-class=\"{active: itemIdx==$index && navIdx==$parent.$index}\">{{menuItem.name}}</a></li>\n" +\r
21534     "                           </ul>\n" +\r
21535     "                           </div>\n" +\r
21536     "            </li>\n" +\r
21537     "        </ul>\n" +\r
21538     "    </div>\n" +\r
21539     "</div>");\r
21540 }]);\r
21541 \r
21542 angular.module("b2bTemplate/listbox/listbox.html", []).run(["$templateCache", function($templateCache) {\r
21543   $templateCache.put("b2bTemplate/listbox/listbox.html",\r
21544     "<div class=\"b2b-list-box\" tabindex=\"0\" role=\"listbox\" ng-transclude>\n" +\r
21545     "</div>");\r
21546 }]);\r
21547 \r
21548 angular.module("b2bTemplate/modalsAndAlerts/b2b-backdrop.html", []).run(["$templateCache", function($templateCache) {\r
21549   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-backdrop.html",\r
21550     "<div class=\"b2b-modal-backdrop fade in hidden-by-modal\" aria-hidden=\"true\" tabindex=\"-1\"></div>");\r
21551 }]);\r
21552 \r
21553 angular.module("b2bTemplate/modalsAndAlerts/b2b-window.html", []).run(["$templateCache", function($templateCache) {\r
21554   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-window.html",\r
21555     "<div class=\"modalwrapper active {{windowClass}}\" ng-class=\"{'modal-landscape': isModalLandscape}\" role=\"{{isNotifDialog?'alertdialog':'dialog'}}\" tabindex=\"-1\" aria-labelledby=\"{{title}}\" aria-describedby=\"{{content}}\">\n" +\r
21556     "    <div class=\"modal fade in {{sizeClass}}\" ng-transclude></div>\n" +\r
21557     "</div>");\r
21558 }]);\r
21559 \r
21560 angular.module("b2bTemplate/monthSelector/monthSelector-popup.html", []).run(["$templateCache", function($templateCache) {\r
21561   $templateCache.put("b2bTemplate/monthSelector/monthSelector-popup.html",\r
21562     "<div id=\"monthselector{{$id}}\" class=\"datepicker dropdown-menu monthselector\" \n" +\r
21563     "     ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" \n" +\r
21564     "     ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" \n" +\r
21565     "     style=\"display: block;\" aria-hidden=\"false\" role=\"dialog presentation\" tabindex=\"-1\">\n" +\r
21566     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +\r
21567     "        <span class=\"offscreen-text\" aria-live=\"polite\" aria-atomic=\"true\">{{title}} displaying</span>\n" +\r
21568     "        <table class=\"table-condensed\" role=\"grid\">\n" +\r
21569     "            <thead>\n" +\r
21570     "                <tr ng-repeat=\"header in headers\">\n" +\r
21571     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"header\"></th>\n" +\r
21572     "                </tr>\n" +\r
21573     "                <tr>\n" +\r
21574     "                    <th id=\"prev{{$id}}\" role=\"button\" tabindex=\"0\" b2b-accessibility-click=\"13\" aria-label=\"Previous Year\" ng-class=\"{'prev': !disablePrev}\" ng-style=\"{visibility: visibilityPrev}\" ng-click=\"!disablePrev && move(-1,$event)\"><i class=\"icon-primary-left\"></i></th>\n" +\r
21575     "                    <th id=\"year{{$id}}\" role=\"heading\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch b2b-monthSelector-label\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +\r
21576     "                    <th id=\"next{{$id}}\" role=\"button\" tabindex=\"0\" b2b-accessibility-click=\"13\" aria-label=\"Next Year\" ng-class=\"{'next': !disableNext}\" ng-style=\"{visibility: visibilityNext}\" ng-click=\"!disableNext && move(1,$event)\"><i class=\"icon-primary-right\"></i></th>\n" +\r
21577     "                </tr>\n" +\r
21578     "                <tr ng-show=\"labels.length > 0\">\n" +\r
21579     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +\r
21580     "                </tr>\n" +\r
21581     "            </thead>\n" +\r
21582     "            <tbody b2b-key type=\"table\" columns=\"4\" >\n" +\r
21583     "                <tr ng-repeat=\"row in rows\">\n" +\r
21584     "                    <td headers=\"{{dt.header}}\" b2b-key-item=\"dt.focusable\" b2b-accessibility-click=\"13,32\" tabindex=\"{{(!(dt.focusable && (dt.selected || dt.firstFocus || currFocus)) && -1) || 0}}\" aria-hidden=\"{{(!dt.focusable && true) || false}}\" role=\"{{(dt.focusable && 'gridcell') || ''}}\" aria-label=\"{{(dt.focusable && dt.date | date : 'MMMM, y') || ''}}\" aria-selected=\"{{(dt.focusable && (dt.selected || dt.dateRange) && true) || false}}\" ng-repeat=\"dt in row\" class=\"day magic\" ng-class=\"{'active': dt.focusable && dt.selected && !dt.dateRange, 'start-date': dt.focusable && dt.fromDate && dt.dateRange, 'between-date': dt.focusable && !dt.fromDate && !dt.selected && dt.dateRange, 'end-date': dt.focusable && dt.selected && dt.dateRange, 'old': dt.oldMonth, 'new': dt.nextMonth, 'disabled': dt.disabled, 'due-date': dt.dueDate, 'late-fee': dt.pastDue}\" ng-focus=\"currFocus=true\" ng-blur=\"currFocus=false\" title=\"{{(dt.focusable && dt.pastDue && legendMessage) || ''}}\" b2b-element-focus=\"inline && dt.focusable && dt.selected && !dt.dateRange\" ng-click=\"!ngDisabled && !dt.disabled && select(dt.date)\">\n" +\r
21585     "                        <div aria-hidden=\"true\"  tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label | limitTo: 3}}</div>\n" +\r
21586     "                    </td>\n" +\r
21587     "                </tr>\n" +\r
21588     "            </tbody>\n" +\r
21589     "            <tfoot>\n" +\r
21590     "                <tr ng-repeat=\"footer in footers\">\n" +\r
21591     "                    <th colspan=\"7\" class=\"text-left\" b2b-append-element=\"footer\"></th>\n" +\r
21592     "                </tr>\n" +\r
21593     "            </tfoot>\n" +\r
21594     "        </table>\n" +\r
21595     "    </div>\n" +\r
21596     "</div>");\r
21597 }]);\r
21598 \r
21599 angular.module("b2bTemplate/monthSelector/monthSelector.html", []).run(["$templateCache", function($templateCache) {\r
21600   $templateCache.put("b2bTemplate/monthSelector/monthSelector.html",\r
21601     "<div>\n" +\r
21602     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +\r
21603     "</div>");\r
21604 }]);\r
21605 \r
21606 angular.module("b2bTemplate/monthSelector/monthSelectorLink.html", []).run(["$templateCache", function($templateCache) {\r
21607   $templateCache.put("b2bTemplate/monthSelector/monthSelectorLink.html",\r
21608     "<div>\n" +\r
21609     "    <span class=\"span12\" ng-transclude></span>\n" +\r
21610     "</div>");\r
21611 }]);\r
21612 \r
21613 angular.module("b2bTemplate/pagination/b2b-pagination.html", []).run(["$templateCache", function($templateCache) {\r
21614   $templateCache.put("b2bTemplate/pagination/b2b-pagination.html",\r
21615     "<div class=\"b2b-pager\">\n" +\r
21616     "    <div ng-if=\"notMobile && totalPages > 1\">\n" +\r
21617     "        <a tabindex=\"{{currentPage <= 1 ? -1 : 0 }}\" class=\"b2b-pager__item--prev\" b2b-accessibility-click=\"13,32\" title=\"Previous Page\" ng-click=\"prev($event)\" ng-if=\"totalPages > 10\" ng-class=\"currentPage <= 1 ? 'b2b-pager__item--prev-disabled': '' \">\n" +\r
21618     "            <i class=\"icon-primary-left\"></i>\n" +\r
21619     "        </a>\n" +\r
21620     "        <a tabindex=\"{{currentPage === 1 ? -1 : 0}}\" ng-class=\"{'b2b-pager__item--noclick': currentPage === 1}\" aria-selected=\"{{checkSelectedPage(page)}}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page 1{{checkSelectedPage(page) ? ' selected' : '' }}\" ng-if=\"totalPages > 10 && currentPage > 6\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(1, $event)\">\n" +\r
21621     "            1<span class=\"offscreen-text\" ng-if=\"currentPage === 1\"> is selected</span>\n" +\r
21622     "        </a>\n" +\r
21623     "        <a tabindex=\"{{currentPage === 2 ? -1 : 0}}\" aria-selected=\"{{checkSelectedPage(page)}}\" ng-class=\"{'b2b-pager__item--noclick': currentPage === 2}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page 2{{checkSelectedPage(page) ? ' selected' : '' }}\" ng-if=\"totalPages > 10 && currentPage > 6\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(2, $event)\">2<span class=\"offscreen-text\" ng-if=\"currentPage === 2\"> is selected</span></a>\n" +\r
21624     "\n" +\r
21625     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage > 6\">...</span>\n" +\r
21626     "\n" +\r
21627     "        <a tabindex=\"{{checkSelectedPage(page) ? -1 : 0}}\" href=\"javascript:void(0)\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{page}}\" b2b-element-focus=\"isFocused(page)\" ng-repeat=\"page in pages\" ng-class=\"{'b2b-pager__item--active': checkSelectedPage(page), 'b2b-pager__item--noclick': checkSelectedPage(page)}\" b2b-accessibility-click=\"13,32\" ng-click=\"!checkSelectedPage(page) && selectPage(page, $event)\">{{page}}<span class=\"offscreen-text\" ng-if=\"currentPage === page\"> is selected</span></a>\n" +\r
21628     "\n" +\r
21629     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage <= totalPages - 5\">...</span>\n" +\r
21630     "\n" +\r
21631     "        <a tabindex=\"{{checkSelectedPage(page) ? -1 : 0}}\" href=\"javascript:void(0)\" ng-class=\"{'b2b-pager__item--noclick': checkSelectedPage(page)}\" aria-selected=\"{{checkSelectedPage(page)}}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{totalPages-1}}\" ng-if=\"totalPages > 10 && currentPage <= totalPages - 5\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(totalPages-1, $event)\">{{totalPages-1}}<span class=\"offscreen-text\" ng-if=\"currentPage === totalPages-1\"> is selected</span></a>\n" +\r
21632     "\n" +\r
21633     "        <a tabindex=\"{{currentPage === totalPages ? -1 : 0}}\" href=\"javascript:void(0)\" ng-class=\"{'b2b-pager__item--noclick': currentPage === totalPages}\" aria-selected=\"{{checkSelectedPage(page)}}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{totalPages}}\" ng-if=\"totalPages > 10 && currentPage <= totalPages - 5\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(totalPages, $event)\">{{totalPages}}<span class=\"offscreen-text\" ng-if=\"currentPage === totalPages\"> is selected</span></a>\n" +\r
21634     "\n" +\r
21635     "        <a tabindex=\"{{currentPage >= totalPages ? -1 : 0 }}\" href=\"javascript:void(0)\" class=\"b2b-pager__item--next\" b2b-accessibility-click=\"13,32\" title=\"Next Page\" ng-click=\"next($event)\" ng-if=\"totalPages > 10\" ng-class=\"currentPage >= totalPages ? 'b2b-pager__item--next-disabled' :'' \">\n" +\r
21636     "            <i class=\"icon-primary-right\"></i>\n" +\r
21637     "        </a>\n" +\r
21638     "        \n" +\r
21639     "        <span class=\"fieldLabel\" ng-show=\"totalPages > 10 && showInput === true\">    \n" +\r
21640     "            <label for=\"{{inputId}}\">Go to Page:</label>\n" +\r
21641     "            <input id=\"{{inputId}}\" class=\"b2b-pager__item--input\" type=\"number\" ng-blur=\"onfocusOut($event)\" ng-focus=\"onfocusIn($event)\" ng-keypress=\"gotoKeyClick($event)\" b2b-only-nums=\"4\" ng-model=\"$parent.gotoPage\" />\n" +\r
21642     "            <button class=\"btn-arrow\" ng-click=\"gotoBtnClick()\" ng-disabled=\"$parent.gotoPage !== 0 || $parent.gotoPage !== undefined\" aria-label=\"Go to\">\n" +\r
21643     "                <div class=\"btn btn-small btn-secondary\">\n" +\r
21644     "                    <i class=\"icon-primary-right\"></i>\n" +\r
21645     "                </div>\n" +\r
21646     "            </button>\n" +\r
21647     "        </span>\n" +\r
21648     "    </div>\n" +\r
21649     "    <div ng-if=\"isMobile && totalPages > 1\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\" ng-class=\"isMobile ? 'b2b-mobile-view': '' \">\n" +\r
21650     "        <a tabindex=\"{{checkSelectedPage(page) ? -1 : 0}}\" href=\"javascript:void(0)\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{page}}\" b2b-element-focus=\"isFocused(page)\" ng-repeat=\"page in pages\" ng-class=\"{'b2b-pager__item--active': checkSelectedPage(page), fade1: ($index == 0 && currentPage > meanVal+1),  fade2: ($index == 1 && currentPage > meanVal+1), fadesl: ($index == pages.length-2 && currentPage < totalPages - meanVal),  fadel: ($last && currentPage < totalPages - meanVal), 'b2b-pager__item--noclick': checkSelectedPage(page)}\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(page, $event)\">{{page}}</a>\n" +\r
21651     "    </div>\n" +\r
21652     "</div>\n" +\r
21653     "");\r
21654 }]);\r
21655 \r
21656 angular.module("b2bTemplate/paneSelector/paneSelector.html", []).run(["$templateCache", function($templateCache) {\r
21657   $templateCache.put("b2bTemplate/paneSelector/paneSelector.html",\r
21658     "<div class=\"panes\" ng-transclude></div>");\r
21659 }]);\r
21660 \r
21661 angular.module("b2bTemplate/paneSelector/paneSelectorPane.html", []).run(["$templateCache", function($templateCache) {\r
21662   $templateCache.put("b2bTemplate/paneSelector/paneSelectorPane.html",\r
21663     "<div class=\"pane-block\" ng-transclude></div>");\r
21664 }]);\r
21665 \r
21666 angular.module("b2bTemplate/profileCard/profileCard-addUser.html", []).run(["$templateCache", function($templateCache) {\r
21667   $templateCache.put("b2bTemplate/profileCard/profileCard-addUser.html",\r
21668     "<div  class=\"span3 b2b-profile-card b2b-add-user\">\n" +\r
21669     "    <div class=\"atcenter\">\n" +\r
21670     "        <div class=\"circle\"><i class=\"icon-primary-add-maximize\"></i></div>\n" +\r
21671     "        <div>Create new user</div>\n" +\r
21672     "    </div>\n" +\r
21673     "</div>");\r
21674 }]);\r
21675 \r
21676 angular.module("b2bTemplate/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {\r
21677   $templateCache.put("b2bTemplate/profileCard/profileCard.html",\r
21678     "<div class=\"span3 b2b-profile-card\">\n" +\r
21679     "    <div class=\"top-block\">\n" +\r
21680     "       <div class=\"profile-image\">\n" +\r
21681     "            <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +\r
21682     "            <span ng-if=\"!image\" class=\"default-img\">{{initials}}</span>\n" +\r
21683     "\n" +\r
21684     "            <h4 class=\"name\">{{profile.name}}</h4>\n" +\r
21685     "\n" +\r
21686     "            <p class=\"status\">\n" +\r
21687     "                <span class=\"status-icon\" ng-class=\"{'status-green':colorIcon==='green','status-red':colorIcon==='red','status-blue':colorIcon==='blue','status-yellow':colorIcon==='yellow'}\">   \n" +\r
21688     "                </span>\n" +\r
21689     "                <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +\r
21690     "            </p>\n" +\r
21691     "        </div>\n" +\r
21692     "    </div>\n" +\r
21693     "    <div class=\"bottom-block\">\n" +\r
21694     "         <div class=\"profile-details\">\n" +\r
21695     "            <label>Username</label>\n" +\r
21696     "            <div ng-if=\"shouldClip(profile.userName)\" ng-mouseover=\"showUserNameTooltip = true;\" ng-mouseleave=\"showUserNameTooltip = false;\">\n" +\r
21697     "                <div ng-if=\"shouldClip(profile.userName)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showUserNameTooltip\">\n" +\r
21698     "                    {{profile.userName.slice(0, 25)+'...'}}\n" +\r
21699     "                    <div class=\"arrow\"></div>\n" +\r
21700     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21701     "                        <div class=\"tooltip-size-control\">\n" +\r
21702     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21703     "                                {{profile.userName}}\n" +\r
21704     "                            </div>\n" +\r
21705     "                        </div>\n" +\r
21706     "                    </div>\n" +\r
21707     "                </div>\n" +\r
21708     "            </div>\n" +\r
21709     "            <div ng-if=\"!shouldClip(profile.userName)\">\n" +\r
21710     "                {{profile.userName}}\n" +\r
21711     "            </div>\n" +\r
21712     "            <label>Email</label>\n" +\r
21713     "            <div ng-if=\"shouldClip(profile.email)\" ng-mouseover=\"showEmailTooltip = true;\" ng-mouseleave=\"showEmailTooltip = false;\">\n" +\r
21714     "                <div ng-if=\"shouldClip(profile.email)\" class=\"tooltip\" data-placement=\"bottom\" b2b-tooltip show-tooltip=\"showEmailTooltip\">\n" +\r
21715     "                    {{profile.email.slice(0, 25)+'...'}}\n" +\r
21716     "                    <div class=\"arrow\"></div>\n" +\r
21717     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21718     "                        <div class=\"tooltip-size-control\">\n" +\r
21719     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21720     "                                {{profile.email}}\n" +\r
21721     "                            </div>\n" +\r
21722     "                        </div>\n" +\r
21723     "                    </div>\n" +\r
21724     "                </div>\n" +\r
21725     "            </div>\n" +\r
21726     "            <div ng-if=\"!shouldClip(profile.email)\">\n" +\r
21727     "                {{profile.email}}\n" +\r
21728     "            </div>\n" +\r
21729     "            <label>Role</label>\n" +\r
21730     "            <div ng-if=\"shouldClip(profile.role)\" ng-mouseover=\"showRoleTooltip = true;\" ng-mouseleave=\"showRoleTooltip = false;\">\n" +\r
21731     "                <div ng-if=\"shouldClip(profile.role)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showRoleTooltip\">\n" +\r
21732     "                    {{profile.role.slice(0, 25)+'...'}}\n" +\r
21733     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21734     "                        <div class=\"tooltip-size-control\">\n" +\r
21735     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21736     "                                {{profile.role}}\n" +\r
21737     "                            </div>\n" +\r
21738     "                        </div>\n" +\r
21739     "                    </div>\n" +\r
21740     "                </div>\n" +\r
21741     "            </div>\n" +\r
21742     "            <div ng-if=\"!shouldClip(profile.role)\">\n" +\r
21743     "                {{profile.role}}\n" +\r
21744     "            </div>\n" +\r
21745     "            <label>Last login</label>\n" +\r
21746     "            <div ng-if=\"shouldClip(profile.lastLogin)\" ng-mouseover=\"showLastLoginTooltip = true;\" ng-mouseleave=\"showLastLoginTooltip = false;\">\n" +\r
21747     "                <div ng-if=\"shouldClip(profile.lastLogin)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showLastLoginTooltip\">\n" +\r
21748     "                    {{profile.lastLogin.slice(0, 25)+'...'}}\n" +\r
21749     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21750     "                        <div class=\"tooltip-size-control\">\n" +\r
21751     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21752     "                                {{profile.lastLogin}}\n" +\r
21753     "                            </div>\n" +\r
21754     "                        </div>\n" +\r
21755     "                    </div>\n" +\r
21756     "                </div>\n" +\r
21757     "            </div>\n" +\r
21758     "            <div ng-if=\"!shouldClip(profile.lastLogin)\">\n" +\r
21759     "                {{profile.lastLogin}}\n" +\r
21760     "            </div>\n" +\r
21761     "         </div>\n" +\r
21762     "    </div>\n" +\r
21763     "</div>");\r
21764 }]);\r
21765 \r
21766 angular.module("b2bTemplate/searchField/searchField.html", []).run(["$templateCache", function($templateCache) {\r
21767   $templateCache.put("b2bTemplate/searchField/searchField.html",\r
21768     "<div class=\"search-bar\">\n" +\r
21769     "    <div class='input-container' ng-blur=\"blurInput()\">\n" +\r
21770     "        <input type=\"text\" class=\"innershadow b2b-search-input-field\" id=\"{{configObj.labelId}}\" b2b-search-input ng-model=\"inputModel\" ng-disabled=\"disabled\" b2b-reset ng-keydown=\"selectionIndex($event)\" placeholder=\"{{configObj.ghostText}}\" style=\"width:100%\" maxlength=\"{{configObj.maxLength}}\" title=\"{{inputModel}}\" aria-label=\"{{inputModel.length>0?inputModel:configObj.ghostText}}\"  aria-live=\"assertive\"/>\n" +\r
21771     "            <button class=\"btn-search\" ng-disabled=\"disabled\" ng-click=\"startSearch()\" b2b-accessibility-click=\"13,32\" aria-label=\"Search\" ng-focus=\"showListFlag = false\" type=\"button\"><i class=\"icoControls-magnifyingglass\"></i></button>\n" +\r
21772     "    </div>\n" +\r
21773     "    <div class=\"search-suggestion-wrapper\" ng-if=\"filterList.length >=0\" ng-show=\"showListFlag\">\n" +\r
21774     "        <ul class=\"search-suggestion-list\" role=\"listbox\">      \n" +\r
21775     "            <li class=\"no-result\" ng-if=\"filterList.length == 0 && configObj.display\">{{configObj.resultText}}</li>\n" +\r
21776     "            <li class=\"search-suggestion-item\" ng-if=\"filterList.length\" ng-repeat=\"item in filterList | limitTo:configObj.noOfItemsDisplay track by $index\" ng-bind-html=\"item.title | b2bMultiSepartorHighlight:inputModel:configObj.searchSeperator\" ng-class=\"{active:isActive($index,filterList.length)}\" ng-click=\"selectItem($index,item.title)\">\n" +\r
21777     "                {{item.title}}     \n" +\r
21778     "            </li>\n" +\r
21779     "        </ul>\n" +\r
21780     "    </div>\n" +\r
21781     "</div>");\r
21782 }]);\r
21783 \r
21784 angular.module("b2bTemplate/seekBar/seekBar.html", []).run(["$templateCache", function($templateCache) {\r
21785   $templateCache.put("b2bTemplate/seekBar/seekBar.html",\r
21786     "<div class=\"b2b-seek-bar-container\" ng-class=\"{vertical:verticalSeekBar}\">\n" +\r
21787     "    <div class=\"b2b-seek-bar-track-container\">\n" +\r
21788     "        <div class=\"b2b-seek-bar-track\"></div>\n" +\r
21789     "        <div class=\"b2b-seek-bar-track-fill\"></div>\n" +\r
21790     "    </div>\n" +\r
21791     "    <div class=\"b2b-seek-bar-knob-container\" role=\"menu\"  >\n" +\r
21792     "        <div class=\"b2b-seek-bar-knob\" tabindex=\"0\" role=\"menuitem\"></div>\n" +\r
21793     "    </div>\n" +\r
21794     "</div>");\r
21795 }]);\r
21796 \r
21797 angular.module("b2bTemplate/slider/slider.html", []).run(["$templateCache", function($templateCache) {\r
21798   $templateCache.put("b2bTemplate/slider/slider.html",\r
21799     "<div class=\"b2b-slider-container\" ng-class=\"{'vertical':verticalSlider}\">\n" +\r
21800     "    <div class=\"slider-track-container\">\n" +\r
21801     "        <div class=\"slider-track\"></div>\n" +\r
21802     "        <div class=\"slider-track-fill\" ng-style=\"{backgroundColor:trackFillColor}\"></div>\n" +\r
21803     "    </div>\n" +\r
21804     "    <div class=\"slider-knob-container\" ng-class=\"{'slider-knob-hidden':hideKnob}\">\n" +\r
21805     "        <div class=\"slider-knob\" role=\"slider\" aria-valuemin=\"{{min}}\" aria-valuemax=\"{{max}}\" aria-labelledby=\"{{labelId}}\" aria-valuenow=\"{{currentModelValue}}\" aria-valuetext=\"{{currentModelValue}}{{postAriaLabel}}\" aria-orientation=\"{{verticalSlider ? 'vertical' : 'horizontal'}}\"></div>\n" +\r
21806     "    </div>\n" +\r
21807     "</div>");\r
21808 }]);\r
21809 \r
21810 angular.module("b2bTemplate/spinButton/spinButton.html", []).run(["$templateCache", function($templateCache) {\r
21811   $templateCache.put("b2bTemplate/spinButton/spinButton.html",\r
21812     "<div class=\"btn-group btn-spinbutton-toggle\" ng-class=\"{'disabled': disabledFlag}\">\n" +\r
21813     "    <button type=\"button\" tabindex=\"{{isMobile?'0':'-1'}}\" aria-hidden=\"{{notMobile}}\" class=\"btn btn-secondary btn-prev icon-primary-subtractminimize\" ng-click=\"minus();focusInputSpinButton($event)\" aria-label=\"Remove {{step}}\" aria-controls=\"{{spinButtonId}}\" ng-class=\"{'disabled': isMinusDisabled()}\" ng-disabled=\"isMinusDisabled()\" aria-disabled=\"{{isMinusDisabled()}}\" role=\"spinbutton\"></button>\n" +\r
21814     "    <input class=\"btn pull-left\" id=\"{{spinButtonId}}\" type=\"tel\" b2b-only-nums=\"3\" maxlength=\"3\" min={{min}} max={{max}} data-max-value=\"{{max}}\" ng-model=\"inputValue[inputModelKey]\" value=\"{{inputValue[inputModelKey]}}\" aria-live=\"polite\" aria-valuenow=\"{{inputValue[inputModelKey]}}\" aria-valuemin=\"{{min}}\" aria-valuemax=\"{{max}}\" ng-disabled=\"disabledFlag\">\n" +\r
21815     "    <button type=\"button\" tabindex=\"{{isMobile?'0':'-1'}}\" aria-hidden=\"{{notMobile}}\" class=\"btn btn-secondary btn-next icon-primary-add-maximize\" ng-click=\"plus();focusInputSpinButton($event)\" aria-label=\"Add {{step}}\" aria-controls=\"{{spinButtonId}}\" ng-class=\"{'disabled': isPlusDisabled()}\" ng-disabled=\"isPlusDisabled()\" aria-disabled=\"{{isPlusDisabled()}}\" role=\"spinbutton\"></button>\n" +\r
21816     "</div>");\r
21817 }]);\r
21818 \r
21819 angular.module("b2bTemplate/statusTracker/statusTracker.html", []).run(["$templateCache", function($templateCache) {\r
21820   $templateCache.put("b2bTemplate/statusTracker/statusTracker.html",\r
21821     "<div class=\"b2b-status-tracker row\">\n" +\r
21822     "   <button tabindex=\"0\" ng-disabled=\"currentViewIndex === 0\" ng-if=\"statuses.length > b2bStatusTrackerConfig.maxViewItems\" class=\"btn-arrow\" type=\"button\" aria-label=\"Previous status\" ng-click=\"previousStatus()\">\n" +\r
21823     "       <div class=\"btn btn-small btn-secondary\">\n" +\r
21824     "           <i class=\"icon-primary-left\"></i>\n" +\r
21825     "       </div>\n" +\r
21826     "   </button>\n" +\r
21827     "   <div ng-repeat=\"status in statuses\" class=\"b2b-status-tracker-step\" ng-class=\"{ 'complete' : status.complete, 'current' : currentStatus($index)}\" ng-show=\"isInViewport($index)\">\n" +\r
21828     "       <p class=\"b2b-status-tracker-heading\">{{status.heading}}</p>\n" +\r
21829     "       <div class=\"progress\">\n" +\r
21830     "           <div class=\"progress-bar\">\n" +\r
21831     "               <span class=\"hidden-spoken\">\n" +\r
21832     "                   {{status.complete ? 'Complete' : 'Incomplete'}}\n" +\r
21833     "               </span>\n" +\r
21834     "           </div>\n" +\r
21835     "       </div>\n" +\r
21836     "       <div class=\"b2b-status-tracker-estimate\">\n" +\r
21837     "           <i ng-show=\"status.estimate !== '' && status.estimate !== undefined\" ng-class=\"status.complete ? 'icoControls-approval' : 'icon-misc-time'\"></i> {{status.complete ? 'Complete' : status.estimate}}\n" +\r
21838     "           &nbsp;\n" +\r
21839     "       </div>\n" +\r
21840     "       \n" +\r
21841     "       <div class=\"b2b-status-tracker-description\">\n" +\r
21842     "           {{status.description}}\n" +\r
21843     "       </div>\n" +\r
21844     "   </div>\n" +\r
21845     "   <button tabindex=\"0\" ng-disabled=\"currentViewIndex + b2bStatusTrackerConfig.maxViewItems === statuses.length\" ng-if=\"statuses.length > b2bStatusTrackerConfig.maxViewItems\" class=\"btn-arrow\" type=\"button\" aria-label=\"Next status\" ng-click=\"nextStatus()\">\n" +\r
21846     "       <div class=\"btn btn-small btn-secondary\">\n" +\r
21847     "           <i class=\"icon-primary-right\"></i>\n" +\r
21848     "       </div>\n" +\r
21849     "   </button>\n" +\r
21850     "</div>");\r
21851 }]);\r
21852 \r
21853 angular.module("b2bTemplate/stepTracker/stepTracker.html", []).run(["$templateCache", function($templateCache) {\r
21854   $templateCache.put("b2bTemplate/stepTracker/stepTracker.html",\r
21855     "<div class=\"b2b-step-tracker\">\n" +\r
21856     "    <button class=\"btn-arrow b2b-left-arrow\" ng-click=\"previousStatus()\" ng-disabled=\"currentViewIndex === 0\" ng-if=\"stepsItemsObject.length > b2bStepTrackerConfig.maxViewItems\" aria-label=\"Previous step\">\n" +\r
21857     "       <div class=\"btn btn-left btn-small btn-secondary\"><i class=\"icon-primary-left\"></i></div>\n" +\r
21858     "   </button>\n" +\r
21859     "    <button class=\"btn-arrow b2b-right-arrow\" ng-click=\"nextStatus()\" ng-disabled=\"currentViewIndex + b2bStepTrackerConfig.maxViewItems === stepsItemsObject.length\" ng-if=\"stepsItemsObject.length > b2bStepTrackerConfig.maxViewItems\" aria-label=\"Next step\">\n" +\r
21860     "       <div class=\"btn btn-small btn-right btn-secondary\"><i class=\"icon-primary-right\"></i></div>\n" +\r
21861     "   </button>\n" +\r
21862     "    <ul class=\"b2b-steps\">\n" +\r
21863     "        <li ng-class=\"{'b2b-step-done':$index < currentIndex - 1 ,'b2b-step-on':$index == currentIndex - 1}\" \n" +\r
21864     "            ng-repeat=\"stepsItem in stepsItemsObject\" ng-show=\"isInViewport($index)\">\n" +\r
21865     "           <p class=\"b2b-step-text\" data-sm-text=\"{{stepsItem.dataMobile}}\" data-large-text=\"{{stepsItem.dataDesktop}}\">{{stepsItem.text}}</p>\n" +\r
21866     "            <span class=\"hidden-spoken\">\n" +\r
21867     "                {{($index < currentIndex - 1)? 'Complete. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +\r
21868     "                {{($index == currentIndex - 1)? 'In Progress. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +\r
21869     "                {{($index > currentIndex - 1)? 'Incomplete. '+stepsItem.text+' '+stepsItem.dataMobile:''}}\n" +\r
21870     "            </span>\n" +\r
21871     "        </li>\n" +\r
21872     "    </ul>\n" +\r
21873     "</div>");\r
21874 }]);\r
21875 \r
21876 angular.module("b2bTemplate/switches/switches-spanish.html", []).run(["$templateCache", function($templateCache) {\r
21877   $templateCache.put("b2bTemplate/switches/switches-spanish.html",\r
21878     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +\r
21879     "    <span class=\"btn-slider-on\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"activo\">activo</i></span>\n" +\r
21880     "    <span class=\"switch-handle\"></span>\n" +\r
21881     "    <span class=\"btn-slider-off\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"inactivo\">inactivo</i></span>\n" +\r
21882     "</div>");\r
21883 }]);\r
21884 \r
21885 angular.module("b2bTemplate/switches/switches.html", []).run(["$templateCache", function($templateCache) {\r
21886   $templateCache.put("b2bTemplate/switches/switches.html",\r
21887     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +\r
21888     "    <span class=\"btn-slider-on\">On</span>\n" +\r
21889     "    <span class=\"switch-handle\"></span>\n" +\r
21890     "    <span class=\"btn-slider-off\">Off</span>\n" +\r
21891     "</div>");\r
21892 }]);\r
21893 \r
21894 angular.module("b2bTemplate/tableMessages/tableMessage.html", []).run(["$templateCache", function($templateCache) {\r
21895   $templateCache.put("b2bTemplate/tableMessages/tableMessage.html",\r
21896     "<div class=\"b2b-table-message\">\n" +\r
21897     "    <div class=\"b2b-message\" ng-if=\"msgType === 'noMatchingResults'\">\n" +\r
21898     "        <div class=\"b2b-magnify-glass\"></div>\n" +\r
21899     "        <div>\n" +\r
21900     "            <div ng-transclude></div>\n" +\r
21901     "        </div>\n" +\r
21902     "    </div>\n" +\r
21903     "    <div class=\"b2b-message\" ng-if=\"msgType == 'infoCouldNotLoad'\">\n" +\r
21904     "        <div class=\"icon-primary-alert b2b-alert\" aria-label=\"Oops! The information could not load at this time. Please click link to refresh the page.\"></div>\n" +\r
21905     "        <div>Oops!</div>\n" +\r
21906     "        <div>The information could not load at this time.</div>\n" +\r
21907     "        <div>Please <a href=\"javascript:void(0)\" title=\"Refresh the page\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +\r
21908     "        </div>\n" +\r
21909     "    </div>\n" +\r
21910     "    <div class=\"b2b-message\" ng-if=\"msgType == 'magnifySearch'\">\n" +\r
21911     "        <div class=\"b2b-magnify-glass\"></div>\n" +\r
21912     "        <div>\n" +\r
21913     "            <p class=\"b2b-message-title\">Please input values to\n" +\r
21914     "                <br/> begin your search.</p>\n" +\r
21915     "        </div>\n" +\r
21916     "    </div>\n" +\r
21917     "    <div class=\"b2b-message\" ng-if=\"msgType === 'loadingTable'\">\n" +\r
21918     "        <div class=\"icon-primary-spinner-ddh b2b-loading-dots\"></div>\n" +\r
21919     "        <div ng-transclude></div>\n" +\r
21920     "    </div>\n" +\r
21921     "</div>\n" +\r
21922     "");\r
21923 }]);\r
21924 \r
21925 angular.module("b2bTemplate/tableScrollbar/tableScrollbar.html", []).run(["$templateCache", function($templateCache) {\r
21926   $templateCache.put("b2bTemplate/tableScrollbar/tableScrollbar.html",\r
21927     "<div class=\"b2b-table-scrollbar\">\n" +\r
21928     "    <div class=\"b2b-scrollbar-arrows\">\n" +\r
21929     "        <button class=\"btn-arrow  b2b-scrollbar-arrow-left\" type=\"button\" ng-attr-aria-label=\"{{disableLeft ? 'Scroll Left Disabled' : 'Scroll Left'}}\" ng-click=\"scrollLeft()\" ng-disabled=\"disableLeft\"><div class=\"btn btn-alt\"><i class=\"icon-primary-left\"></i></div></button>\n" +\r
21930     "        <button class=\"btn-arrow b2b-scrollbar-arrow-right\" ng-attr-aria-label=\"{{disableRight ? 'Scroll Right Disabled' : 'Scroll Right'}}\" ng-click=\"scrollRight()\" ng-disabled=\"disableRight\" type=\"button\"><div class=\"btn btn-alt\"><i class=\"icon-primary-right\"></i></div></button>\n" +\r
21931     "    </div>\n" +\r
21932     "    <div class=\"b2b-table-inner-container\">\n" +\r
21933     "        <span ng-transclude></span>\n" +\r
21934     "    </div>\n" +\r
21935     "</div>");\r
21936 }]);\r
21937 \r
21938 angular.module("b2bTemplate/tables/b2bTable.html", []).run(["$templateCache", function($templateCache) {\r
21939   $templateCache.put("b2bTemplate/tables/b2bTable.html",\r
21940     "<table ng-class=\"{'striped': responsive, 'complex-table': responsive && active}\" ng-transclude></table>");\r
21941 }]);\r
21942 \r
21943 angular.module("b2bTemplate/tables/b2bTableBody.html", []).run(["$templateCache", function($templateCache) {\r
21944   $templateCache.put("b2bTemplate/tables/b2bTableBody.html",\r
21945     "<td ng-hide=\"isHidden()\" ng-transclude></td>");\r
21946 }]);\r
21947 \r
21948 angular.module("b2bTemplate/tables/b2bTableHeaderSortable.html", []).run(["$templateCache", function($templateCache) {\r
21949   $templateCache.put("b2bTemplate/tables/b2bTableHeaderSortable.html",\r
21950     "<th scope=\"col\" role=\"columnheader\" aria-sort=\"{{sortPattern !== 'null' && 'none' || sortPattern}}\" aria-label=\"{{headerName}} {{sortable !== 'false' && ': activate to sort' || ' '}} {{sortPattern !== 'null' && '' || sortPattern}}\" tabindex=\"{{sortable !== 'false' && '0' || '-1'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"(sortable !== 'false') && sort();\" ng-hide=\"isHidden()\">\n" +\r
21951     "    <span ng-transclude></span>\n" +\r
21952     "    <i ng-class=\"{'icon-primary-arrows-sort-arrow active': sortPattern === 'ascending', 'icon-primary-arrows-sort-arrow active down': sortPattern === 'descending'}\"></i>\n" +\r
21953     "</th>");\r
21954 }]);\r
21955 \r
21956 angular.module("b2bTemplate/tables/b2bTableHeaderUnsortable.html", []).run(["$templateCache", function($templateCache) {\r
21957   $templateCache.put("b2bTemplate/tables/b2bTableHeaderUnsortable.html",\r
21958     "<th scope=\"col\" ng-hide=\"isHidden()\" ng-transclude></th>");\r
21959 }]);\r
21960 \r
21961 angular.module("b2bTemplate/tabs/b2bTab.html", []).run(["$templateCache", function($templateCache) {\r
21962   $templateCache.put("b2bTemplate/tabs/b2bTab.html",\r
21963     "<li role=\"tab\" aria-selected=\"{{isTabActive()}}\" aria-controls=\"{{tabPanelId}}\" class=\"tab\" \n" +\r
21964     "    ng-class=\"{'active': isTabActive()}\" ng-click=\"clickTab()\" ng-hide=\"tabItem.disabled\">\n" +\r
21965     "    <a href=\"javascript:void(0)\"  tabindex=\"{{(isTabActive() && tabItem.disabled)?-1:0}}\"\n" +\r
21966     "       ng-disabled=\"tabItem.disabled\" aria-expanded=\"{{(isTabActive() && !tabItem.disabled)}}\" \n" +\r
21967     "       b2b-accessibility-click=\"13,32\" ng-transclude></a>\n" +\r
21968     "    <span class=\"hidden-spoken\" ng-if=\"isTabActive()\">Active tab</span>\n" +\r
21969     "</li>");\r
21970 }]);\r
21971 \r
21972 angular.module("b2bTemplate/tabs/b2bTabset.html", []).run(["$templateCache", function($templateCache) {\r
21973   $templateCache.put("b2bTemplate/tabs/b2bTabset.html",\r
21974     "<ul class=\"tabs promo-tabs\" role=\"tablist\" ng-transclude></ul>");\r
21975 }]);\r
21976 \r
21977 angular.module("b2bTemplate/treeNav/groupedTree.html", []).run(["$templateCache", function($templateCache) {\r
21978   $templateCache.put("b2bTemplate/treeNav/groupedTree.html",\r
21979     "<ul role=\"group\">\n" +\r
21980     "    <li aria-expanded=\"{{(member.active?true:false)}}\" role=\"treeitem\" aria-label=\"{{key}}\" ng-repeat='(key,value) in collection | groupBy : \"grpChild\"' b2b-tree-link><a class=\"grp\" ng-class=\"{'active': value.showGroup == true}\" tabindex=\"-1\" href='javascript:void(0);'>{{(key)?key:''}}<span class=\"b2b-tree-node-icon\"><i ng-class=\"{'icon-primary-expanded': value.showGroup == true, 'icon-primary-collapsed': value.showGroup == undefined || value.showGroup == false }\"></i></span></a>\n" +\r
21981     "        <ul role=\"group\">\n" +\r
21982     "            <b2b-member ng-repeat='member in value.childArray' member='member' time-delay='{{timeDelay}}' group-it='groupIt'></b2b-member>\n" +\r
21983     "        </ul>\n" +\r
21984     "    </li>\n" +\r
21985     "</ul>");\r
21986 }]);\r
21987 \r
21988 angular.module("b2bTemplate/treeNav/treeMember.html", []).run(["$templateCache", function($templateCache) {\r
21989   $templateCache.put("b2bTemplate/treeNav/treeMember.html",\r
21990     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.tooltipContent ? member.tooltipContent : member.name}}\" aria-describedby=\"description_{{$id}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-link>\n" +\r
21991     "    <a tabindex=\"-1\" title=\"{{member.tooltipContent ? member.tooltipContent : member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active,'b2b-locked-node':member.locked}\">       <span class=\"b2b-tree-node-name\">{{member.name}}</span>\n" +\r
21992     "        <span class=\"{{!member.child?'end':''}} b2b-tree-node-icon\">\n" +\r
21993     "            <i class=\"b2b-tree-expandCollapse-icon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +\r
21994     "        </span>\n" +\r
21995     "         <div id=\"description_{{$id}}\" class=\"offscreen-text\">\n" +\r
21996     "           {{member.descriptionText}}\n" +\r
21997     "        </div>\n" +\r
21998     "        <div class=\"b2b-tree-tooltip\" ng-if=\"member.showTooltip\">\n" +\r
21999     "           <span class=\"b2b-tree-arrow-left\"></span>\n" +\r
22000     "           <div class=\"b2b-tree-tooltip-content\">\n" +\r
22001     "               {{member.tooltipContent}}\n" +\r
22002     "           </div>  \n" +\r
22003     "        </div>\n" +\r
22004     "    </a>\n" +\r
22005     "</li>");\r
22006 }]);\r
22007 \r
22008 angular.module("b2bTemplate/treeNav/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {\r
22009   $templateCache.put("b2bTemplate/treeNav/ungroupedTree.html",\r
22010     "<ul role=\"{{setRole}}\"><b2b-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-member></ul>");\r
22011 }]);\r
22012 \r
22013 angular.module("b2bTemplate/treeNodeCheckbox/groupedTree.html", []).run(["$templateCache", function($templateCache) {\r
22014   $templateCache.put("b2bTemplate/treeNodeCheckbox/groupedTree.html",\r
22015     "<ul role=\"group\">\n" +\r
22016     "    <li aria-expanded=\"{{(member.active?true:false)}}\" role=\"treeitem\" aria-label=\"{{key}}\" ng-repeat='(key,value) in collection | groupBy : \"grpChild\"' b2b-tree-node-link><a class=\"grp\" ng-class=\"{'active': value.showGroup == true}\" tabindex=\"-1\" href='javascript:void(0);'>\n" +\r
22017     "        <span class=\"ng-hide\">\n" +\r
22018     "            <label class=\"checkbox\">\n" +\r
22019     "                <input type=\"checkbox\" tabindex=\"-1\" class=\"treeCheckBox grpTreeCheckbox\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{(key)?key:''}}</span>\n" +\r
22020     "            </label>\n" +\r
22021     "        </span>\n" +\r
22022     "        <span>\n" +\r
22023     "            {{(key)?key:''}}    \n" +\r
22024     "        </span>\n" +\r
22025     "        <span class=\"nodeIcon\"><i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded': value.showGroup == true, 'icon-primary-collapsed': value.showGroup == undefined || value.showGroup == false }\"></i></span></a>\n" +\r
22026     "        <ul role=\"group\">\n" +\r
22027     "            <b2b-tree-member ng-repeat='member in value.childArray' member='member' group-it='groupIt'></b2b-tree-member>\n" +\r
22028     "        </ul>\n" +\r
22029     "    </li>\n" +\r
22030     "</ul>");\r
22031 }]);\r
22032 \r
22033 angular.module("b2bTemplate/treeNodeCheckbox/treeMember.html", []).run(["$templateCache", function($templateCache) {\r
22034   $templateCache.put("b2bTemplate/treeNodeCheckbox/treeMember.html",\r
22035     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.name}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-node-link>\n" +\r
22036     "    <a tabindex=\"-1\" title=\"{{member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active}\">\n" +\r
22037     "       <span ng-show=\"member.displayCheckbox\">\n" +\r
22038     "               <label class=\"checkbox\">\n" +\r
22039     "                <input type=\"checkbox\" tabindex=\"-1\" ng-model=\"member.isSelected\" ng-class=\"{'treeCheckBox': (member.displayCheckbox !== undefined)}\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{member.name}}</span>\n" +\r
22040     "            </label>\n" +\r
22041     "        </span>\n" +\r
22042     "       <span ng-show=\"!member.displayCheckbox\">\n" +\r
22043     "           {{member.name}} \n" +\r
22044     "       </span>\n" +\r
22045     "        <span class=\"nodeIcon {{!member.child?'end':''}}\">\n" +\r
22046     "            <i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +\r
22047     "        </span>\n" +\r
22048     "    </a>\n" +\r
22049     "</li>");\r
22050 }]);\r
22051 \r
22052 angular.module("b2bTemplate/treeNodeCheckbox/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {\r
22053   $templateCache.put("b2bTemplate/treeNodeCheckbox/ungroupedTree.html",\r
22054     "<ul role=\"{{setRole}}\"><b2b-tree-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-tree-member></ul>");\r
22055 }]);\r