[PORTAL-7] Rebase
[portal.git] / ecomp-portal-FE-os / 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             }\r
3624         };\r
3625     }]).directive('b2bHeaderSubmenu', ['$timeout',function ($timeout) {\r
3626         return{\r
3627             restrict: 'A',\r
3628             link: function (scope, elem) {\r
3629                 var caretSign = angular.element("<i class='menuCaret'></i>");\r
3630                 $timeout(function(){\r
3631                     var menuItem = angular.element(elem[0].children[0]);\r
3632                     menuItem.bind('focus mouseenter', function () {\r
3633                         elem.parent().children().removeClass('active');\r
3634                         elem.addClass('active');\r
3635                         if(elem[0].childElementCount > 1){ // > 1 has third level menu\r
3636                             menuItem.attr('aria-expanded',true);\r
3637                             menuItem.attr('aria-haspopup',true);\r
3638                         }\r
3639                         var caretLeft = (elem[0].offsetLeft +  elem[0].offsetWidth/2) - 10;\r
3640                         caretSign.css({left: caretLeft + 'px'});\r
3641                         angular.element(caretSign);\r
3642                         var tertiaryItems = elem[0].querySelectorAll('[b2b-header-tertiarymenu]');\r
3643                         if(tertiaryItems.length >=1){\r
3644                             elem.append(caretSign);\r
3645                         }\r
3646                     });\r
3647                     menuItem.bind('blur', function () {\r
3648                         $timeout(function () {\r
3649                             var parentElm = document.activeElement.parentElement.parentElement;\r
3650                             if(parentElm){\r
3651                                 if (!(parentElm.hasAttribute('b2b-header-tertiarymenu'))) {\r
3652                                     elem.removeClass('active');\r
3653                                     if(elem[0].childElementCount > 1){ // > 1 has third level menu\r
3654                                         menuItem.attr('aria-expanded',false);\r
3655                                     }\r
3656                                     var caret = elem[0].querySelector('.menuCaret');\r
3657                                     if(caret){\r
3658                                         caret.remove();\r
3659                                     }   \r
3660                                 }\r
3661                             }\r
3662                         });\r
3663                     });\r
3664                 });\r
3665             }\r
3666         };\r
3667     }]).directive('b2bHeaderTertiarymenu', ['$timeout','keymap', function ($timeout,keymap){\r
3668         return{\r
3669             restrict: 'A',\r
3670             require:'^b2bHeaderMenu',\r
3671             link: function (scope, elem,attr,ctrl) {\r
3672                 \r
3673                 elem.bind('keydown', function (evt) {\r
3674                     var activeElm = document.activeElement;\r
3675                     var activeParentElm = activeElm.parentElement;\r
3676                     var activeParentObj  = angular.element(activeParentElm)[0];\r
3677                     \r
3678                     if(activeParentElm.hasAttribute('b2b-tertiary-link')){\r
3679                         var quarterNav = angular.element(activeParentElm)[0].querySelector('li[b2b-header-quarternarymenu]');\r
3680                         if(quarterNav){\r
3681                             var links = ctrl.getFirstElement(angular.element(quarterNav)[0],'a');\r
3682                         }\r
3683                     }\r
3684                     var tertiaryMenu = activeElm.parentElement.parentElement.parentElement;\r
3685                     var tertiaryMenuFlag = tertiaryMenu.hasAttribute('b2b-tertiary-link');\r
3686                     \r
3687                     switch (evt.keyCode) {\r
3688                         case keymap.KEY.DOWN:\r
3689                             evt.stopPropagation();\r
3690                             evt.preventDefault();\r
3691                             if (activeParentElm.hasAttribute('b2b-tertiary-link')) {\r
3692                                 if(angular.element(quarterNav).hasClass('active')){\r
3693                                     links.focus();\r
3694                                 }else if(activeParentObj.nextElementSibling){\r
3695                                     ctrl.nextSiblingFocus(activeParentObj,true);\r
3696                                 }\r
3697                             }\r
3698                             else if(angular.element(activeParentElm).hasClass('active')){\r
3699                                 ctrl.nextSiblingFocus(activeElm);\r
3700                             }\r
3701                             break;                        \r
3702                         case keymap.KEY.UP:\r
3703                             evt.stopPropagation();\r
3704                             evt.preventDefault();\r
3705                             if(activeParentElm.hasAttribute('b2b-tertiary-link')){\r
3706                                 if(activeParentObj.previousElementSibling.hasAttribute('b2b-tertiary-link')){\r
3707                                     ctrl.previousSiblingFocus(activeParentObj,true);\r
3708                                 }else{\r
3709                                     var elm = angular.element(activeElm.parentElement.parentElement.parentElement.parentElement.parentElement)[0];\r
3710                                     ctrl.getFirstElement(elm,"a").focus();\r
3711                                 }\r
3712                             }else if(angular.element(activeParentElm).hasClass('active')){\r
3713                                     if (activeElm.previousElementSibling) {\r
3714                                         ctrl.previousSiblingFocus(activeElm);\r
3715                                     }else if (tertiaryMenuFlag) {\r
3716                                         var elm = angular.element(tertiaryMenu)[0];\r
3717                                         ctrl.getFirstElement(elm,"a.header-tertiaryitem").focus();\r
3718                                     }\r
3719                                 }\r
3720                             break;\r
3721                         default:\r
3722                             break;\r
3723                     }\r
3724                 });\r
3725             }            \r
3726         };          \r
3727     }]).directive('b2bHeaderTogglemenu', ['$timeout', 'keymap', function ($timeout, keymap) {\r
3728         return{\r
3729             restrict: 'A',\r
3730             require: '^b2bHeaderMenu',\r
3731             link: function (scope, elem, attrs, ctrl) {\r
3732                 var quarterNav;\r
3733                 $timeout(function () {\r
3734                     quarterNav = angular.element(elem.parent())[0].querySelector('li[b2b-header-quarternarymenu]');\r
3735                     elem.bind('click', function () {\r
3736                         angular.element(quarterNav).toggleClass('active');\r
3737                     });\r
3738                 });\r
3739             }\r
3740         };\r
3741     }]).directive('b2bHeaderResponsive', ['$timeout',function ($timeout) {\r
3742         return{\r
3743             restrict: 'A',\r
3744             controller: function($scope){\r
3745                 this.applyMediaQueries = function(value){\r
3746                     document.querySelector('style').textContent += \r
3747                         "@media screen and (max-width:950px) { \\r
3748                             .header__item.profile { right: " + value + "px; } \\r
3749                         }";\r
3750                 };\r
3751                 this.arrangeResponsiveHeader = function(children){\r
3752                     /* \r
3753                      * clientWidth of 1090 === max-width of 1100px\r
3754                      * clientWidth of 920 === max-width of 950px\r
3755                      * see b2b-angular.css for rest of responsive header CSS\r
3756                      */\r
3757                   if (document.documentElement.clientWidth <= 920) { \r
3758                         switch(children){\r
3759                             case 1:\r
3760                                 this.applyMediaQueries(200);                    \r
3761                                 break;\r
3762                             case 2:\r
3763                                 this.applyMediaQueries(200);                            \r
3764                                 break;\r
3765                             default: // anthing above 3, however, should not have more than 3 to date\r
3766                                 this.applyMediaQueries(200);                                                                            \r
3767                         }\r
3768                     }\r
3769                 }\r
3770             },\r
3771             link: function (scope, elem, attrs, ctrl) {\r
3772                 var children;\r
3773                 var profile;\r
3774                 \r
3775                 // onload of page\r
3776                 $timeout(function(){ \r
3777                     profile = document.querySelector('li.header__item.profile');\r
3778                     children = angular.element(profile).children().length;\r
3779                     \r
3780                     ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers\r
3781                 });\r
3782 \r
3783                 // on screen resize\r
3784                 window.addEventListener('resize', function(event){ // caret adjustmet\r
3785                     var activeSubmenu = elem[0].querySelector('[b2b-header-menu] [b2b-header-submenu].active');\r
3786                     var activeSubmenuEl = angular.element(activeSubmenu);\r
3787                     if(activeSubmenu){\r
3788                         var caretSign = activeSubmenu.querySelector('i.menuCaret');\r
3789                         if(caretSign){\r
3790                             var caretSignEl = angular.element(caretSign);\r
3791                             var caretLeft = (activeSubmenu.offsetLeft +  activeSubmenu.offsetWidth/2) - 10;\r
3792                             caretSignEl.css({left: caretLeft + 'px'});\r
3793                         }\r
3794                     }\r
3795 \r
3796                     ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers\r
3797                 });\r
3798             }\r
3799         };\r
3800     }]);\r
3801 \r
3802 /**\r
3803  * @ngdoc directive\r
3804  * @name Layouts.att:headings\r
3805  *\r
3806  * @description\r
3807  *  <file src="src/headings/docs/readme.md" />\r
3808  *\r
3809  * @usage\r
3810     <h1 class="heading-page">38px page heading</h1>\r
3811     <h2 class="heading-major-section">30px major section heading</h2>\r
3812     <h3 class="heading-sub-section">24px sub-section heading</h3>\r
3813     <h2 class="heading-medium">20px medium heading</h2>\r
3814     <h2 class="heading-medium-emphasis">20px medium emphasis heading</h2>\r
3815     <h3 class="heading-small">18px small heading</h3>\r
3816     <h3 class="heading-small-emphasis">18px small emphasis heading</h3>\r
3817     <h3 class="heading-micro">13px micro heading</h3>\r
3818 \r
3819     <h2 class="heading-group">Lead</h2>\r
3820     <h1 class="heading-page">This is 38px heading</h1>\r
3821     <h2 class="lead">This is lead text...The next big thing since the last big thing we announced.</h2>\r
3822     <h2 class="heading-group">Eyebrow</h2>\r
3823     <h3 class="eyebrow">EYEBROW TEXT</h3>\r
3824     <h2 class="heading-major-section">This is a 30px heading</h2>\r
3825     <h3 class="eyebrow">EYEBROW TEXT</h3>\r
3826     <h3 class="heading-sub-section">24px sub-section heading</h3>\r
3827     <h2 class="heading-group">Subheading</h2>\r
3828     <h2 class="heading-major-section">This is a 30px heading</h2>\r
3829     <h3 class="subheading">A subheading here to support what was said above</h3>\r
3830  * @example\r
3831  <section id="code">\r
3832     <b>HTML + AngularJS</b>\r
3833     <example module="b2b.att">\r
3834     <file src="src/headings/docs/demo.html" />\r
3835 </example>\r
3836 </section>\r
3837  */\r
3838 \r
3839 var b2bLegalCopy = angular.module('b2b.att.headings', []);\r
3840 /**\r
3841  * @ngdoc directive\r
3842  * @name Tabs, tables & accordions.att:horizontalTable\r
3843  *\r
3844  * @description\r
3845  *  <file src="src/horizontalTable/docs/readme.md" />\r
3846  *\r
3847  * @usage\r
3848  * @param {int} sticky - Number of sticky columns to have. Maximum of 3.\r
3849  * @param {boolean} refresh - A boolean that when set to true will force a re-render of table. Only use when using 'bulk mode'\r
3850  * @example\r
3851  *  <section id="code">\r
3852         <example module="b2b.att">\r
3853             <file src="src/horizontalTable/docs/demo.html" />\r
3854             <file src="src/horizontalTable/docs/demo.js" />\r
3855        </example>\r
3856     </section>\r
3857  *\r
3858  */\r
3859 angular.module('b2b.att.horizontalTable', [])\r
3860     .constant('b2bHorizontalTableConfig', {\r
3861         'maxStickyColumns': 3\r
3862     })\r
3863     .directive('b2bHorizontalTable', ['$timeout', 'b2bHorizontalTableConfig', 'b2bDOMHelper', function ($timeout, b2bHorizontalTableConfig, b2bDOMHelper) {\r
3864         return {\r
3865             restrict: 'EA',\r
3866             scope: true,\r
3867             transclude: true,\r
3868             scope: {\r
3869                 numOfStickyCols: '=?sticky',\r
3870                 refresh: '=?'\r
3871 \r
3872             },\r
3873             templateUrl: 'b2bTemplate/horizontalTable/horizontalTable.html',\r
3874             link: function (scope, element, attrs, ctrl) {\r
3875                 scope.numOfStickyCols = scope.numOfStickyCols || 1;\r
3876                 scope.viewportIndex = scope.numOfStickyCols;\r
3877 \r
3878                 // JM520E: This is a temporary hack until I solve the ngRepeat issue\r
3879                 function hack() {\r
3880                     if (element.find('th').length < scope.numOfStickyCols) {\r
3881                         // DOM ngRepeat is not ready, let's check back in 10 ms\r
3882                         console.info('THs are not ready, trying again in 10ms');\r
3883                         $timeout(hack, 10, false);\r
3884                     } else {\r
3885                         init();\r
3886                     }\r
3887                 }\r
3888                 hack();\r
3889 \r
3890                 if (attrs.refresh !== undefined && attrs.refresh !== '') {\r
3891                     scope.$watch('refresh', function(oldVal, newVal) {\r
3892                         if (scope.refresh) {\r
3893                             // From testing it takes about 30 ms before ngRepeat executes, so let's set initial timeout\r
3894                             // NOTE: May need to expose timeout to developers. Application is known to have digest cycle of 3-5k watches.\r
3895                             $timeout(init, 100, false);\r
3896                             scope.refresh = false;\r
3897                         }\r
3898                     });\r
3899                 }\r
3900 \r
3901                 var tableElement = element.find('table');\r
3902                 var thElements = element.find('th');\r
3903                 var innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));\r
3904                 var outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));\r
3905 \r
3906                 var tableColumns = [];\r
3907                 var tableRows = element.find('tr');\r
3908 \r
3909                 var maxWidth = 0,\r
3910                     maxHeight = 0;\r
3911                 var totalWidth = element.children()[0].offsetWidth;\r
3912                 var lastVisibleColumn = 0;\r
3913                 var collectiveColumnWidth = [];\r
3914                 var collectiveRowHeight = [];\r
3915                 var columnSets = [];\r
3916                 var setIndex = 0; \r
3917                 var stickyPixels = 0;\r
3918 \r
3919                 var displayNoneCSS = {'display': 'none'};\r
3920                 var displayBlockCSS = {'display': 'table-cell'};\r
3921 \r
3922                 function calculateVisibleColumns(startingPoint) {\r
3923                     var usedWidth = 0, \r
3924                         visibleColumns = startingPoint || scope.numOfStickyCols;\r
3925 \r
3926                     while(usedWidth < stickyPixels && visibleColumns < collectiveColumnWidth.length) {\r
3927                         if (usedWidth+collectiveColumnWidth[visibleColumns] > stickyPixels) {\r
3928                             if (startingPoint === visibleColumns) {\r
3929                                 return visibleColumns; // The next cell is too large to fit, it should be only thing to fit\r
3930                             }\r
3931                             visibleColumns--;\r
3932                             return visibleColumns;\r
3933                         }\r
3934                         usedWidth += collectiveColumnWidth[visibleColumns];\r
3935                         visibleColumns++;\r
3936                     }\r
3937 \r
3938                     if (usedWidth > stickyPixels) {\r
3939                         return --visibleColumns;\r
3940                     }\r
3941                     return visibleColumns;\r
3942                 }\r
3943 \r
3944                 function updateCellDisplay(set) {\r
3945                     for (var i = scope.numOfStickyCols; i < tableColumns.length; i++) {\r
3946                         angular.element(tableColumns[i]).css(displayNoneCSS);\r
3947                     }\r
3948 \r
3949                     for (var i = set[0]; i <= set[1]; i++) {\r
3950                         angular.element(tableColumns[i]).css(displayBlockCSS);\r
3951                     }\r
3952                 }\r
3953 \r
3954                 function forceDigest() {\r
3955                     if (!scope.$$phase) {\r
3956                         scope.$digest();\r
3957                     }\r
3958                 }\r
3959 \r
3960                 function findMax(arr, prop) {\r
3961                     var max = 0;\r
3962                     var localVal = 0;\r
3963                     var prevDisplay;\r
3964                     var item;\r
3965                     for (var i = 0; i < arr.length; i++) {\r
3966                         item = arr[i];\r
3967                         prevDisplay = angular.element(item).css('display');\r
3968                         if (scope.$$phase) {\r
3969                             scope.$digest();\r
3970                         }\r
3971                         if (prop === 'width') {\r
3972                             localVal = Math.ceil(parseInt(window.getComputedStyle(item).width.split('px')[0], 10)) + 30; // 30 px is padding\r
3973                         } else if (prop === 'offsetWidth') {\r
3974                             localVal = item.offsetWidth;\r
3975                         } else if (prop === 'height') {\r
3976                             localVal = item.offsetHeight;\r
3977                         }\r
3978 \r
3979                         if (localVal >= max) {\r
3980                             max = localVal;\r
3981                         }\r
3982                     }\r
3983                     \r
3984                     return max;\r
3985                 }\r
3986 \r
3987                 function init() {\r
3988                     // Reset this from a previous execution\r
3989                     tableColumns = [];\r
3990                     collectiveColumnWidth = [];\r
3991                     collectiveRowHeight = [];\r
3992                     maxWidth = 0;\r
3993                     maxHeight = 0;\r
3994                     lastVisibleColumn = 0;\r
3995                     columnSets = [];\r
3996                     setIndex = 0; \r
3997                     visibleColumns = [];\r
3998                     stickyPixels = 0;\r
3999 \r
4000                     tableElement = element.find('table');\r
4001                     thElements = element.find('th');\r
4002                     innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));\r
4003                     outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));\r
4004                     totalWidth = element.children()[0].offsetWidth;\r
4005 \r
4006 \r
4007                     tableRows = element.find('tr');\r
4008                     totalWidth = element.children()[0].offsetWidth;\r
4009 \r
4010                     scope.disableLeft = true;\r
4011                     scope.disableRight = false;\r
4012 \r
4013                     if (scope.numOfStickyCols > b2bHorizontalTableConfig.maxStickyColumns) {\r
4014                         throw new Error("Table can only support 3 sticky columns.");\r
4015                     }                  \r
4016 \r
4017                     angular.forEach(tableRows, function(row, rowIndex) {\r
4018                         collectiveRowHeight.push(findMax(row.children, 'height'));\r
4019                         for(var j = 0; j < row.children.length; j++) {\r
4020                             if (tableColumns[j] === undefined) {\r
4021                                 tableColumns[j] = [];\r
4022                             }\r
4023                             tableColumns[j].push(row.children[j]);\r
4024                         }\r
4025                     });\r
4026 \r
4027                     // We need to reset all the displayNones from previous runs, if applicable\r
4028                     if (attrs.refresh !== undefined && attrs.refresh !== '')  {\r
4029                         for (var i = scope.numOfStickyCols+1; i < tableColumns.length; i++) {\r
4030                             angular.element(tableColumns[i]).css(displayBlockCSS);\r
4031                         }\r
4032                     }\r
4033 \r
4034                     for (var i = 0; i < tableColumns.length; i++) {\r
4035                         collectiveColumnWidth.push(findMax(tableColumns[i], 'width')); //offsetWidth doesn't take into account custom css inside\r
4036                     }\r
4037                     for(var i = 0; i < scope.numOfStickyCols; i++) {\r
4038                         maxWidth += collectiveColumnWidth[i];\r
4039                     }\r
4040       \r
4041                     stickyPixels = totalWidth-maxWidth;\r
4042 \r
4043 \r
4044                     // At this point, for each tr, I need to set the properties (height) and each numOfStickyCols children\r
4045                     // should be set with sticky properties (margin-left and width)\r
4046                     var width = maxWidth;\r
4047                     for(var i = 0; i < scope.numOfStickyCols; i++) {\r
4048                         for (var j = 0; j < tableRows.length; j++) {\r
4049                             trObject = angular.element(tableRows[j].children[i]);\r
4050                             \r
4051                             angular.element(trObject).css({\r
4052                                 'margin-left': -(width + 2) + 'px', \r
4053                                 'width': (collectiveColumnWidth[i] + 3) + 'px', // instead of taking the max width, grab max width for that column\r
4054                                 'height': collectiveRowHeight[j] + 'px',\r
4055                                 'position': 'absolute',\r
4056                                 'background-color': 'lightgrey'\r
4057                             });\r
4058                         }\r
4059                         \r
4060 \r
4061                         width -= collectiveColumnWidth[i];\r
4062                     }\r
4063 \r
4064                     innerContainer.css({\r
4065                         'padding-left': (maxWidth + 2) + 'px'\r
4066                     });\r
4067 \r
4068 \r
4069                     // Let's precompute all the (set) combinations beforehand\r
4070                     columnSets = []; \r
4071                     for (var i = scope.numOfStickyCols; i < tableColumns.length;) {\r
4072                         visibleColumns = calculateVisibleColumns(i);\r
4073                         columnSets.push([i, visibleColumns]);\r
4074                         i = visibleColumns + 1;\r
4075                     }\r
4076                     \r
4077                     updateCellDisplay(columnSets[setIndex]);\r
4078                     checkScrollArrows();\r
4079 \r
4080                     scope.numOfCols = tableColumns.length;\r
4081 \r
4082                     console.log('Bulk Mode is ' + (attrs.bulkMode ? 'enabled': 'disabled'));\r
4083                     console.log('tableColumns', tableColumns);\r
4084                     console.log('collectiveColumnWidth: ', collectiveColumnWidth);\r
4085                     console.log('maxWidth: ', maxWidth);\r
4086                 }\r
4087 \r
4088                 function checkScrollArrows() {\r
4089                     scope.disableLeft = (setIndex === 0);\r
4090                     scope.disableRight = !(setIndex < columnSets.length-1);\r
4091                 }\r
4092 \r
4093 \r
4094                 scope.moveViewportLeft = function () {\r
4095                     setIndex--;\r
4096                     updateCellDisplay(columnSets[setIndex]);\r
4097                     checkScrollArrows();\r
4098 \r
4099                     if (scope.disableLeft) {\r
4100                         element.find('span')[0].focus();\r
4101                     }\r
4102                 };\r
4103                 \r
4104                 scope.moveViewportRight = function () {\r
4105                     setIndex++;\r
4106                     updateCellDisplay(columnSets[setIndex]);\r
4107                     checkScrollArrows();\r
4108                     \r
4109                     if (scope.disableRight) {\r
4110                         element.find('span')[0].focus();\r
4111                     }\r
4112                 };\r
4113 \r
4114                 scope.getColumnSet = function () {\r
4115                     return columnSets[setIndex];\r
4116                 };\r
4117 \r
4118                 innerContainer.bind('scroll', function () {\r
4119                     $timeout(function () {\r
4120                         checkScrollArrows();\r
4121                     }, 1);\r
4122                 });\r
4123 \r
4124             }\r
4125         };\r
4126     }]);\r
4127 /**\r
4128  * @ngdoc directive\r
4129  * @name Forms.att:hourPicker\r
4130  *\r
4131  * @description\r
4132  *  <file src="src/hourPicker/docs/readme.md" />\r
4133  *\r
4134  * @usage\r
4135  * <div b2b-hourpicker ng-model="hourpickerValue.value"></div>\r
4136     \r
4137  * @example\r
4138  *  <section id="code">\r
4139         <example module="b2b.att">\r
4140             <file src="src/hourPicker/docs/demo.html" />\r
4141             <file src="src/hourPicker/docs/demo.js" />\r
4142         </example>\r
4143     </section>\r
4144  *\r
4145  */\r
4146 angular.module('b2b.att.hourPicker', ['b2b.att.utilities'])\r
4147 \r
4148 .constant('b2bHourpickerConfig', {\r
4149     dayOptions: [{\r
4150         title: 'sunday',\r
4151         caption: 'Sun',\r
4152         label: 'S',\r
4153         disabled: false\r
4154     }, {\r
4155         title: 'monday',\r
4156         caption: 'Mon',\r
4157         label: 'M',\r
4158         disabled: false\r
4159     }, {\r
4160         title: 'tuesday',\r
4161         caption: 'Tues',\r
4162         label: 'T',\r
4163         disabled: false\r
4164     }, {\r
4165         title: 'wednesday',\r
4166         caption: 'Wed',\r
4167         label: 'W',\r
4168         disabled: false\r
4169     }, {\r
4170         title: 'thursday',\r
4171         caption: 'Thu',\r
4172         label: 'T',\r
4173         disabled: false\r
4174     }, {\r
4175         title: 'friday',\r
4176         caption: 'Fri',\r
4177         label: 'F',\r
4178         disabled: false\r
4179     }, {\r
4180         title: 'saturday',\r
4181         caption: 'Sat',\r
4182         label: 'S',\r
4183         disabled: false\r
4184     }],\r
4185     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
4186     startTimeDefaultOptionIndex: -1,\r
4187     startTimeDefaultMeridiem: "am",\r
4188     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
4189     endTimeDefaultOptionIndex: -1,\r
4190     endTimeDefaultMeridiem: "pm",\r
4191     sameDayOption: true\r
4192 })\r
4193 \r
4194 .factory('b2bNormalizeHourpickerValues', [function () {\r
4195     var _normalize = function (hourpickerValues) {\r
4196         if (angular.isDefined(hourpickerValues) && hourpickerValues != null) {\r
4197             var finalHourpickerValues = [];\r
4198             var hourpickerValue = {};\r
4199             var days = {};\r
4200             for (var i = 0; i < hourpickerValues.length; i++) {\r
4201                 days = hourpickerValues[i].days ? hourpickerValues[i].days : {};\r
4202                 hourpickerValue.startTime = hourpickerValues[i].startTime ? hourpickerValues[i].startTime : '';\r
4203                 hourpickerValue.startMeridiem = hourpickerValues[i].startMeridiem ? hourpickerValues[i].startMeridiem : '';\r
4204                 hourpickerValue.endTime = hourpickerValues[i].endTime ? hourpickerValues[i].endTime : '';\r
4205                 hourpickerValue.endMeridiem = hourpickerValues[i].endMeridiem ? hourpickerValues[i].endMeridiem : '';\r
4206                 hourpickerValue.days = [];\r
4207 \r
4208                 var retrieveDaysText = function (daysDetails) {\r
4209                     var daysTexts = [];\r
4210                     var first = -1;\r
4211                     var last = -1;\r
4212                     var index = -1;\r
4213                     for (var i in days) {\r
4214                         if (days[i].value) {\r
4215                             daysTexts.push(i);\r
4216                         }\r
4217                     }\r
4218 \r
4219                     first = daysTexts[0];\r
4220                     last = daysTexts[0];\r
4221                     index = 0;\r
4222                     hourpickerValue.days[index] = days[first].caption;\r
4223                     if (daysTexts.length > 1) {\r
4224                         for (var i = 1; i < daysTexts.length; i++) {\r
4225                             if (daysTexts[i] - last === 1) {\r
4226                                 last = daysTexts[i];\r
4227                                 hourpickerValue.days[index] = days[first].caption + ' - ' + days[last].caption;\r
4228                             } else {\r
4229                                 index++;\r
4230                                 first = last = daysTexts[i];\r
4231                                 hourpickerValue.days[index] = days[first].caption;\r
4232                             }\r
4233                         }\r
4234                     }\r
4235                 };\r
4236                 retrieveDaysText();\r
4237 \r
4238                 finalHourpickerValues.push(angular.copy(hourpickerValue));\r
4239             }\r
4240 \r
4241             return angular.copy(finalHourpickerValues);\r
4242         }\r
4243     };\r
4244 \r
4245     return {\r
4246         normalize: _normalize\r
4247     };\r
4248 }])\r
4249 \r
4250 .directive('b2bHourpicker', ['b2bHourpickerConfig', 'b2bNormalizeHourpickerValues', function (b2bHourpickerConfig, b2bNormalizeHourpickerValues) {\r
4251     return {\r
4252         restrict: 'EA',\r
4253         replace: false,\r
4254         scope: true,\r
4255         require: 'ngModel',\r
4256         templateUrl: 'b2bTemplate/hourPicker/b2bHourpicker.html',\r
4257         controller: ['$scope', function (scope) {\r
4258 \r
4259         }],\r
4260         link: function (scope, elem, attr, ctrl) {\r
4261             scope.hourpicker = {};\r
4262             scope.hourpicker.dayOptions = attr.dayOptions ? scope.$parent.$eval(attr.dayOptions) : b2bHourpickerConfig.dayOptions;\r
4263             scope.hourpicker.startTimeOptions = attr.startTimeOptions ? scope.$parent.$eval(attr.startTimeOptions) : b2bHourpickerConfig.startTimeOptions;\r
4264             scope.hourpicker.endTimeOptions = attr.endTimeOptions ? scope.$parent.$eval(attr.endTimeOptions) : b2bHourpickerConfig.endTimeOptions;\r
4265             scope.hourpicker.startTimeDefaultOptionIndex = attr.startTimeDefaultOptionIndex ? scope.$parent.$eval(attr.startTimeDefaultOptionIndex) : b2bHourpickerConfig.startTimeDefaultOptionIndex;\r
4266             scope.hourpicker.endTimeDefaultOptionIndex = attr.endTimeDefaultOptionIndex ? scope.$parent.$eval(attr.endTimeDefaultOptionIndex) : b2bHourpickerConfig.endTimeDefaultOptionIndex;\r
4267             scope.hourpicker.startTimeDefaultMeridiem = attr.startTimeDefaultMeridiem ? scope.$parent.$eval(attr.startTimeDefaultMeridiem) : b2bHourpickerConfig.startTimeDefaultMeridiem;\r
4268             scope.hourpicker.endTimeDefaultMeridiem = attr.endTimeDefaultMeridiem ? scope.$parent.$eval(attr.endTimeDefaultMeridiem) : b2bHourpickerConfig.endTimeDefaultMeridiem;\r
4269             scope.hourpicker.sameDayOption = attr.sameDayOption ? scope.$parent.$eval(attr.sameDayOption) : b2bHourpickerConfig.sameDayOption;\r
4270             scope.hourpicker.editMode = -1;\r
4271 \r
4272             scope.hourpickerValues = [];\r
4273             scope.finalHourpickerValues = [];\r
4274             scope.addHourpickerValue = function (hourpickerPanelValue) {\r
4275                 if (hourpickerPanelValue) {\r
4276                     if (scope.hourpicker.editMode > -1) {\r
4277                         scope.hourpickerValues[scope.hourpicker.editMode] = hourpickerPanelValue;\r
4278                         scope.hourpicker.editMode = -1;\r
4279                     } else {\r
4280                         scope.hourpickerValues.push(hourpickerPanelValue);\r
4281                     }\r
4282                 }\r
4283                 scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));\r
4284                 ctrl.$setViewValue(angular.copy(scope.hourpickerValues));\r
4285             };\r
4286             ctrl.$render = function () {\r
4287                 if (angular.isDefined(ctrl.$modelValue)) {\r
4288                     scope.hourpickerValues = angular.copy(ctrl.$modelValue);\r
4289                     scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));\r
4290                 }\r
4291             };\r
4292             scope.editHourpickerValue = function (index) {\r
4293                 scope.hourpickerPanelValue = angular.copy(scope.hourpickerValues[index]);\r
4294                 scope.hourpicker.editMode = index;\r
4295             };\r
4296             scope.deleteHourpickerValue = function (index) {\r
4297                 scope.hourpickerValues.splice(index, 1);\r
4298                 scope.resetHourpickerPanelValue();\r
4299                 scope.addHourpickerValue();\r
4300             };\r
4301 \r
4302             scope.setValidity = function (errorType, errorValue) {\r
4303                 ctrl.$setValidity(errorType, errorValue);\r
4304             }\r
4305         }\r
4306     }\r
4307 }])\r
4308 \r
4309 .directive('b2bHourpickerPanel', [function () {\r
4310     return {\r
4311         restrict: 'EA',\r
4312         replace: false,\r
4313         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerPanel.html',\r
4314         controller: ['$scope', function (scope) {\r
4315 \r
4316         }],\r
4317         link: function (scope, elem, attr, ctrl) {\r
4318             var hourpickerPanelValueTemplate = {\r
4319                 days: {},\r
4320                 startTime: '',\r
4321                 startMeridiem: 'am',\r
4322                 endTime: '',\r
4323                 endMeridiem: 'pm'\r
4324             };\r
4325             for (var i = 0; i < scope.hourpicker.dayOptions.length; i++) {\r
4326                 hourpickerPanelValueTemplate.days[i] = {\r
4327                     value: false,\r
4328                     title: scope.hourpicker.dayOptions[i].title,\r
4329                     caption: scope.hourpicker.dayOptions[i].caption\r
4330                 };\r
4331             }\r
4332             scope.hourpickerPanelValue = {};\r
4333             scope.disableAddBtn = true;\r
4334 \r
4335             scope.$watch('hourpickerPanelValue.days', function(){\r
4336                 for(var i in scope.hourpickerPanelValue.days)\r
4337                 {\r
4338                     if(scope.hourpickerPanelValue.days[i].value)\r
4339                     {\r
4340                         scope.disableAddBtn = false;\r
4341                         break;\r
4342                     }\r
4343                     scope.disableAddBtn = true;\r
4344                 }\r
4345             }, true);\r
4346 \r
4347             scope.resetHourpickerPanelValue = function () {\r
4348                 scope.hourpickerPanelValue = angular.copy(hourpickerPanelValueTemplate);\r
4349                 if (scope.hourpicker.startTimeDefaultOptionIndex > -1) {\r
4350                     scope.hourpickerPanelValue.startTime = scope.hourpicker.startTimeOptions[scope.hourpicker.startTimeDefaultOptionIndex];\r
4351                 }\r
4352                 if (scope.hourpicker.endTimeDefaultOptionIndex > -1) {\r
4353                     scope.hourpickerPanelValue.endTime = scope.hourpicker.endTimeOptions[scope.hourpicker.endTimeDefaultOptionIndex];\r
4354                 }\r
4355                 scope.hourpickerPanelValue.startMeridiem = scope.hourpicker.startTimeDefaultMeridiem;\r
4356                 scope.hourpickerPanelValue.endMeridiem = scope.hourpicker.endTimeDefaultMeridiem;\r
4357                 scope.hourpicker.editMode = -1;\r
4358                 scope.setValidity('invalidHourpickerData', true);\r
4359                 scope.setValidity('invalidHourpickerTimeRange', true);\r
4360             };\r
4361             scope.resetHourpickerPanelValue();\r
4362             scope.updateHourpickerValue = function () {\r
4363                 if (scope.isFormValid() && !scope.isTimeOverlap()) {\r
4364                     scope.addHourpickerValue(angular.copy(scope.hourpickerPanelValue));\r
4365                     scope.resetHourpickerPanelValue();\r
4366                 }\r
4367             };\r
4368 \r
4369             scope.isFormValid = function () {\r
4370                 var isStartTimeAvailable = scope.hourpickerPanelValue.startTime ? true : false;\r
4371                 var isStartMeridiemAvailable = scope.hourpickerPanelValue.startMeridiem ? true : false;\r
4372                 var isEndTimeAvailable = scope.hourpickerPanelValue.endTime ? true : false;\r
4373                 var isEndMeridiemAvailable = scope.hourpickerPanelValue.endMeridiem ? true : false;\r
4374                 var currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);\r
4375                 var currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);\r
4376                 var isTimeInProperSequence = currentEndTime > currentStartTime;\r
4377                 var isDayChecked = false;\r
4378                 for (var i in scope.hourpickerPanelValue.days) {\r
4379                     if (scope.hourpickerPanelValue.days[i].value) {\r
4380                         isDayChecked = true;\r
4381                         break;\r
4382                     }\r
4383                 }\r
4384 \r
4385                 if (isStartTimeAvailable && isStartMeridiemAvailable && isEndTimeAvailable && isEndMeridiemAvailable && isTimeInProperSequence && isDayChecked) {\r
4386                     scope.setValidity('invalidHourpickerData', true);\r
4387                     return true;\r
4388                 } else {\r
4389                     scope.setValidity('invalidHourpickerData', false);\r
4390                     return false;\r
4391                 }\r
4392             };\r
4393             scope.isTimeOverlap = function () {\r
4394                 var selectedDays = [];\r
4395                 for (var i in scope.hourpickerPanelValue.days) {\r
4396                     if (scope.hourpickerPanelValue.days[i].value) {\r
4397                         selectedDays.push(i);\r
4398                     }\r
4399                 }\r
4400 \r
4401                 var currentStartTime, currentEndTime, existingStartTime, existingEndTime;\r
4402                 currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);\r
4403                 currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);\r
4404                 for (var i = 0; i < scope.hourpickerValues.length; i++) {\r
4405                     \r
4406                     if (i === scope.hourpicker.editMode) {\r
4407                         continue;\r
4408                     }\r
4409 \r
4410                     for (var j = 0; j < selectedDays.length; j++) {\r
4411                         existingStartTime = getTime(scope.hourpickerValues[i].startTime, scope.hourpickerValues[i].startMeridiem);\r
4412                         existingEndTime = getTime(scope.hourpickerValues[i].endTime, scope.hourpickerValues[i].endMeridiem);\r
4413                         if (scope.hourpickerValues[i].days[selectedDays[j]].value) {\r
4414                             if(!scope.hourpicker.sameDayOption){\r
4415                                 scope.setValidity('dayAlreadySelected', false);\r
4416                                 return true;\r
4417                             } else if ((currentStartTime > existingStartTime && currentStartTime < existingEndTime) || (currentEndTime > existingStartTime && currentEndTime < existingEndTime)) {\r
4418                                 scope.setValidity('invalidHourpickerTimeRange', false);\r
4419                                 return true;\r
4420                             } else if ((existingStartTime > currentStartTime && existingStartTime < currentEndTime) || (existingEndTime > currentStartTime && existingEndTime < currentEndTime)) {\r
4421                                 scope.setValidity('invalidHourpickerTimeRange', false);\r
4422                                 return true;\r
4423                             } else if ((currentStartTime === existingStartTime) && (currentEndTime === existingEndTime)) {\r
4424                                 scope.setValidity('invalidHourpickerTimeRange', false);\r
4425                                 return true;\r
4426                             }\r
4427                         }\r
4428                     }\r
4429                 }\r
4430 \r
4431                 scope.setValidity('dayAlreadySelected', true);\r
4432                 scope.setValidity('invalidHourpickerTimeRange', true);\r
4433                 return false;\r
4434             };\r
4435             var getTime = function (timeString, meridiem) {\r
4436                 var tempDate = new Date();\r
4437                 if (timeString && meridiem) {\r
4438                     var timeSplit = timeString.split(':');\r
4439                     var hour = ((meridiem === 'PM' || meridiem === 'pm') && timeSplit[0] !== '12') ? parseInt(timeSplit[0], 10) + 12 : parseInt(timeSplit[0], 10);\r
4440                     tempDate.setHours(hour, parseInt(timeSplit[1], 10), 0, 0);\r
4441                 }\r
4442 \r
4443                 return tempDate.getTime();\r
4444             };\r
4445         }\r
4446     }\r
4447 }])\r
4448 \r
4449 .directive('b2bHourpickerValue', [function () {\r
4450     return {\r
4451         restrict: 'EA',\r
4452         replace: false,\r
4453         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerValue.html',\r
4454         controller: ['$scope', function (scope) {\r
4455 \r
4456         }],\r
4457         link: function (scope, elem, attr, ctrl) {\r
4458             scope.hourpickerValue = {};\r
4459             scope.hourpickerValue.startTime = attr.startTime ? scope.$eval(attr.startTime) : '';\r
4460             scope.hourpickerValue.startMeridiem = attr.startMeridiem ? scope.$eval(attr.startMeridiem) : '';\r
4461             scope.hourpickerValue.endTime = attr.endTime ? scope.$eval(attr.endTime) : '';\r
4462             scope.hourpickerValue.endMeridiem = attr.endMeridiem ? scope.$eval(attr.endMeridiem) : '';\r
4463             scope.hourpickerValue.days = attr.days ? scope.$eval(attr.days).join(', ') : '';\r
4464             scope.hourpickerValue.index = attr.b2bHourpickerValue ? scope.$eval(attr.b2bHourpickerValue) : -1;\r
4465         }\r
4466     }\r
4467 }]);\r
4468 /**\r
4469  * @ngdoc directive\r
4470  * @name Template.att:inputTemplate\r
4471  *\r
4472  * @description\r
4473  *  <file src="src/inputTemplate/docs/readme.md" />\r
4474  *\r
4475  * @usage\r
4476  *  <input type="text" id="fieldId" placeholder="placholder text here" class="span12 input-enhanced" name="fieldName">\r
4477  *\r
4478  * @example\r
4479  <section id="code">\r
4480     <b>HTML + AngularJS</b>\r
4481     <example module="b2b.att">\r
4482         <file src="src/inputTemplate/docs/demo.html" />\r
4483         <file src="src/inputTemplate/docs/demo.js" />\r
4484     </example>\r
4485  </section>\r
4486  */\r
4487 angular.module('b2b.att.inputTemplate', []);\r
4488 \r
4489 /**\r
4490  * @ngdoc directive\r
4491  * @name Navigation.att:leftNavigation\r
4492  *\r
4493  * @description\r
4494  *  <file src="src/leftNavigation/docs/readme.md" />\r
4495  *\r
4496  * @usage\r
4497  *   <b2b-left-navigation data-menu="menuData"></b2b-left-navigation> \r
4498  *\r
4499  * @example\r
4500  *  <section id="code">\r
4501         <example module="b2b.att">\r
4502             <file src="src/leftNavigation/docs/demo.html" />\r
4503             <file src="src/leftNavigation/docs/demo.js" />\r
4504        </example>\r
4505     </section>\r
4506  *\r
4507  */\r
4508 angular.module('b2b.att.leftNavigation', [])\r
4509     .directive('b2bLeftNavigation', [function () {\r
4510         return {\r
4511             restrict: 'EA',\r
4512             templateUrl: 'b2bTemplate/leftNavigation/leftNavigation.html',\r
4513             scope: {\r
4514                 menuData: '='\r
4515             },\r
4516             link: function (scope, element, attrs, ctrl) {\r
4517                 scope.idx = -1;\r
4518                 scope.itemIdx = -1;\r
4519                 scope.navIdx = -1;\r
4520                 scope.toggleNav = function (val,link) {\r
4521                     if (val === scope.idx) {\r
4522                         scope.idx = -1;\r
4523                         return;\r
4524                     }\r
4525                     scope.idx = val;\r
4526                 };\r
4527                 /*New function for ECOMP sdk*/\r
4528                 scope.toggleDrawer = function(showmenu){\r
4529                         scope.idx=-1; /*hide the sunmenus*/\r
4530                         /*if(showmenu){\r
4531                                 //scope.openList.length=0;\r
4532                                 document.getElementById('page-content').style.marginLeft = "50px";\r
4533                         }\r
4534                         else\r
4535                                 document.getElementById('page-content').style.marginLeft = "250px";   */                \r
4536                 };\r
4537                 scope.liveLink = function (evt, val1, val2) {\r
4538                     scope.itemIdx = val1;\r
4539                     scope.navIdx = val2;\r
4540                     evt.stopPropagation();\r
4541                 };\r
4542             }\r
4543         };\r
4544     }]);\r
4545 /**\r
4546  * @ngdoc directive\r
4547  * @name Buttons, links & UI controls.att:links\r
4548  *\r
4549  * @description\r
4550  *  <file src="src/links/docs/readme.md" />\r
4551  * @usage\r
4552  *      <!-- See below examples for link implementation -->\r
4553  *      \r
4554  * @example\r
4555        <section id="code">              \r
4556            <b>HTML + AngularJS</b>\r
4557            <example module="b2b.att">\r
4558            <file src="src/links/docs/demo.html" />\r
4559             <file src="src/links/docs/demo.js" />            \r
4560           </example>          \r
4561         </section>\r
4562  */\r
4563 angular.module('b2b.att.links', []);\r
4564 /**\r
4565  * @ngdoc directive\r
4566  * @name Misc.att:listbox\r
4567  *\r
4568  * @description\r
4569  *  <file src="src/listbox/docs/readme.md" />\r
4570  *\r
4571  * @param {int} currentIndex - Current index of selected listbox item. Is not supported on multiselect listbox\r
4572  * @param {Array} listboxData - Data of listbox items. Should include full data regardless if HTML will be filtered.\r
4573 \r
4574  * @example\r
4575  *  <section id="code">   \r
4576      <example module="b2b.att">\r
4577      <file src="src/listbox/docs/demo.html" />\r
4578      <file src="src/listbox/docs/demo.js" />\r
4579      </example>\r
4580     </section>\r
4581  *\r
4582  */\r
4583 angular.module('b2b.att.listbox', ['b2b.att.utilities'])\r
4584 .directive('b2bListBox', ['keymap', 'b2bDOMHelper', '$rootScope', function(keymap, b2bDOMHelper, $rootScope) {\r
4585                 return {\r
4586                     restrict: 'AE',\r
4587                     transclude: true,\r
4588                     replace: true,\r
4589                     scope: {\r
4590                         currentIndex: '=', \r
4591                         listboxData: '='\r
4592                     },\r
4593                     templateUrl: 'b2bTemplate/listbox/listbox.html',\r
4594                     link: function(scope, elem, attr) {\r
4595 \r
4596                         if (attr.ariaMultiselectable !== undefined || attr.ariaMultiselectable === 'true') {\r
4597                             scope.multiselectable = true;\r
4598                         } else {\r
4599                             scope.multiselectable = false;\r
4600                         }\r
4601 \r
4602                         var shiftKey = false;\r
4603                         var elements = [];\r
4604                         var prevDirection = undefined; // previous direction is used for an edge case when shifting\r
4605                         var shiftKeyPressed = false; // Used to handle shift clicking\r
4606                         var ctrlKeyPressed = false;\r
4607 \r
4608                         var currentIndexSet = {\r
4609                             'elementIndex': 0,\r
4610                             'listboxDataIndex': 0\r
4611                         };\r
4612 \r
4613                         /*scope.$watch('currentIndex', function(oldVal, newVal) {\r
4614                             if (angular.equals(oldVal, newVal)) return;\r
4615                             if (!scope.multiselectable) {\r
4616                                 // This doesn't garuntee anything. index will update on focus based on rules\r
4617                                 currentIndexSet.listboxDataIndex = scope.currentIndex;\r
4618                                 // Should this occur? \r
4619                                 //scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;\r
4620 \r
4621                                 // Update elementIndex\r
4622                                 elements = elem.children();\r
4623                                 var indecies = Array.prototype.map.call(elements, function(item) {\r
4624                                     return parseInt(angular.element(item).attr('data-index'), 10);\r
4625                                 }).filter(function(item) {\r
4626                                     return item === scope.currentIndex;\r
4627                                 });\r
4628                                 currentIndex.elementIndex = indecies[0];\r
4629                                 //focusOnElement(currentIndexSet.elementIndex); // This isn't shifting focus\r
4630                                 if (!scope.$$phase) {\r
4631                                     scope.$apply();\r
4632                                 }\r
4633                             }\r
4634                         });*/\r
4635 \r
4636                         function isTrue(item) {\r
4637                             if (item.selected === true) {\r
4638                                 return true;\r
4639                             }\r
4640                         }\r
4641 \r
4642                         function incrementIndex(elem) {\r
4643                             $rootScope.$apply();\r
4644 \r
4645                             var nextElem = elem.next();\r
4646                             if (!angular.isDefined(nextElem) || nextElem.length === 0) {\r
4647                                 return;\r
4648                             }\r
4649 \r
4650                             currentIndexSet.elementIndex += 1;\r
4651                             currentIndexSet.listboxDataIndex = parseInt(nextElem.attr('data-index'), 10);\r
4652                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4653 \r
4654                             if (currentIndexSet.elementIndex >= elements.length - 1) {\r
4655                                 currentIndexSet.elementIndex = elements.length-1;\r
4656                             }\r
4657                         }\r
4658 \r
4659                         function decrementIndex(elem) {\r
4660                             $rootScope.$apply();\r
4661                             var prevElem = angular.element(b2bDOMHelper.previousElement(elem));\r
4662                             if (!angular.isDefined(prevElem) || prevElem.length === 0) {\r
4663                                 return;\r
4664                             }\r
4665 \r
4666                             currentIndexSet.elementIndex -= 1;\r
4667                             currentIndexSet.listboxDataIndex = parseInt(prevElem.attr('data-index'), 10);\r
4668                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4669 \r
4670                             if (currentIndexSet.elementIndex <= 0) {\r
4671                                 currentIndexSet.elementIndex = 0;\r
4672                             }\r
4673                         }\r
4674 \r
4675                         var focusOnElement = function(index) {\r
4676                             try {\r
4677                                 elements[index].focus();\r
4678                             } catch (e) {};\r
4679                         }\r
4680 \r
4681                         function selectItems(startIndex, endIndex, forceValue) {\r
4682                             for (var i = startIndex; i < endIndex; i++) {\r
4683                                 if (forceValue === undefined) {\r
4684                                     // We will flip the value\r
4685                                     scope.listboxData[i].selected = !scope.listboxData[i].selected;\r
4686                                 } else {\r
4687                                     scope.listboxData[i].selected = forceValue;\r
4688                                 }\r
4689                             }\r
4690 \r
4691                             if (!scope.$$phase) {\r
4692                                 scope.$apply();\r
4693                             }\r
4694                         }\r
4695 \r
4696                         elem.bind('focus', function(evt) { \r
4697                             // If multiselectable or not and nothing is selected, put focus on first element \r
4698                             // If multiselectable and a range is set, put focus on first element of range \r
4699                             // If not multiselectable and something selected, put focus on element \r
4700                             elements = elem.children(); \r
4701                              var selectedItems = scope.listboxData.filter(isTrue); \r
4702                              var elementsIndies = Array.prototype.map.call(elements, function(item) {\r
4703                                 return parseInt(angular.element(item).attr('data-index'), 10);\r
4704                             });\r
4705  \r
4706                             if (selectedItems.length == 0) { \r
4707                                 focusOnElement(0); \r
4708                                 currentIndexSet.listboxDataIndex = 0;\r
4709                             } else if (attr.ariaMultiselectable) { \r
4710                                 var index = scope.listboxData.indexOf(selectedItems[0]); \r
4711                                 var indies = elementsIndies.filter(function(item) {\r
4712                                     return (item === index);\r
4713                                 });\r
4714 \r
4715                                 if (indies.length === 0 || indies[0] != index) {\r
4716                                     // Set focused on 0\r
4717                                     currentIndexSet.elementIndex = elementsIndies[0]; \r
4718                                     currentIndexSet.listboxDataIndex = 0;\r
4719                                     focusOnElement(currentIndexSet.elementIndex);\r
4720                                 } else {\r
4721                                     focusOnElement(indies[0]); \r
4722                                     currentIndexSet.elementIndex = indies[0];\r
4723                                     currentIndexSet.listboxDataIndex = index;\r
4724                                 }\r
4725                             } else { \r
4726                                 focusOnElement(currentIndexSet.elementIndex);  \r
4727                             }\r
4728                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4729 \r
4730                             if (!scope.$$phase) {\r
4731                                 scope.$apply();\r
4732                             }\r
4733                         });\r
4734                         elem.bind('keyup', function(evt) {\r
4735                             if (evt.keyCode === keymap.KEY.SHIFT) {\r
4736                                 shiftKeyPressed = false;\r
4737                             } else if (evt.keyCode === keymap.KEY.CTRL) {\r
4738                                 ctrlKeyPressed = false;\r
4739                             }\r
4740                         });\r
4741         \r
4742                         elem.bind('keydown', function(evt) {\r
4743                             var keyCode = evt.keyCode;\r
4744                             elements = elem.children();\r
4745                             if (keyCode === keymap.KEY.SHIFT) {\r
4746                                 shiftKeyPressed = true;\r
4747                             } else if (evt.keyCode === keymap.KEY.CTRL) {\r
4748                                 ctrlKeyPressed = true;\r
4749                             }\r
4750 \r
4751                             switch(keyCode) {\r
4752                                 case 65: // A key\r
4753                                 {\r
4754                                     if (scope.multiselectable && evt.ctrlKey) {\r
4755                                         var arr = scope.listboxData.filter(isTrue);\r
4756                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {\r
4757                                             return parseInt(angular.element(item).attr('data-index'), 10);\r
4758                                         });\r
4759                                         var val = !(arr.length === scope.listboxData.length);\r
4760                                         for (var i = 0; i < elementsIndies.length; i++) {\r
4761                                             scope.listboxData[elementsIndies[i]].selected = val;\r
4762                                         }\r
4763 \r
4764                                         if (!scope.$$phase) {\r
4765                                             scope.$apply();\r
4766                                         }\r
4767                                         \r
4768                                         evt.preventDefault();\r
4769                                         evt.stopPropagation();\r
4770                                     }\r
4771                                     break;\r
4772                                 }\r
4773                                 case keymap.KEY.END:\r
4774                                 {\r
4775                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {\r
4776                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {\r
4777                                             return parseInt(angular.element(item).attr('data-index'), 10);\r
4778                                         }).filter(function(item) {\r
4779                                             return (item >= currentIndexSet.listboxDataIndex);\r
4780                                         });\r
4781                                         for (var i = 0; i < elementsIndies.length; i++) {\r
4782                                             scope.listboxData[elementsIndies[i]].selected = true;\r
4783                                         }\r
4784                                         evt.preventDefault();\r
4785                                         evt.stopPropagation();\r
4786 \r
4787                                         if (!scope.$$phase) {\r
4788                                             scope.$apply();\r
4789                                         }\r
4790                                     }\r
4791                                     break;\r
4792                                 }\r
4793                                 case keymap.KEY.HOME: \r
4794                                 {\r
4795                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {\r
4796                                         selectItems(0, currentIndexSet.listboxDataIndex+1, true); // currentIndex+1 is what is being focused on\r
4797                                         evt.preventDefault();\r
4798                                         evt.stopPropagation();\r
4799                                     }\r
4800                                     break;\r
4801                                 }\r
4802                                 case keymap.KEY.LEFT:\r
4803                                 case keymap.KEY.UP:\r
4804                                 {\r
4805                                     if (currentIndexSet.listboxDataIndex === 0) {\r
4806                                         evt.preventDefault();\r
4807                                         evt.stopPropagation();\r
4808                                         return;\r
4809                                     }\r
4810 \r
4811                                     decrementIndex(elements.eq(currentIndexSet.elementIndex));\r
4812                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {\r
4813                                         if (evt.shiftKey) {\r
4814                                             if (prevDirection === 'DOWN') {\r
4815                                                 scope.listboxData[currentIndexSet.listboxDataIndex+1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex+1].selected;\r
4816                                             }\r
4817                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;\r
4818                                         }\r
4819                                         prevDirection = 'UP';\r
4820                                     } else {\r
4821                                         // If no modifier keys are selected, all other items need to be unselected.\r
4822                                         prevDirection = undefined;\r
4823                                         selectItems(0, scope.listboxData.length, false);\r
4824                                         scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;\r
4825                                     }\r
4826                                     focusOnElement(currentIndexSet.elementIndex);\r
4827                                     if(!scope.$$phase) {\r
4828                                         scope.$apply();\r
4829                                     }\r
4830                                     evt.preventDefault();\r
4831                                     evt.stopPropagation();\r
4832                                     break;\r
4833                                 }\r
4834                                 case keymap.KEY.RIGHT:\r
4835                                 case keymap.KEY.DOWN:\r
4836                                 {\r
4837                                     if (currentIndexSet.listboxDataIndex === scope.listboxData.length-1) {\r
4838                                         evt.preventDefault();\r
4839                                         evt.stopPropagation();\r
4840                                         return;\r
4841                                     }\r
4842 \r
4843                                     incrementIndex(elements.eq(currentIndexSet.elementIndex));\r
4844                                     \r
4845                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {\r
4846                                         if (evt.shiftKey) {\r
4847                                             if (prevDirection === 'UP') {\r
4848                                                 scope.listboxData[currentIndexSet.listboxDataIndex-1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex-1].selected;\r
4849                                             }\r
4850                                             \r
4851                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;    \r
4852                                         }\r
4853                                         prevDirection = 'DOWN';\r
4854                                     } else {\r
4855                                         // If no modifier keys are selected, all other items need to be unselected.\r
4856                                         prevDirection = undefined;\r
4857                                         selectItems(0, scope.listboxData.length, false);\r
4858                                         scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;\r
4859                                     }\r
4860 \r
4861                                     focusOnElement(currentIndexSet.elementIndex);\r
4862                                     if(!scope.$$phase) {\r
4863                                         scope.$apply();\r
4864                                     }\r
4865                                     evt.preventDefault();\r
4866                                     evt.stopPropagation();\r
4867                                     break;\r
4868                                 }\r
4869                                 case keymap.KEY.TAB:\r
4870                                     if(evt.shiftKey) {\r
4871                                         var previousElement = b2bDOMHelper.previousElement(elem.parent().parent(), true);\r
4872                                         evt.preventDefault();\r
4873                                         previousElement.focus();\r
4874                                     }\r
4875                                     break;\r
4876                                 default:\r
4877                                     break;\r
4878                             }\r
4879                         });\r
4880 \r
4881                         elem.bind('click', function(evt) {\r
4882                             var index = parseInt(evt.target.dataset.index, 10);\r
4883                             if (index === undefined || isNaN(index)) {\r
4884                                 return;\r
4885                             }\r
4886                             if (scope.multiselectable && currentIndexSet.listboxDataIndex !== undefined) {\r
4887                                 if (shiftKeyPressed) {\r
4888                                     var min = Math.min(index, currentIndexSet.listboxDataIndex);\r
4889                                     var max = Math.max(index, currentIndexSet.listboxDataIndex);\r
4890 \r
4891                                     if (index === min) { // clicking up\r
4892                                         var firstIndex = scope.listboxData.findIndex(function(item) { return item.selected === true;});\r
4893                                         // Given the firstIndex, let's find the matching element to get proper element match\r
4894                                         elements = elem.children();\r
4895                                         elements.eq(firstIndex)\r
4896                                         var elementsThatMatch = Array.prototype.filter.call(elements, function(item) {\r
4897                                             if (parseInt(angular.element(item).attr('data-index'), 10) === firstIndex) {\r
4898                                                 return true;\r
4899                                             }\r
4900                                         });\r
4901                                         firstIndex = parseInt(angular.element(elementsThatMatch).attr('data-index'), 10);\r
4902                                         \r
4903                                         if (index <= firstIndex && scope.listboxData.filter(isTrue).length > 1) {\r
4904                                             // Break the selection into 2\r
4905                                             selectItems(firstIndex + 1, max + 1, undefined); // + 1 needed because selectItems only selects up to MAX\r
4906                                             selectItems(min, firstIndex, undefined); \r
4907                                         } else if (scope.listboxData.filter(isTrue).length == 1){\r
4908                                             selectItems(min, max, undefined); \r
4909                                         } else {\r
4910                                             selectItems(min + 1, max + 1, undefined);\r
4911                                         }\r
4912                                     } else { // clicking down\r
4913                                         selectItems(min + 1, max + 1, scope.listboxData[min].selected);\r
4914                                     }\r
4915                                 } else if (ctrlKeyPressed) {\r
4916                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;\r
4917                                 } else {\r
4918                                     selectItems(0, scope.listboxData.length, false);\r
4919                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;\r
4920                                 }\r
4921                             } else {\r
4922                                 selectItems(0, scope.listboxData.length, false);\r
4923                                 scope.listboxData[index].selected = !scope.listboxData[index].selected;\r
4924                             }\r
4925                             currentIndexSet.elementIndex = index;\r
4926                             currentIndexSet.listboxDataIndex = index;\r
4927                             scope.currentIndex = currentIndexSet.listboxDataIndex;\r
4928                             if (!scope.$$phase) {\r
4929                                 scope.$apply();\r
4930                             }\r
4931                             focusOnElement(index);\r
4932                         });\r
4933                     }\r
4934                 };\r
4935             }]);\r
4936 /**\r
4937  * @ngdoc directive\r
4938  * @name Videos, audio & animation.att:loaderAnimation\r
4939  *\r
4940  * @description\r
4941  *  <file src="src/loaderAnimation/docs/readme.md" />\r
4942  *\r
4943  * @usage\r
4944  *   <!-- Below demo js shows-->\r
4945  *   Angular library uses Global.css's icon-primary-spinner.\r
4946  *\r
4947  * @example\r
4948  *  <section id="code">\r
4949         <example module="b2b.att">\r
4950             <file src="src/loaderAnimation/docs/demo.html" />\r
4951             <file src="src/loaderAnimation/docs/demo.js" />\r
4952        </example>\r
4953     </section>\r
4954  *\r
4955  */\r
4956 angular.module('b2b.att.loaderAnimation', [])\r
4957     .constant('b2bSpinnerConfig', {\r
4958         loadingText: 'Loading...',\r
4959         startEvent: 'startButtonSpinner',\r
4960         stopEvent: 'stopButtonSpinner'\r
4961     })\r
4962     .constant("progressTrackerConfig", {\r
4963         loadingText: 'Loading...',\r
4964         minDuration: "",\r
4965         activationDelay: "",\r
4966         minDurationPromise: "",\r
4967         activationDelayPromise: ""\r
4968     })\r
4969 \r
4970 .provider('progressTracker', function () {\r
4971     this.$get = ['$q', '$timeout', function ($q, $timeout) {\r
4972         function cancelTimeout(promise) {\r
4973             if (promise) {\r
4974                 $timeout.cancel(promise);\r
4975             }\r
4976         }\r
4977         return function ProgressTracker(options) {\r
4978             //do new if user doesn't\r
4979             if (!(this instanceof ProgressTracker)) {\r
4980                 return new ProgressTracker(options);\r
4981             }\r
4982 \r
4983             options = options || {};\r
4984             //Array of promises being tracked\r
4985             var tracked = [];\r
4986             var self = this;\r
4987             //Allow an optional "minimum duration" that the tracker has to stay active for.\r
4988             var minDuration = options.minDuration;\r
4989             //Allow a delay that will stop the tracker from activating until that time is reached\r
4990             var activationDelay = options.activationDelay;\r
4991             var minDurationPromise;\r
4992             var activationDelayPromise;\r
4993             self.active = function () {\r
4994                 //Even if we have a promise in our tracker, we aren't active until delay is elapsed\r
4995                 if (activationDelayPromise) {\r
4996                     return false;\r
4997                 }\r
4998                 return tracked.length > 0;\r
4999             };\r
5000             self.tracking = function () {\r
5001                 //Even if we aren't active, we could still have a promise in our tracker\r
5002                 return tracked.length > 0;\r
5003             };\r
5004             self.destroy = self.cancel = function () {\r
5005                 minDurationPromise = cancelTimeout(minDurationPromise);\r
5006                 activationDelayPromise = cancelTimeout(activationDelayPromise);\r
5007                 for (var i = tracked.length - 1; i >= 0; i--) {\r
5008                     tracked[i].resolve();\r
5009                 }\r
5010                 tracked.length = 0;\r
5011             };\r
5012             //Create a promise that will make our tracker active until it is resolved.\r
5013             // @return deferred - our deferred object that is being tracked\r
5014             self.createPromise = function () {\r
5015                 var deferred = $q.defer();\r
5016                 tracked.push(deferred);\r
5017                 //If the tracker was just inactive and this the first in the list of promises, we reset our delay and minDuration again.\r
5018                 if (tracked.length === 1) {\r
5019                     if (activationDelay) {\r
5020                         activationDelayPromise = $timeout(function () {\r
5021                             activationDelayPromise = cancelTimeout(activationDelayPromise);\r
5022                             startMinDuration();\r
5023                         }, activationDelay);\r
5024                     } else {\r
5025                         startMinDuration();\r
5026                     }\r
5027                 }\r
5028                 deferred.promise.then(onDone(false), onDone(true));\r
5029                 return deferred;\r
5030 \r
5031                 function startMinDuration() {\r
5032                     if (minDuration) {\r
5033                         minDurationPromise = $timeout(angular.noop, minDuration);\r
5034                     }\r
5035                 }\r
5036                 //Create a callback for when this promise is done. It will remove our tracked promise from the array if once minDuration is complete\r
5037                 function onDone() {\r
5038                     return function () {\r
5039                         (minDurationPromise || $q.when()).then(function () {\r
5040                             var index = tracked.indexOf(deferred);\r
5041                             tracked.splice(index, 1);\r
5042                             //If this is the last promise, cleanup the timeouts for activationDelay\r
5043                             if (tracked.length === 0) {\r
5044                                 activationDelayPromise = cancelTimeout(activationDelayPromise);\r
5045                             }\r
5046                         });\r
5047                     };\r
5048                 }\r
5049             };\r
5050             self.addPromise = function (promise) {\r
5051                 \r
5052 //                we cannot assign then function in other var and then add the resolve and reject \r
5053                 var thenFxn = promise && (promise.then || promise.$then || (promise.$promise && promise.$promise.then));                \r
5054                 if (!thenFxn) {\r
5055                     throw new Error("progressTracker expects a promise object :: Not found");\r
5056                 }\r
5057                 var deferred = self.createPromise();\r
5058                 //When given promise is done, resolve our created promise\r
5059                 //Allow $then for angular-resource objects\r
5060 \r
5061                 promise.then(function (value) {\r
5062                         deferred.resolve(value);\r
5063                         return value;\r
5064                     }, function (value) {\r
5065                         deferred.reject(value);\r
5066                         return $q.reject(value);\r
5067                     }\r
5068                 );\r
5069                 return deferred;\r
5070             };\r
5071         };\r
5072     }];\r
5073 })\r
5074 \r
5075 .config(['$httpProvider', function ($httpProvider) {\r
5076     $httpProvider.interceptors.push(['$q', 'progressTracker', function ($q) {\r
5077         return {\r
5078             request: function (config) {\r
5079                 if (config.tracker) {\r
5080                     if (!angular.isArray(config.tracker)) {\r
5081                         config.tracker = [config.tracker];\r
5082                     }\r
5083                     config.$promiseTrackerDeferred = config.$promiseTrackerDeferred || [];\r
5084 \r
5085                     angular.forEach(config.tracker, function (tracker) {\r
5086                         var deferred = tracker.createPromise();\r
5087                         config.$promiseTrackerDeferred.push(deferred);\r
5088                     });\r
5089                 }\r
5090                 return $q.when(config);\r
5091             },\r
5092             response: function (response) {\r
5093                 if (response.config && response.config.$promiseTrackerDeferred) {\r
5094                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {\r
5095                         deferred.resolve(response);\r
5096                     });\r
5097                 }\r
5098                 return $q.when(response);\r
5099             },\r
5100             responseError: function (response) {\r
5101                 if (response.config && response.config.$promiseTrackerDeferred) {\r
5102                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {\r
5103                         deferred.reject(response);\r
5104                     });\r
5105                 }\r
5106                 return $q.reject(response);\r
5107             }\r
5108         };\r
5109     }]);\r
5110 }])\r
5111 \r
5112 .directive('b2bClickSpin', ['$timeout', '$parse', '$rootScope', 'progressTracker', function ($timeout, $parse, $rootScope, progressTracker) {\r
5113     return {\r
5114         restrict: 'A',\r
5115         link: function (scope, elm, attrs) {\r
5116             var fn = $parse(attrs.b2bClickSpin);\r
5117             elm.on('click', function (event) {\r
5118                 var promise = $timeout(function () {console.log("inside Promise")}, 5000);\r
5119                 scope.$apply(function () {\r
5120                     fn(scope, {\r
5121                         $event: event\r
5122                     });\r
5123                 });\r
5124                 //comment this line if not running unit test\r
5125                 $rootScope.loadingTracker = progressTracker({\r
5126                     minDuration: 750\r
5127                 });\r
5128                 $rootScope.loadingTracker.addPromise(promise);\r
5129                 angular.forEach("$routeChangeSuccess $viewContentLoaded $locationChangeSuccess".split(" "), function (event) {\r
5130                     $rootScope.$on(event, function () {\r
5131 \r
5132                         $timeout.cancel(promise);\r
5133                     });\r
5134                 });\r
5135             });\r
5136         }\r
5137     };\r
5138 }])\r
5139 \r
5140 .directive('b2bProgressTracker', ['progressTrackerConfig', function (ptc) {\r
5141     return {\r
5142         restrict: 'EA',\r
5143         replace: true,\r
5144         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
5145     };\r
5146 }])\r
5147 \r
5148 .directive('b2bLoadButton', ['b2bSpinnerConfig', '$timeout', function (spinnerConfig, $timeout) {\r
5149     var spinButton = function (state, element, data) {\r
5150         \r
5151         var attr = element.html() ? 'html' : 'val';\r
5152         state = state + 'Text';\r
5153         if (state === 'loadingText') {\r
5154             element[attr](data[state]);\r
5155             element.attr("disabled",'disabled');\r
5156             element.addClass('disabled');\r
5157         } else if (state === 'resetText') {\r
5158             element[attr](data[state]);\r
5159             element.removeAttr("disabled");\r
5160             element.removeClass('disabled');\r
5161         }\r
5162     };\r
5163 \r
5164     return {\r
5165         restrict: 'A',\r
5166         replace: false,\r
5167         scope: {\r
5168             promise: '=promise',\r
5169             startEvent: '@startEvent',\r
5170             stopEvent: '@stopEvent'\r
5171         },\r
5172         link: function (scope, element, attr) {\r
5173             var validAttr = element.html() ? 'html' : 'val';\r
5174             var data = {\r
5175                 loadingText: '',\r
5176                 resetText: ''\r
5177             };\r
5178 \r
5179             var updateLoadingText = function (val) {\r
5180                 var loadingText = val;\r
5181                 if (!angular.isDefined(loadingText) || loadingText === "") {\r
5182                     loadingText = spinnerConfig.loadingText;\r
5183                 }\r
5184                 data.loadingText = validAttr === 'html' ? "<i class=\"icon-primary-spinner small\"></i>" + loadingText : loadingText;\r
5185             };\r
5186             var updateResetText = function (val) {\r
5187                 data.resetText = val;\r
5188             };\r
5189 \r
5190             attr.$observe('b2bLoadButton', function (val) {\r
5191                 updateLoadingText(val);\r
5192             });\r
5193             $timeout(function () {\r
5194                 updateResetText(element[validAttr]());\r
5195             }, 500);\r
5196 \r
5197             if (!angular.isDefined(scope.startEvent) || scope.startEvent === "") {\r
5198                 scope.startEvent = spinnerConfig.startEvent;\r
5199             }\r
5200 \r
5201             if (!angular.isDefined(scope.stopEvent) || scope.stopEvent === "") {\r
5202                 scope.stopEvent = spinnerConfig.stopEvent;\r
5203             }\r
5204 \r
5205             scope.$watch('promise', function () {\r
5206                 if (angular.isDefined(scope.promise) && angular.isFunction(scope.promise.then)) {\r
5207                     spinButton('loading', element, data);\r
5208                     scope.promise.then(function () {\r
5209                         spinButton('reset', element, data);\r
5210                     }, function () {\r
5211                         spinButton('reset', element, data);\r
5212                     });\r
5213                 }\r
5214             });\r
5215 \r
5216             scope.$on(scope.startEvent, function () {\r
5217                 spinButton('loading', element, data);\r
5218                 scope.$on(scope.stopEvent, function () {\r
5219                     spinButton('reset', element, data);\r
5220                 });\r
5221             });\r
5222         }\r
5223     };\r
5224 }])\r
5225 \r
5226 \r
5227 ;\r
5228  /**\r
5229  * @ngdoc directive\r
5230  * @name Misc.att:messageWrapper\r
5231  * @scope\r
5232  * @param {boolean} trigger - A boolean that triggers directive to switch focus\r
5233  * @param {integer} delay  - Extra delay added to trigger code to allow for DOM to be ready. Default is 10ms.\r
5234  * @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
5235  * @param {string} trapFocus - Attribute-based API to trap focus within the message. This should be enabled by default on all toast messages.\r
5236  * @description\r
5237  *  <file src="src/messageWrapper/docs/readme.md" />\r
5238  * @usage\r
5239  * <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
5240  *\r
5241  * @example\r
5242  *  <section id="code">   \r
5243  <b>HTML + AngularJS</b>\r
5244  <example module="b2b.att">\r
5245  <file src="src/messageWrapper/docs/demo.html" />\r
5246  <file src="src/messageWrapper/docs/demo.js" />\r
5247  </example>\r
5248  </section>\r
5249  *\r
5250  */\r
5251 angular.module('b2b.att.messageWrapper', ['b2b.att.utilities'])\r
5252 .directive('b2bMessageWrapper', ['b2bDOMHelper', '$compile', '$timeout', '$log', function(b2bDOMHelper, $compile, $timeout, $log) {\r
5253   return {\r
5254     restrict: 'AE',\r
5255     scope: {\r
5256       trigger: '=',\r
5257       delay: '=?'\r
5258     },\r
5259     transclude: true,\r
5260     replace: true,\r
5261     template: '<div ng-transclude></div>',\r
5262     link: function(scope, elem, attrs) {\r
5263       scope.delay = scope.delay || 10;\r
5264 \r
5265       if (attrs.trapFocus != undefined && !elem.children().eq(0).attr('b2b-trap-focus-inside-element')) {\r
5266         // Append b2bTrapFocusInsideElement onto first child and recompile\r
5267         elem.children().eq(0).attr('b2b-trap-focus-inside-element', 'false');\r
5268         elem.children().eq(0).attr('trigger', scope.trigger);\r
5269         $compile(elem.contents())(scope);\r
5270       }\r
5271 \r
5272       var firstElement = undefined,\r
5273           launchingElement = undefined;\r
5274       \r
5275       scope.$watch('trigger', function(oldVal, newVal) {\r
5276         if (oldVal === newVal) return;\r
5277         if (!angular.isDefined(launchingElement)) {\r
5278           launchingElement = document.activeElement;\r
5279         }\r
5280         $timeout(function() {\r
5281           if (scope.trigger) {\r
5282 \r
5283             if (attrs.noFocus === true || attrs.noFocus === "") {\r
5284               elem.children()[0].focus();\r
5285             } else {\r
5286               firstElement = b2bDOMHelper.firstTabableElement(elem);\r
5287 \r
5288               if (angular.isDefined(firstElement)) {\r
5289                 firstElement.focus();\r
5290               }\r
5291             }\r
5292             \r
5293           } else {\r
5294             if (angular.isDefined(launchingElement) && launchingElement.nodeName !== 'BODY') {\r
5295               if (launchingElement === document.activeElement) {\r
5296                 return;\r
5297               }\r
5298 \r
5299               if (b2bDOMHelper.isInDOM(launchingElement) && b2bDOMHelper.isTabable(launchingElement)) {\r
5300                   // At this point, launchingElement is still a valid element, but focus will fail and \r
5301                   // activeElement will become body, hence we want to apply custom logic and find previousElement\r
5302                   var prevLaunchingElement = launchingElement;\r
5303                   launchingElement.focus();\r
5304 \r
5305                   if (document.activeElement !== launchingElement || document.activeElement.nodeName === 'BODY') {\r
5306                     launchingElement = b2bDOMHelper.previousElement(angular.element(prevLaunchingElement), true);\r
5307                     launchingElement.focus();\r
5308                   }\r
5309               } else {\r
5310                 launchingElement = b2bDOMHelper.previousElement(launchingElement, true);\r
5311                 launchingElement.focus();\r
5312               }\r
5313             }\r
5314           }\r
5315         }, scope.delay); \r
5316       });\r
5317     }\r
5318   };\r
5319 }]);\r
5320 /**\r
5321  * @ngdoc directive\r
5322  * @name Messages, modals & alerts.att:modalsAndAlerts\r
5323  *\r
5324  * @description\r
5325  *  <file src="src/modalsAndAlerts/docs/readme.md" />\r
5326  *\r
5327  * @usage\r
5328  *  <button class="btn" b2b-modal="b2bTemplate/modalsAndAlerts/demo_modal.html" modal-ok="ok()" modal-cancel="cancel()">Launch demo modal</button>\r
5329  *\r
5330  * @example\r
5331  *  <section id="code">\r
5332      <example module="b2b.att">\r
5333       <file src="src/modalsAndAlerts/docs/demo.html" />\r
5334       <file src="src/modalsAndAlerts/docs/demo.js" />\r
5335      </example>\r
5336     </section>\r
5337  *\r
5338  */\r
5339 angular.module('b2b.att.modalsAndAlerts', ['b2b.att.position', 'b2b.att.transition', 'b2b.att.utilities'])\r
5340 \r
5341 /**\r
5342  * A helper, internal data structure that acts as a map but also allows getting / removing\r
5343  * elements in the LIFO order\r
5344  */\r
5345 .factory('$$stackedMap', function () {\r
5346     return {\r
5347         createNew: function () {\r
5348             var stack = [];\r
5349 \r
5350             return {\r
5351                 add: function (key, value) {\r
5352                     stack.push({\r
5353                         key: key,\r
5354                         value: value\r
5355                     });\r
5356                 },\r
5357                 get: function (key) {\r
5358                     for (var i = 0; i < stack.length; i++) {\r
5359                         if (key === stack[i].key) {\r
5360                             return stack[i];\r
5361                         }\r
5362                     }\r
5363                 },\r
5364                 keys: function () {\r
5365                     var keys = [];\r
5366                     for (var i = 0; i < stack.length; i++) {\r
5367                         keys.push(stack[i].key);\r
5368                     }\r
5369                     return keys;\r
5370                 },\r
5371                 top: function () {\r
5372                     return stack[stack.length - 1];\r
5373                 },\r
5374                 remove: function (key) {\r
5375                     var idx = -1;\r
5376                     for (var i = 0; i < stack.length; i++) {\r
5377                         if (key === stack[i].key) {\r
5378                             idx = i;\r
5379                             break;\r
5380                         }\r
5381                     }\r
5382                     return stack.splice(idx, 1)[0];\r
5383                 },\r
5384                 removeTop: function () {\r
5385                     return stack.splice(stack.length - 1, 1)[0];\r
5386                 },\r
5387                 length: function () {\r
5388                     return stack.length;\r
5389                 }\r
5390             };\r
5391         }\r
5392     };\r
5393 }).factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', function ($document, $isElement, DOMHelper, keymap) {\r
5394     var elementStack = [];\r
5395     var stackHead = undefined;\r
5396     var firstTabableElement, lastTabableElement;\r
5397 \r
5398     var trapKeyboardFocusInFirstElement = function (e) {\r
5399         if (!e.keyCode) {\r
5400             e.keyCode = e.which;\r
5401         }\r
5402 \r
5403         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {\r
5404             lastTabableElement[0].focus();\r
5405             e.preventDefault(e);\r
5406             e.stopPropagation(e);\r
5407         }\r
5408 \r
5409     };\r
5410 \r
5411     var trapKeyboardFocusInLastElement = function (e) {\r
5412         if (!e.keyCode) {\r
5413             e.keyCode = e.which;\r
5414         }\r
5415 \r
5416         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {\r
5417             firstTabableElement[0].focus();\r
5418             e.preventDefault(e);\r
5419             e.stopPropagation(e);\r
5420         }\r
5421     };\r
5422     \r
5423     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {\r
5424         var bodyElements = $document.find('body').children();\r
5425 \r
5426         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(DOMHelper.firstTabableElement(stackHead));\r
5427         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(DOMHelper.lastTabableElement(stackHead));\r
5428 \r
5429         if (flag) {\r
5430             for (var i = 0; i < bodyElements.length; i++) {\r
5431                 if (bodyElements[i] !== stackHead[0]) {\r
5432                     bodyElements.eq(i).attr('aria-hidden', true);\r
5433                 }\r
5434             }\r
5435             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);\r
5436             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);\r
5437         } else {\r
5438             for (var j = 0; j < bodyElements.length; j++) {\r
5439                 if (bodyElements[j] !== stackHead[0]) {\r
5440                     bodyElements.eq(j).removeAttr('aria-hidden');\r
5441                 }\r
5442             }\r
5443             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);\r
5444             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);\r
5445         }\r
5446     };\r
5447     var toggleTrapFocusInElement = function (flag, element) {\r
5448         if (angular.isDefined(flag) && angular.isDefined(element)) {\r
5449             if (angular.isUndefined(stackHead)) {\r
5450                 stackHead = element;\r
5451                 trapFocusInElement(flag);\r
5452             } else {\r
5453                 if (flag) {\r
5454                     trapFocusInElement(false);\r
5455                     elementStack.push(stackHead);\r
5456                     stackHead = element;\r
5457                     trapFocusInElement(true);\r
5458                 } else {\r
5459                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {\r
5460                         trapFocusInElement(false);\r
5461                         stackHead = elementStack.pop();\r
5462                         if (angular.isDefined(stackHead)) {\r
5463                             trapFocusInElement(true);\r
5464                         }\r
5465                     }\r
5466                 }\r
5467             }\r
5468         }else {\r
5469             if (angular.isDefined(stackHead)) {\r
5470                 trapFocusInElement(false, firstTabableElement, lastTabableElement);\r
5471                 trapFocusInElement(true);\r
5472             }\r
5473         }\r
5474     };\r
5475 \r
5476     return toggleTrapFocusInElement;\r
5477 }])\r
5478 \r
5479 /**\r
5480  * A helper directive for the $modal service. It creates a backdrop element.\r
5481  */\r
5482 .directive('b2bModalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) {\r
5483     return {\r
5484         restrict: 'EA',\r
5485         replace: true,\r
5486         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-backdrop.html',\r
5487         link: function (scope, element, attrs) {\r
5488             scope.close = function (evt) {\r
5489                 var modal = $modalStack.getTop();\r
5490                 if (modal && modal.value.backdrop && modal.value.backdrop !== 'static') {\r
5491                     evt.preventDefault();\r
5492                     evt.stopPropagation();\r
5493                     $modalStack.dismiss(modal.key, 'backdrop click');\r
5494                 }\r
5495             };\r
5496         }\r
5497     };\r
5498 }])\r
5499 \r
5500 .directive('b2bModalWindow', ['$timeout', 'windowOrientation', '$window', function ($timeout, windowOrientation, $window) {\r
5501     return {\r
5502         restrict: 'EA',\r
5503         scope: {\r
5504             index: '@'\r
5505         },\r
5506         replace: true,\r
5507         transclude: true,\r
5508         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-window.html',\r
5509         controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {\r
5510             scope.windowClass = attrs.windowClass || '';\r
5511             scope.sizeClass = attrs.sizeClass || '';\r
5512             scope.isNotifDialog = false;\r
5513 \r
5514             this.setTitle = function (title) {\r
5515                 scope.title = title;\r
5516             };\r
5517             this.setContent = function (content) {\r
5518                 scope.content = content;\r
5519                 scope.isNotifDialog = true;\r
5520             };\r
5521             this.isDockedModal = scope.windowClass.indexOf('modal-docked') > -1;\r
5522         }],\r
5523         link: function (scope, element, attrs, ctrl) {\r
5524             if (ctrl.isDockedModal) {\r
5525                 scope.isModalLandscape = false;\r
5526 \r
5527                 var window = angular.element($window);\r
5528                 scope.updateCss = function () {\r
5529                     if (windowOrientation.isPotrait()) { // Potrait Mode\r
5530                         scope.isModalLandscape = false;\r
5531                     } else if (windowOrientation.isLandscape()) { // Landscape Mode\r
5532                         scope.isModalLandscape = true;\r
5533                     }\r
5534                 };\r
5535 \r
5536                 $timeout(function () {\r
5537                     scope.updateCss();\r
5538                     scope.$apply();\r
5539                 }, 100);\r
5540                 window.bind('orientationchange', function () {\r
5541                     scope.updateCss();\r
5542                     scope.$apply();\r
5543                 });\r
5544                 window.bind('resize', function () {\r
5545                     scope.updateCss();\r
5546                     scope.$apply();\r
5547                 });\r
5548             }else {\r
5549                 angular.element(element[0].querySelectorAll(".awd-select-list")).css({\r
5550                     "max-height": "200px"\r
5551                 });\r
5552             }\r
5553 \r
5554             var isIE = /msie|trident/i.test(navigator.userAgent);\r
5555             if (isIE) {\r
5556                 if(angular.element(element[0].querySelector('.corner-button button.close')).length > 0){\r
5557                     angular.element(element[0].querySelector('.corner-button button.close')).bind('focus', function () {\r
5558                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollLeft = 0;\r
5559                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollTop = 0;\r
5560                     });\r
5561                 }\r
5562             }\r
5563             \r
5564         }\r
5565     };\r
5566 }])\r
5567 \r
5568 .directive('b2bModalTitle', [function () {\r
5569     return {\r
5570         restrict: 'A',\r
5571         require: '^b2bModalWindow',\r
5572         link: function (scope, elem, attr, ctrl) {\r
5573             ctrl.setTitle(attr.id);\r
5574         }\r
5575     };\r
5576 }])\r
5577 \r
5578 .directive('b2bModalContent', [function () {\r
5579     return {\r
5580         restrict: 'A',\r
5581         require: '^b2bModalWindow',\r
5582         link: function (scope, elem, attr, ctrl) {\r
5583             ctrl.setContent(attr.id);\r
5584         }\r
5585     };\r
5586 }])\r
5587 \r
5588 \r
5589 .directive('b2bModalBody', ['$timeout', '$position', '$document', '$window', 'windowOrientation', 'b2bAwdBreakpoints', function ($timeout, $position, $document, $window, windowOrientation, b2bAwdBreakpoints) {\r
5590     return {\r
5591         restrict: 'AC',\r
5592         scope: {\r
5593             index: '@'\r
5594         },\r
5595         require: '^b2bModalWindow',\r
5596         link: function (scope, element, attrs, ctrl) {\r
5597             var window = angular.element($window);\r
5598             var body = $document.find('body').eq(0);\r
5599             scope.setModalHeight = function () {\r
5600                 var modalHeaderHeight, modalFooterHeight, modalBodyHeight, windowHeight, windowWidth, modalHeight;\r
5601                 modalHeaderHeight = 0;\r
5602                 modalFooterHeight = 0;\r
5603                 windowHeight = $window.innerHeight;\r
5604                 windowWidth = $window.innerWidth;\r
5605                 body.css({\r
5606                     'height': windowHeight + 'px'\r
5607                 });\r
5608 \r
5609                 if (ctrl.isDockedModal) {\r
5610                     var modalElements = element.parent().children();\r
5611                     for (var i = 0; i < modalElements.length; i++) {\r
5612                         if (modalElements.eq(i).hasClass('b2b-modal-header')) {\r
5613                             modalHeaderHeight = $position.position(modalElements.eq(i)).height;\r
5614                         } else if (modalElements.eq(i).hasClass('b2b-modal-footer')) {\r
5615                             modalFooterHeight = $position.position(modalElements.eq(i)).height;\r
5616                         }\r
5617                     }\r
5618 \r
5619                     modalHeight = $position.position(element.parent()).height;\r
5620 \r
5621                     modalBodyHeight = modalHeight - (modalHeaderHeight + modalFooterHeight) + 'px';\r
5622 \r
5623                     if (windowOrientation.isPotrait()) { // Potrait Mode\r
5624                         element.removeAttr('style').css({\r
5625                             height: modalBodyHeight\r
5626                         });\r
5627                     } else if (windowOrientation.isLandscape() && windowWidth < b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Mobile\r
5628                         element.removeAttr('style');\r
5629                     } else if (windowOrientation.isLandscape() && windowWidth >= b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Non-Mobile\r
5630                         element.removeAttr('style').css({\r
5631                             height: modalBodyHeight\r
5632                         });\r
5633                     }\r
5634                 }\r
5635             };\r
5636 \r
5637             $timeout(function () {\r
5638                 scope.setModalHeight();\r
5639                 scope.$apply();\r
5640             }, 100);\r
5641             window.bind('orientationchange', function () {\r
5642                 scope.setModalHeight();\r
5643                 scope.$apply();\r
5644             });\r
5645             window.bind('resize', function () {\r
5646                 scope.setModalHeight();\r
5647                 scope.$apply();\r
5648             });\r
5649         }\r
5650     };\r
5651 }])\r
5652 \r
5653 .directive('b2bModalFooter', ['windowOrientation', '$window', function (windowOrientation, $window) {\r
5654     return {\r
5655         restrict: 'AC',\r
5656         scope: {\r
5657             index: '@'\r
5658         },\r
5659         link: function (scope, element, attrs) {\r
5660 \r
5661         }\r
5662     };\r
5663 }])\r
5664 \r
5665 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', '$log', '$timeout', 'trapFocusInElement', function ($document, $compile, $rootScope, $$stackedMap, $log, $timeout, trapFocusInElement) {\r
5666     var backdropjqLiteEl, backdropDomEl;\r
5667     var backdropScope = $rootScope.$new(true);\r
5668     var body = $document.find('body').eq(0);\r
5669     var html = $document.find('html').eq(0);\r
5670     var openedWindows = $$stackedMap.createNew();\r
5671     var $modalStack = {};\r
5672 \r
5673     function backdropIndex() {\r
5674         var topBackdropIndex = -1;\r
5675         var opened = openedWindows.keys();\r
5676         for (var i = 0; i < opened.length; i++) {\r
5677             if (openedWindows.get(opened[i]).value.backdrop) {\r
5678                 topBackdropIndex = i;\r
5679             }\r
5680         }\r
5681         return topBackdropIndex;\r
5682     }\r
5683 \r
5684     $rootScope.$watch(backdropIndex, function (newBackdropIndex) {\r
5685         backdropScope.index = newBackdropIndex;\r
5686     });\r
5687 \r
5688     function removeModalWindow(modalInstance) {\r
5689         //background scroll fix\r
5690         html.removeAttr('style');\r
5691         body.removeAttr('style');\r
5692         body.removeClass('styled-by-modal');\r
5693 \r
5694         var modalWindow = openedWindows.get(modalInstance).value;\r
5695         trapFocusInElement(false, modalWindow.modalDomEl);\r
5696 \r
5697         //clean up the stack\r
5698         openedWindows.remove(modalInstance);\r
5699 \r
5700         //remove window DOM element\r
5701         modalWindow.modalDomEl.remove();\r
5702 \r
5703         //remove backdrop if no longer needed\r
5704         if (backdropDomEl && backdropIndex() === -1) {\r
5705             backdropDomEl.remove();\r
5706             backdropDomEl = undefined;\r
5707         }\r
5708 \r
5709         //destroy scope\r
5710         modalWindow.modalScope.$destroy();\r
5711     }\r
5712 \r
5713     $document.bind('keydown', function (evt) {\r
5714         var modal;\r
5715 \r
5716         if (evt.which === 27) {\r
5717             modal = openedWindows.top();\r
5718             if (modal && modal.value.keyboard) {\r
5719                 $rootScope.$apply(function () {\r
5720                     $modalStack.dismiss(modal.key);\r
5721                 });\r
5722             }\r
5723         }\r
5724     });\r
5725 \r
5726     $modalStack.open = function (modalInstance, modal) {\r
5727 \r
5728         openedWindows.add(modalInstance, {\r
5729             deferred: modal.deferred,\r
5730             modalScope: modal.scope,\r
5731             backdrop: modal.backdrop,\r
5732             keyboard: modal.keyboard\r
5733         });\r
5734 \r
5735         var angularDomEl = angular.element('<div b2b-modal-window></div>');\r
5736         angularDomEl.attr('window-class', modal.windowClass);\r
5737         angularDomEl.attr('size-class', modal.sizeClass);\r
5738         angularDomEl.attr('index', openedWindows.length() - 1);\r
5739         angularDomEl.html(modal.content);\r
5740 \r
5741         var modalDomEl = $compile(angularDomEl)(modal.scope);\r
5742         openedWindows.top().value.modalDomEl = modalDomEl;\r
5743         //background page scroll fix\r
5744         html.css({\r
5745             'overflow-y': 'hidden'\r
5746         });\r
5747         body.css({\r
5748             'overflow-y': 'hidden',\r
5749             'width': '100%',\r
5750             'height': window.innerHeight + 'px'\r
5751         });\r
5752         body.addClass('styled-by-modal');\r
5753         body.append(modalDomEl);\r
5754 \r
5755         if (backdropIndex() >= 0 && !backdropDomEl) {\r
5756             backdropjqLiteEl = angular.element('<div b2b-modal-backdrop></div>');\r
5757             backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);\r
5758             body.append(backdropDomEl);\r
5759         }\r
5760 \r
5761         $timeout(function () {\r
5762 \r
5763             if (modal.scope.$$childHead.isNotifDialog) {\r
5764                 angular.element(modalDomEl).find('button')[0].focus();\r
5765             } else {\r
5766                 angular.element(modalDomEl)[0].focus();\r
5767             }\r
5768             trapFocusInElement(true, angular.element(modalDomEl).eq(0));\r
5769         }, 200);\r
5770     };\r
5771 \r
5772     $modalStack.close = function (modalInstance, result) {\r
5773         var modal = openedWindows.get(modalInstance);\r
5774         if (modal) {\r
5775             modal.value.deferred.resolve(result);\r
5776             removeModalWindow(modalInstance);\r
5777         }\r
5778     };\r
5779 \r
5780     $modalStack.dismiss = function (modalInstance, reason) {\r
5781         var modalWindow = openedWindows.get(modalInstance).value;\r
5782         if (modalWindow) {\r
5783             modalWindow.deferred.reject(reason);\r
5784             removeModalWindow(modalInstance);\r
5785         }\r
5786     };\r
5787 \r
5788     $modalStack.getTop = function () {\r
5789         return openedWindows.top();\r
5790     };\r
5791 \r
5792     return $modalStack;\r
5793 }])\r
5794 \r
5795 .provider('$modal', function () {\r
5796     var $modalProvider = {\r
5797         options: {\r
5798             backdrop: true, //can be also false or 'static'\r
5799             keyboard: true\r
5800         },\r
5801         $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {\r
5802             var $modal = {};\r
5803 \r
5804             function getTemplatePromise(options) {\r
5805                 return options.template ? $q.when(options.template) :\r
5806                     $http.get(options.templateUrl, {\r
5807                         cache: $templateCache\r
5808                     }).then(function (result) {\r
5809                         return result.data;\r
5810                     });\r
5811             }\r
5812 \r
5813             function getResolvePromises(resolves) {\r
5814                 var promisesArr = [];\r
5815                 angular.forEach(resolves, function (value, key) {\r
5816                     if (angular.isFunction(value) || angular.isArray(value)) {\r
5817                         promisesArr.push($q.when($injector.invoke(value)));\r
5818                     }\r
5819                 });\r
5820                 return promisesArr;\r
5821             }\r
5822 \r
5823             $modal.open = function (modalOptions) {\r
5824 \r
5825                 var modalResultDeferred = $q.defer();\r
5826                 var modalOpenedDeferred = $q.defer();\r
5827                 //prepare an instance of a modal to be injected into controllers and returned to a caller\r
5828                 var modalInstance = {\r
5829                     result: modalResultDeferred.promise,\r
5830                     opened: modalOpenedDeferred.promise,\r
5831                     close: function (result) {\r
5832                         $modalStack.close(modalInstance, result);\r
5833                     },\r
5834                     dismiss: function (reason) {\r
5835                         $modalStack.dismiss(modalInstance, reason);\r
5836                     }\r
5837                 };\r
5838 \r
5839                 //merge and clean up options\r
5840                 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);\r
5841                 modalOptions.resolve = modalOptions.resolve || {};\r
5842 \r
5843                 //verify options\r
5844                 if (!modalOptions.template && !modalOptions.templateUrl) {\r
5845                     throw new Error('One of template or templateUrl options is required.');\r
5846                 }\r
5847 \r
5848                 var templateAndResolvePromise =\r
5849                     $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));\r
5850 \r
5851 \r
5852                 templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {\r
5853 \r
5854                     var modalScope = (modalOptions.scope || $rootScope).$new();\r
5855                     modalScope.$close = modalInstance.close;\r
5856                     modalScope.$dismiss = modalInstance.dismiss;\r
5857 \r
5858                     var ctrlInstance, ctrlLocals = {};\r
5859                     var resolveIter = 1;\r
5860 \r
5861                     //controllers\r
5862                     if (modalOptions.controller) {\r
5863                         ctrlLocals.$scope = modalScope;\r
5864                         ctrlLocals.$modalInstance = modalInstance;\r
5865                         angular.forEach(modalOptions.resolve, function (value, key) {\r
5866                             ctrlLocals[key] = tplAndVars[resolveIter++];\r
5867                         });\r
5868 \r
5869                         ctrlInstance = $controller(modalOptions.controller, ctrlLocals);\r
5870                     }\r
5871 \r
5872                     $modalStack.open(modalInstance, {\r
5873                         scope: modalScope,\r
5874                         deferred: modalResultDeferred,\r
5875                         content: tplAndVars[0],\r
5876                         backdrop: modalOptions.backdrop,\r
5877                         keyboard: modalOptions.keyboard,\r
5878                         windowClass: modalOptions.windowClass,\r
5879                         sizeClass: modalOptions.sizeClass\r
5880                     });\r
5881 \r
5882                 }, function resolveError(reason) {\r
5883                     modalResultDeferred.reject(reason);\r
5884                 });\r
5885 \r
5886                 templateAndResolvePromise.then(function () {\r
5887                     modalOpenedDeferred.resolve(true);\r
5888                 }, function () {\r
5889                     modalOpenedDeferred.reject(false);\r
5890                 });\r
5891 \r
5892                 return modalInstance;\r
5893             };\r
5894 \r
5895             return $modal;\r
5896         }]\r
5897     };\r
5898 \r
5899     return $modalProvider;\r
5900 })\r
5901 \r
5902 .directive("b2bModal", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {\r
5903     return {\r
5904         restrict: 'A',\r
5905         scope: {\r
5906             b2bModal: '@',\r
5907             modalController: '@',\r
5908             modalOk: '&',\r
5909             modalCancel: '&',\r
5910             windowClass: '@',\r
5911             sizeClass: '@'\r
5912         },\r
5913         link: function (scope, elm, attr) {\r
5914             elm.bind('click', function (ev) {\r
5915                 var currentPosition = ev.pageY - ev.clientY;\r
5916                 ev.preventDefault();\r
5917                 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {\r
5918                     scope.b2bModal = elm.attr("href");\r
5919                 }\r
5920                 $modal.open({\r
5921                     templateUrl: scope.b2bModal,\r
5922                     controller: scope.modalController,\r
5923                     windowClass: scope.windowClass,\r
5924                     sizeClass: scope.sizeClass\r
5925                 }).result.then(function (value) {\r
5926                     scope.modalOk({\r
5927                         value: value\r
5928                     });\r
5929                     elm[0].focus();\r
5930                 }, function (value) {\r
5931                     scope.modalCancel({\r
5932                         value: value\r
5933                     });\r
5934                     elm[0].focus();\r
5935                 });\r
5936             });\r
5937         }\r
5938     };\r
5939 }])\r
5940 \r
5941 .directive("utilityFilter", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {\r
5942     return {\r
5943         restrict: 'EA',\r
5944         scope: {\r
5945             utilityFilter: '@'\r
5946         },\r
5947         require: 'ngModel',\r
5948         templateUrl: 'b2bTemplate/modal/u-filter.html',\r
5949         link: function (scope, element, attribute, ctrl) {\r
5950             //controller to be passed to $modal service\r
5951             scope.options = angular.copy(scope.$parent.$eval(attribute.ngModel));\r
5952             scope.$parent.$watch(attribute.ngModel, function (newVal, oldVal) {\r
5953                 if (newVal !== oldVal) {\r
5954                     scope.options = newVal;\r
5955                 }\r
5956             });\r
5957             var modalCtrl = function ($scope, options) {\r
5958                 $scope.options = angular.copy(options);\r
5959             };\r
5960 \r
5961             if (angular.isDefined(scope.utilityFilter)) {\r
5962                 scope.templateUrl = scope.utilityFilter;\r
5963             } else {\r
5964                 scope.templateUrl = 'b2bTemplate/modal/u-filter-window.html';\r
5965             }\r
5966             element.bind('click', function (ev) {\r
5967                 var currentPosition = ev.pageY - ev.clientY;\r
5968                 $modal.open({\r
5969                     templateUrl: scope.templateUrl,\r
5970                     controller: modalCtrl,\r
5971                     resolve: {\r
5972                         options: function () {\r
5973                             return scope.options;\r
5974                         }\r
5975                     }\r
5976                 }).result.then(function (value) {\r
5977                     ctrl.$setViewValue(value);\r
5978                     element[0].focus();\r
5979                     $scrollTo(0, currentPosition, 0);\r
5980                 }, function () {\r
5981                     element[0].focus();\r
5982                     $scrollTo(0, currentPosition, 0);\r
5983                 });\r
5984             });\r
5985         }\r
5986     };\r
5987 }]);\r
5988 /**\r
5989  * @ngdoc directive\r
5990  * @name Forms.att:monthSelector\r
5991  *\r
5992  * @description\r
5993  *  <file src="src/monthSelector/docs/readme.md" />\r
5994  *\r
5995  * @usage\r
5996  * <div b2b-monthpicker ng-model="dt" min="minDate" max="maxDate" mode="monthpicker"></div>\r
5997     \r
5998  * @example\r
5999  *  <section id="code">\r
6000         <example module="b2b.att">\r
6001             <file src="src/monthSelector/docs/demo.html" />\r
6002             <file src="src/monthSelector/docs/demo.js" />\r
6003         </example>\r
6004     </section>\r
6005  *\r
6006  */\r
6007 angular.module('b2b.att.monthSelector', ['b2b.att.position', 'b2b.att.utilities'])\r
6008 \r
6009 .constant('b2bMonthpickerConfig', {\r
6010     dateFormat: 'MM/dd/yyyy',\r
6011     dayFormat: 'd',\r
6012     monthFormat: 'MMMM',\r
6013     yearFormat: 'yyyy',\r
6014     dayHeaderFormat: 'EEEE',\r
6015     dayTitleFormat: 'MMMM yyyy',\r
6016     disableWeekend: false,\r
6017     disableSunday: false,\r
6018     disableDates: null,\r
6019     onSelectClose: null,\r
6020     startingDay: 0,\r
6021     minDate: null,\r
6022     maxDate: null,\r
6023     dueDate: null,\r
6024     fromDate: null,\r
6025     legendIcon: null,\r
6026     legendMessage: null,\r
6027     calendarDisabled: false,\r
6028     collapseWait: 0,\r
6029     orientation: 'left',\r
6030     inline: false,\r
6031     mode:0,\r
6032     helperText: 'The date you selected is $date. Double tap to open calendar. Select a date to close the calendar.',\r
6033     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
6034     MonthpickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation','mode','id'],\r
6035     MonthpickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],\r
6036     MonthpickerFunctionAttributes: ['disableDates', 'onSelectClose']\r
6037 })\r
6038 \r
6039 .factory('b2bMonthpickerService', ['b2bMonthpickerConfig', 'dateFilter', function (b2bMonthpickerConfig, dateFilter) {\r
6040     var setAttributes = function (attr, elem) {\r
6041         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {\r
6042             var attributes = b2bMonthpickerConfig.MonthpickerEvalAttributes.concat(b2bMonthpickerConfig.MonthpickerWatchAttributes, b2bMonthpickerConfig.MonthpickerFunctionAttributes);\r
6043             for (var key in attr) {\r
6044                 var val = attr[key];\r
6045                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
6046                     elem.attr(key.toSnakeCase(), key);\r
6047                 }\r
6048             }\r
6049         }\r
6050     };\r
6051 \r
6052     var bindScope = function (attr, scope) {\r
6053         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {\r
6054             var evalFunction = function (key, val) {\r
6055                 scope[key] = scope.$parent.$eval(val);\r
6056             };\r
6057 \r
6058             var watchFunction = function (key, val) {\r
6059                 scope.$parent.$watch(val, function (value) {\r
6060                     scope[key] = value;\r
6061                 });\r
6062                 scope.$watch(key, function (value) {\r
6063                     scope.$parent[val] = value;\r
6064                 });\r
6065             };\r
6066 \r
6067             var evalAttributes = b2bMonthpickerConfig.MonthpickerEvalAttributes;\r
6068             var watchAttributes = b2bMonthpickerConfig.MonthpickerWatchAttributes;\r
6069             for (var key in attr) {\r
6070                 var val = attr[key];\r
6071                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
6072                     evalFunction(key, val);\r
6073                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {\r
6074                     watchFunction(key, val);\r
6075                 }\r
6076             }\r
6077         }\r
6078     };\r
6079 \r
6080     return {\r
6081         setAttributes: setAttributes,\r
6082         bindScope: bindScope\r
6083     };\r
6084 }])\r
6085 \r
6086 .controller('b2bMonthpickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bMonthpickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {\r
6087     var format = {\r
6088             date: getValue($attrs.dateFormat, dtConfig.dateFormat),\r
6089             day: getValue($attrs.dayFormat, dtConfig.dayFormat),\r
6090             month: getValue($attrs.monthFormat, dtConfig.monthFormat),\r
6091             year: getValue($attrs.yearFormat, dtConfig.yearFormat),\r
6092             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),\r
6093             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),\r
6094             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),\r
6095             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday),\r
6096             disableDates: getValue($attrs.disableDates, dtConfig.disableDates)\r
6097         },\r
6098         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);\r
6099 \r
6100     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;\r
6101     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;\r
6102     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;\r
6103     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;\r
6104     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;\r
6105     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;\r
6106     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;\r
6107     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);\r
6108     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);\r
6109     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);\r
6110     $scope.mode = getValue($attrs.mode, dtConfig.mode);\r
6111     \r
6112     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;\r
6113 \r
6114     function getValue(value, defaultValue) {\r
6115         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;\r
6116     }\r
6117 \r
6118     function getDaysInMonth(year, month) {\r
6119         return new Date(year, month, 0).getDate();\r
6120     }\r
6121 \r
6122     function getDates(startDate, n) {\r
6123         var dates = new Array(n);\r
6124         var current = startDate,\r
6125             i = 0;\r
6126         while (i < n) {\r
6127             dates[i++] = new Date(current);\r
6128             current.setDate(current.getDate() + 1);\r
6129         }\r
6130         return dates;\r
6131     }\r
6132 \r
6133     this.updatePosition = function (b2bMonthpickerPopupTemplate) {\r
6134         $scope.position = $position.offset($element);\r
6135         if($element.find('input').length > 0 ){\r
6136             $scope.position.top += $element.find('input').prop('offsetHeight');\r
6137         }else{\r
6138             $scope.position.top += $element.find('a').prop('offsetHeight');\r
6139         }\r
6140         \r
6141         if ($scope.orientation === 'right') {\r
6142             $scope.position.left -= (((b2bMonthpickerPopupTemplate && b2bMonthpickerPopupTemplate.prop('offsetWidth')) || 290) - $element.find('input').prop('offsetWidth'));\r
6143         }\r
6144     };\r
6145 \r
6146     function isSelected(dt) { \r
6147         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {\r
6148             return true;\r
6149         }\r
6150         return false;\r
6151     }\r
6152 \r
6153     function isFromDate(dt) {\r
6154         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {\r
6155             return true;\r
6156         }\r
6157         return false;\r
6158     }\r
6159 \r
6160     function isDateRange(dt) {\r
6161         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {\r
6162             return true;\r
6163         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {\r
6164             return true;\r
6165         }\r
6166         return false;\r
6167     }\r
6168 \r
6169     function isOld(date, currentMonthDate) {\r
6170         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
6171             return true;\r
6172         } else {\r
6173             return false;\r
6174         }\r
6175     }\r
6176 \r
6177     function isNew(date, currentMonthDate) {\r
6178         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
6179             return true;\r
6180         } else {\r
6181             return false;\r
6182         }\r
6183     }\r
6184 \r
6185     function isPastDue(dt) {\r
6186         if ($scope.dueDate) {\r
6187             return (dt > $scope.dueDate);\r
6188         }\r
6189         return false;\r
6190     }\r
6191 \r
6192     function isDueDate(dt) {\r
6193         if ($scope.dueDate) {\r
6194             return (dt.getTime() === $scope.dueDate.getTime());\r
6195         }\r
6196         return false;\r
6197     }\r
6198 \r
6199     var isDisabled = function (date, currentMonthDate) {\r
6200         if ($attrs.from && !angular.isDate($scope.fromDate)) {\r
6201             return true;\r
6202         }\r
6203         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {\r
6204             return true;\r
6205         }\r
6206         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {\r
6207             return true;\r
6208         }\r
6209         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {\r
6210             return true;\r
6211         }\r
6212         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({\r
6213             date: date\r
6214         })));\r
6215     };\r
6216     \r
6217     var isDisabledMonth = function (date, currentMonthDate) {\r
6218         if ($attrs.from && !angular.isDate($scope.fromDate)) {\r
6219             return true;\r
6220         }\r
6221         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {\r
6222             return true;\r
6223         }\r
6224         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {\r
6225             return true;\r
6226         }\r
6227         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({\r
6228             date: date\r
6229         })));\r
6230     };    \r
6231          \r
6232     var compare = function (date1, date2) {\r
6233         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));\r
6234     };\r
6235 \r
6236     function isMinDateAvailable(startDate, endDate) {\r
6237         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {\r
6238             $scope.disablePrev = true;\r
6239             $scope.visibilityPrev = "hidden";\r
6240         } else {\r
6241             $scope.disablePrev = false;\r
6242             $scope.visibilityPrev = "visible";\r
6243         }\r
6244     }\r
6245     \r
6246     function isMaxDateAvailable(startDate, endDate) {\r
6247         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {\r
6248             $scope.disableNext = true;\r
6249             $scope.visibilityNext = "hidden";\r
6250         } else {\r
6251             $scope.disableNext = false;\r
6252             $scope.visibilityNext = "visible";\r
6253         }\r
6254     }    \r
6255     \r
6256     function isYearInRange(currentYear) {\r
6257             \r
6258         if ($scope.minDate && currentYear === $scope.minDate.getFullYear()) {\r
6259             $scope.disablePrev = true;\r
6260             $scope.visibilityPrev = "hidden";\r
6261         } else {\r
6262             $scope.disablePrev = false;\r
6263             $scope.visibilityPrev = "visible";\r
6264         }\r
6265         \r
6266         if ($scope.maxDate && currentYear === $scope.maxDate.getFullYear()) {\r
6267             $scope.disableNext = true;\r
6268             $scope.visibilityNext = "hidden";\r
6269         } else {\r
6270             $scope.disableNext = false;\r
6271             $scope.visibilityNext = "visible";\r
6272         }\r
6273         \r
6274     }    \r
6275 \r
6276     this.focusNextPrev = function(b2bMonthpickerPopupTemplate,init){\r
6277         if(init){\r
6278             if (!$scope.disablePrev){\r
6279                 b2bMonthpickerPopupTemplate[0].querySelector('th.prev').focus();\r
6280             }else if (!$scope.disableNext){\r
6281                 b2bMonthpickerPopupTemplate[0].querySelector('th.next').focus();\r
6282             }else{\r
6283                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();\r
6284             }\r
6285         }else{\r
6286             if ($scope.disableNext || $scope.disablePrev){\r
6287                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();\r
6288             }       \r
6289         }    \r
6290     };\r
6291 \r
6292     function getLabel(label) {\r
6293         if (label) {\r
6294             var labelObj = {\r
6295                 pre: label.substr(0, 1).toUpperCase(),\r
6296                 post: label\r
6297             };\r
6298             return labelObj;\r
6299         }\r
6300         return;\r
6301     }\r
6302 \r
6303     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {\r
6304         return {\r
6305             date: date,\r
6306             label: dateFilter(date, dayFormat),\r
6307             header: dateFilter(date, dayHeaderFormat),\r
6308             selected: !!isSelected,\r
6309             fromDate: !!isFromDate,\r
6310             dateRange: !!isDateRange,\r
6311             oldMonth: !!isOld,\r
6312             nextMonth: !!isNew,\r
6313             disabled: !!isDisabled,\r
6314             dueDate: !!dueDate,\r
6315             pastDue: !!pastDue,\r
6316             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))\r
6317         };\r
6318     }\r
6319     \r
6320     this.modes = [\r
6321         {\r
6322             name: 'day',\r
6323             getVisibleDates: function (date) {\r
6324                 var year = date.getFullYear(),\r
6325                     month = date.getMonth(),\r
6326                     firstDayOfMonth = new Date(year, month, 1),\r
6327                     lastDayOfMonth = new Date(year, month + 1, 0);\r
6328                 var difference = startingDay - firstDayOfMonth.getDay(),\r
6329                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,\r
6330                     firstDate = new Date(firstDayOfMonth),\r
6331                     numDates = 0;\r
6332 \r
6333                 if (numDisplayedFromPreviousMonth > 0) {\r
6334                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);\r
6335                     numDates += numDisplayedFromPreviousMonth; // Previous\r
6336                 }\r
6337                 numDates += getDaysInMonth(year, month + 1); // Current\r
6338                 numDates += (7 - numDates % 7) % 7; // Next\r
6339 \r
6340                 var days = getDates(firstDate, numDates),\r
6341                     labels = new Array(7);\r
6342                 for (var i = 0; i < numDates; i++) {\r
6343                     var dt = new Date(days[i]);\r
6344                     days[i] = makeDate(dt,\r
6345                         format.day,\r
6346                         format.dayHeader,\r
6347                         isSelected(dt),\r
6348                         isFromDate(dt),\r
6349                         isDateRange(dt),\r
6350                         isOld(dt, date),\r
6351                         isNew(dt, date),\r
6352                         isDisabled(dt, date),\r
6353                         isDueDate(dt),\r
6354                         isPastDue(dt));\r
6355                 }\r
6356                 for (var j = 0; j < 7; j++) {\r
6357                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));\r
6358                 }\r
6359                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);\r
6360                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);\r
6361                 return {\r
6362                     objects: days,\r
6363                     title: dateFilter(date, format.dayTitle),\r
6364                     labels: labels\r
6365                 };\r
6366             },\r
6367             split: 7,\r
6368             step: {\r
6369                 months: 1\r
6370             }\r
6371         },\r
6372         {\r
6373             name: 'month',\r
6374             getVisibleDates: function(date) {\r
6375                 var months = [], \r
6376                     labels = [], \r
6377                     year = date.getFullYear();\r
6378                     for (var i = 0; i < 12; i++) {\r
6379                         var dt = new Date(year,i,1);                \r
6380                         months[i] = makeDate(dt,\r
6381                                     format.month,\r
6382                                     format.dayHeader,\r
6383                                     isSelected(dt), \r
6384                                     isFromDate(dt),\r
6385                                     isDateRange(dt),\r
6386                                     false,\r
6387                                     false,\r
6388                                     isDisabledMonth(dt, date),\r
6389                                     isDueDate(dt),                                       \r
6390                                     isPastDue(dt));                                                                                                                                                         \r
6391                     }\r
6392                 isYearInRange(year);  \r
6393                 return {objects: months, title: dateFilter(date, format.year), labels: labels};\r
6394             },\r
6395             split:4,\r
6396             step: {years: 1}\r
6397         }\r
6398     ];\r
6399 }])\r
6400 \r
6401 .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
6402     return {\r
6403         restrict: 'EA',\r
6404         scope: {\r
6405           trigger: '='\r
6406         },\r
6407         replace: true,\r
6408         transclude: true,\r
6409         templateUrl: function (elem, attr) {\r
6410             if (attr.inline === 'true') {\r
6411                 return 'b2bTemplate/monthSelector/monthSelector-popup.html';\r
6412             }else if (attr.link === 'true') {\r
6413                 return 'b2bTemplate/monthSelector/monthSelectorLink.html';\r
6414             }else {\r
6415                 return 'b2bTemplate/monthSelector/monthSelector.html';\r
6416             }\r
6417         },\r
6418         scope: {},\r
6419         require: ['b2bMonthpickerPopup', 'ngModel', '?^b2bMonthpickerGroup'],\r
6420         controller: 'b2bMonthpickerController',\r
6421         link: function (scope, element, attrs, ctrls) {\r
6422             var MonthpickerCtrl = ctrls[0],\r
6423                 ngModel = ctrls[1],\r
6424                 b2bMonthpickerGroupCtrl = ctrls[2];\r
6425             var b2bMonthpickerPopupTemplate;\r
6426 \r
6427             if (!ngModel) {\r
6428                 $log.error("ng-model is required.");\r
6429                 return; // do nothing if no ng-model\r
6430             }\r
6431 \r
6432             // Configuration parameters\r
6433             var mode = scope.mode,\r
6434                 selected;\r
6435             scope.isOpen = false;\r
6436 \r
6437             scope.headers = [];\r
6438             scope.footers = [];\r
6439             scope.triggerInterval=undefined;\r
6440 \r
6441 \r
6442             if (b2bMonthpickerGroupCtrl) {\r
6443                 b2bMonthpickerGroupCtrl.registerMonthpickerScope(scope);\r
6444             }\r
6445 \r
6446             element.bind('keydown', function (ev) {                   \r
6447                 if (!ev.keyCode) {\r
6448                     if (ev.which) {\r
6449                         ev.keyCode = ev.which;\r
6450                     } else if (ev.charCode) {\r
6451                         ev.keyCode = ev.charCode;\r
6452                     }\r
6453                 }                                \r
6454                 if(ev.keyCode === keymap.KEY.ESC)\r
6455                 {\r
6456                     scope.isOpen = false;\r
6457                     toggleCalendar(scope.isOpen);\r
6458                     scope.$apply();\r
6459                 }\r
6460             });\r
6461             \r
6462             element.find('button').bind('click', function () {\r
6463                 onClicked();                \r
6464             });\r
6465 \r
6466             element.find('a').bind('click', function () {\r
6467                 onClicked();                \r
6468             });\r
6469 \r
6470             \r
6471             element.find('input').bind('click', function () {\r
6472                 onClicked();\r
6473             });\r
6474 \r
6475             var onClicked = function() {        \r
6476                 if (!scope.ngDisabled) {\r
6477                     scope.isOpen = !scope.isOpen;\r
6478                     toggleCalendar(scope.isOpen);                    \r
6479                     MonthpickerCtrl.updatePosition(b2bMonthpickerPopupTemplate);\r
6480                     scope.$apply();\r
6481                 }\r
6482             };\r
6483         \r
6484             var toggleCalendar = function (flag) {\r
6485                 if (!scope.inline) {\r
6486                     if (flag) {\r
6487                         b2bMonthpickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/monthSelector/monthSelector-popup.html'));\r
6488                         b2bMonthpickerPopupTemplate.attr('b2b-trap-focus-inside-element', 'false');\r
6489                         b2bMonthpickerPopupTemplate.attr('trigger', 'true');\r
6490                         b2bMonthpickerPopupTemplate = $compile(b2bMonthpickerPopupTemplate)(scope);\r
6491                         $document.find('body').append(b2bMonthpickerPopupTemplate);\r
6492                         b2bMonthpickerPopupTemplate.bind('keydown', escPress);\r
6493                         $timeout(function () {\r
6494                             scope.getFocus = true;\r
6495                             scope.trigger=0;\r
6496                             scope.$apply();\r
6497                             $timeout(function () {\r
6498                                 scope.getFocus = false;\r
6499                                 scope.$apply();\r
6500                                 MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,true);\r
6501                             }, 100);\r
6502                         });\r
6503                         scope.triggerInterval = $interval(function () {\r
6504                             //This value is updated to trigger init() function of directive on year change.\r
6505                             scope.trigger=(scope.trigger === 0 ? 1 : 0);\r
6506                         }, 200);\r
6507 \r
6508                     } else {\r
6509                         b2bMonthpickerPopupTemplate.unbind('keydown', escPress);\r
6510                         if(scope.triggerInterval)\r
6511                         {\r
6512                             $interval.cancel(scope.triggerInterval);\r
6513                             scope.triggerInterval=undefined;\r
6514                         }\r
6515                         b2bMonthpickerPopupTemplate.remove();\r
6516                         if(element.find('button').length > 0){\r
6517                             element.find('button')[0].focus();\r
6518                         }else{\r
6519                             element.find('a')[0].focus();\r
6520                         }\r
6521                         \r
6522                         scope.getFocus = false;\r
6523                     }\r
6524                 }\r
6525             };\r
6526 \r
6527             var outsideClick = function (e) {\r
6528                 var isElement = $isElement(angular.element(e.target), element, $document);\r
6529                 var isb2bMonthpickerPopupTemplate = $isElement(angular.element(e.target), b2bMonthpickerPopupTemplate, $document);\r
6530                 if (!(isElement || isb2bMonthpickerPopupTemplate)) {\r
6531                     scope.isOpen = false;\r
6532                     toggleCalendar(scope.isOpen);\r
6533                     scope.$apply();\r
6534                 }\r
6535             };\r
6536 \r
6537             var escPress = function (ev) {\r
6538                 if (!ev.keyCode) {\r
6539                     if (ev.which) {\r
6540                         ev.keyCode = ev.which;\r
6541                     } else if (ev.charCode) {\r
6542                         ev.keyCode = ev.charCode;\r
6543                     }\r
6544                 }\r
6545                 if (ev.keyCode) {\r
6546                     if (ev.keyCode === keymap.KEY.ESC) {\r
6547                         scope.isOpen = false;\r
6548                         toggleCalendar(scope.isOpen);\r
6549                         ev.preventDefault();\r
6550                         ev.stopPropagation();\r
6551                     } else if (ev.keyCode === 33) {\r
6552                         !scope.disablePrev && scope.move(-1);\r
6553                         $timeout(function () {\r
6554                             scope.getFocus = true;\r
6555                             scope.$apply();\r
6556                             $timeout(function () {\r
6557                                 scope.getFocus = false;\r
6558                                 scope.$apply();\r
6559                             }, 100);\r
6560                         });\r
6561                         ev.preventDefault();\r
6562                         ev.stopPropagation();\r
6563                     } else if (ev.keyCode === 34) {\r
6564                         !scope.disableNext && scope.move(1);\r
6565                         $timeout(function () {\r
6566                             scope.getFocus = true;\r
6567                             scope.$apply();\r
6568                             $timeout(function () {\r
6569                                 scope.getFocus = false;\r
6570                                 scope.$apply();\r
6571                             }, 100);\r
6572                         });\r
6573                         ev.preventDefault();\r
6574                         ev.stopPropagation();\r
6575                     }\r
6576                     scope.$apply();\r
6577                 }\r
6578             };              \r
6579                     \r
6580             $documentBind.click('isOpen', outsideClick, scope);\r
6581 \r
6582             scope.$on('$destroy', function () {\r
6583                 if (scope.isOpen) {\r
6584                     scope.isOpen = false;\r
6585                     toggleCalendar(scope.isOpen);\r
6586                 }\r
6587             });\r
6588 \r
6589             scope.resetTime = function (date) {\r
6590                 if (typeof date === 'string') {\r
6591                     date = date + 'T12:00:00';\r
6592                 }\r
6593                 var dt;\r
6594                 if (!isNaN(new Date(date))) {\r
6595                     dt = new Date(date);\r
6596                     if(scope.mode === 1){\r
6597                         dt = new Date(dt.getFullYear(), dt.getMonth());\r
6598                     }else{\r
6599                         dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());\r
6600                     }                                                            \r
6601                 } else {\r
6602                     return null;\r
6603                 }\r
6604                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());\r
6605             };\r
6606             \r
6607             if (attrs.min) {\r
6608                 scope.$parent.$watch($parse(attrs.min), function (value) {\r
6609                     scope.minDate = value ? scope.resetTime(value) : null;\r
6610                     refill();\r
6611                 });\r
6612             }\r
6613             if (attrs.max) {\r
6614                 scope.$parent.$watch($parse(attrs.max), function (value) {\r
6615                     scope.maxDate = value ? scope.resetTime(value) : null;\r
6616                     refill();\r
6617                 });\r
6618             }\r
6619             if (attrs.due) {\r
6620                 scope.$parent.$watch($parse(attrs.due), function (value) {\r
6621                     scope.dueDate = value ? scope.resetTime(value) : null;\r
6622                     refill();\r
6623                 });\r
6624             }\r
6625             if (attrs.from) {\r
6626                 scope.$parent.$watch($parse(attrs.from), function (value) {\r
6627                     scope.fromDate = value ? scope.resetTime(value) : null;\r
6628                     refill();\r
6629                 });\r
6630             }\r
6631 \r
6632             if (attrs.legendIcon) {\r
6633                 scope.$parent.$watch(attrs.legendIcon, function (value) {\r
6634                     scope.legendIcon = value ? value : null;\r
6635                     refill();\r
6636                 });\r
6637             }\r
6638             if (attrs.legendMessage) {\r
6639                 scope.$parent.$watch(attrs.legendMessage, function (value) {\r
6640                     scope.legendMessage = value ? value : null;\r
6641                     refill();\r
6642                 });\r
6643             }\r
6644             if (attrs.ngDisabled) {\r
6645                 scope.$parent.$watch(attrs.ngDisabled, function (value) {\r
6646                     scope.ngDisabled = value ? value : null;\r
6647                 });\r
6648             }      \r
6649             \r
6650 \r
6651             // Split array into smaller arrays\r
6652             function split(arr, size) {\r
6653                 var arrays = [];\r
6654                 while (arr.length > 0) {\r
6655                     arrays.push(arr.splice(0, size));\r
6656                 }\r
6657                 return arrays;\r
6658             }\r
6659             \r
6660             var moveMonth = function(selectedDate, direction) {\r
6661                 var step = MonthpickerCtrl.modes[scope.mode].step;\r
6662                 selectedDate.setDate(1);\r
6663                 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));\r
6664                 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));\r
6665 \r
6666                 return selectedDate;\r
6667             };            \r
6668 \r
6669             function refill(date) {\r
6670                 if (angular.isDate(date) && !isNaN(date)) {\r
6671                     selected = new Date(date);\r
6672                 } else {\r
6673                     if (!selected) {\r
6674                         selected = new Date();\r
6675                     }\r
6676                 }\r
6677 \r
6678                 if (selected) {                    \r
6679                     var selectedCalendar;\r
6680                     if(scope.mode === 1){\r
6681                         if(!angular.isDate(selected))\r
6682                            {                           \r
6683                                 selected = new Date();\r
6684                            }\r
6685                         selectedCalendar = moveMonth(angular.copy(selected), -1);\r
6686                     } else {\r
6687                         selectedCalendar = angular.copy(selected);\r
6688                     }\r
6689                     \r
6690                     var currentMode = MonthpickerCtrl.modes[mode],\r
6691                         data = currentMode.getVisibleDates(selected);\r
6692 \r
6693                     scope.rows = split(data.objects, currentMode.split);\r
6694             \r
6695                     var flag=false;\r
6696                     var startFlag=false;\r
6697                     var firstSelected = false;\r
6698                     for(var i=0; i<scope.rows.length; i++)\r
6699                     {\r
6700                         for(var j=0; j<scope.rows[i].length; j++)\r
6701                         {\r
6702                             if(!scope.rows[i][j].disabled && !firstSelected)\r
6703                             {\r
6704                                 firstSelected=true;\r
6705                                 var firstDay = scope.rows[i][j];\r
6706                             }\r
6707 \r
6708                             if(scope.rows[i][j].selected)\r
6709                             {\r
6710                                 flag=true;\r
6711                                 break;\r
6712                             }                  \r
6713                         }\r
6714                         if(flag)\r
6715                         {\r
6716                             break;\r
6717                         }\r
6718                     }\r
6719                     if(!flag && firstSelected)\r
6720                     {\r
6721                        firstDay.firstFocus=true;\r
6722                     }\r
6723 \r
6724                     scope.labels = data.labels || [];\r
6725                     scope.title = data.title;                    \r
6726                 }\r
6727             }\r
6728 \r
6729             scope.select = function (date,$event) {\r
6730                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());\r
6731                 scope.currentDate = dt;\r
6732                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({\r
6733                         date: dt\r
6734                     }) !== false)) {\r
6735                     if (angular.isNumber(scope.collapseWait)) {\r
6736                         $timeout(function () {\r
6737                             scope.isOpen = false;\r
6738                             toggleCalendar(scope.isOpen);\r
6739                         }, scope.collapseWait);\r
6740                     } else {\r
6741                         scope.isOpen = false;\r
6742                         toggleCalendar(scope.isOpen);\r
6743                     }\r
6744                 }\r
6745             };\r
6746 \r
6747             scope.move = function (direction,$event) {\r
6748                 var step = MonthpickerCtrl.modes[mode].step;\r
6749                 selected.setDate(1);\r
6750                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));\r
6751                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));\r
6752                 refill();\r
6753                 scope.getFocus = true;\r
6754                 $timeout(function () {\r
6755                     if (attrs.inline === 'true') {\r
6756                         MonthpickerCtrl.focusNextPrev(element,false); \r
6757                     }else{\r
6758                         MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,false);\r
6759                     }\r
6760                 },100);\r
6761                 $event.preventDefault();\r
6762                 $event.stopPropagation();\r
6763             };\r
6764 \r
6765             scope.$watch('currentDate', function (value) {\r
6766                 if (angular.isDefined(value) && value !== null) {\r
6767                     refill(value);\r
6768                 } else {\r
6769                     refill();\r
6770                 }\r
6771                 ngModel.$setViewValue(value);\r
6772             });\r
6773 \r
6774             ngModel.$render = function () {\r
6775                 scope.currentDate = ngModel.$viewValue;\r
6776             };\r
6777 \r
6778             var stringToDate = function (value) {\r
6779                 if (!isNaN(new Date(value))) {\r
6780                     value = new Date(value);\r
6781                 }\r
6782                 return value;\r
6783             };\r
6784             ngModel.$formatters.unshift(stringToDate);\r
6785         }\r
6786     };\r
6787 }])\r
6788 \r
6789 .directive('b2bMonthpicker', ['$compile', '$log', 'b2bMonthpickerConfig', 'b2bMonthpickerService', function ($compile, $log, b2bMonthpickerConfig, b2bMonthpickerService) {\r
6790     return {\r
6791         restrict: 'A',\r
6792         scope: {\r
6793             disableDates: '&',\r
6794             onSelectClose: '&'\r
6795         },\r
6796         require: 'ngModel',\r
6797         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
6798             var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : b2bMonthpickerConfig.dateFormat;\r
6799             var helperText = angular.isDefined(attr.helperText) ? scope.$parent.$eval(attr.helperText) : b2bMonthpickerConfig.helperText; \r
6800             helperText = helperText.replace('$date', '{{dt | date : \'' + dateFormatString + '\'}}');\r
6801 \r
6802             var descriptionText = angular.isDefined(attr.descriptionText) ? scope.$parent.$eval(attr.descriptionText) : b2bMonthpickerConfig.descriptionText;  \r
6803 \r
6804 \r
6805             var inline = false;\r
6806             if (elem.prop('nodeName') !== 'INPUT' && elem.prop('nodeName') !== 'A') {\r
6807                 inline = true;\r
6808             }\r
6809 \r
6810             var selectedDateMessage = "";\r
6811             \r
6812             if (elem.prop('nodeName') !== 'A'){\r
6813                 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
6814                 elem.attr('tabindex', '-1'); \r
6815                 elem.attr('aria-hidden', 'true');  \r
6816                 elem.attr('readonly', 'true'); \r
6817             }else{\r
6818                 selectedDateMessage = ''\r
6819                 elem.attr('aria-label', helperText);\r
6820             }\r
6821             \r
6822             var descriptionTextSpan = '<span class="offscreen-text" id="monthpicker-description'+scope.$id+'">'+descriptionText+'</span>';\r
6823             elem.removeAttr('b2b-Monthpicker');\r
6824             elem.removeAttr('ng-model');\r
6825             elem.removeAttr('ng-disabled');\r
6826             elem.addClass('Monthpicker-input');\r
6827             elem.attr('ng-model', 'dt');\r
6828             elem.attr('aria-describedby', 'monthpicker-description'+scope.$id);\r
6829             \r
6830             \r
6831             \r
6832             elem.attr('ng-disabled', 'ngDisabled');\r
6833             elem.attr('b2b-format-date', dateFormatString);\r
6834 \r
6835             var wrapperElement = angular.element('<div></div>');\r
6836             wrapperElement.attr('b2b-Monthpicker-popup', '');\r
6837             wrapperElement.attr('ng-model', 'dt');\r
6838             if (inline) {\r
6839                 wrapperElement.attr('inline', inline);\r
6840             }\r
6841             if (elem.prop('nodeName') === 'A'){\r
6842                 wrapperElement.attr('link', true);\r
6843             }\r
6844             b2bMonthpickerService.setAttributes(attr, wrapperElement);\r
6845             b2bMonthpickerService.bindScope(attr, scope);\r
6846 \r
6847             wrapperElement.html('');\r
6848             wrapperElement.append(selectedDateMessage);\r
6849             wrapperElement.append('');\r
6850             wrapperElement.append(descriptionTextSpan);\r
6851             wrapperElement.append('');\r
6852             wrapperElement.append(elem.prop('outerHTML'));\r
6853 \r
6854             var elm = wrapperElement.prop('outerHTML');\r
6855             elm = $compile(elm)(scope);\r
6856             elem.replaceWith(elm);\r
6857         }],\r
6858         link: function (scope, elem, attr, ctrl) {\r
6859             if (!ctrl) {\r
6860                 $log.error("ng-model is required.");\r
6861                 return; // do nothing if no ng-model\r
6862             }\r
6863             \r
6864             scope.$watch('dt', function (value) {\r
6865                 ctrl.$setViewValue(value);\r
6866             });\r
6867             ctrl.$render = function () {\r
6868                 scope.dt = ctrl.$viewValue;\r
6869             };\r
6870         }\r
6871     };\r
6872 }])\r
6873 \r
6874 .directive('b2bMonthpickerGroup', [function () {\r
6875     return {\r
6876         restrict: 'EA',\r
6877         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {\r
6878             this.$$headers = [];\r
6879             this.$$footers = [];\r
6880             this.registerMonthpickerScope = function (MonthpickerScope) {\r
6881                 MonthpickerScope.headers = this.$$headers;\r
6882                 MonthpickerScope.footers = this.$$footers;\r
6883             };\r
6884         }],\r
6885         link: function (scope, elem, attr, ctrl) {}\r
6886     };\r
6887 }])\r
6888 \r
6889 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {\r
6890     return {\r
6891         restrict: 'A',\r
6892         require: 'ngModel',\r
6893         link: function (scope, elem, attr, ctrl) {\r
6894             var b2bFormatDate = "";\r
6895             attr.$observe('b2bFormatDate', function (value) {\r
6896                 b2bFormatDate = value;\r
6897             });\r
6898             var dateToString = function (value) {\r
6899                 if (!isNaN(new Date(value))) {\r
6900                     return dateFilter(new Date(value), b2bFormatDate);\r
6901                 }\r
6902                 return value;\r
6903             };\r
6904             ctrl.$formatters.unshift(dateToString);\r
6905         }\r
6906     };\r
6907 }])\r
6908 \r
6909 .directive('b2bMonthpickerHeader', [function () {\r
6910     return {\r
6911         restrict: 'EA',\r
6912         require: '^b2bMonthpickerGroup',\r
6913         transclude: true,\r
6914         replace: true,\r
6915         template: '',\r
6916         compile: function (elem, attr, transclude) {\r
6917             return function link(scope, elem, attr, ctrl) {\r
6918                 if (ctrl) {\r
6919                     ctrl.$$headers.push(transclude(scope, function () {}));\r
6920                 }\r
6921                 elem.remove();\r
6922             };\r
6923         }\r
6924     };\r
6925 }])\r
6926 \r
6927 .directive('b2bMonthpickerFooter', [function () {\r
6928     return {\r
6929         restrict: 'EA',\r
6930         require: '^b2bMonthpickerGroup',\r
6931         transclude: true,\r
6932         replace: true,\r
6933         template: '',\r
6934         compile: function (elem, attr, transclude) {\r
6935             return function link(scope, elem, attr, ctrl) {\r
6936                 if (ctrl) {\r
6937                     ctrl.$$footers.push(transclude(scope, function () {}));\r
6938                 }\r
6939                 elem.remove();\r
6940             };\r
6941         }\r
6942     };\r
6943 }]);\r
6944 /**\r
6945  * @ngdoc directive\r
6946  * @name Navigation.att:multiLevelNavigation\r
6947  *\r
6948  * @description\r
6949  *  <file src="src/multiLevelNavigation/docs/readme.md" />\r
6950  *\r
6951  * @usage\r
6952  *       <div class="b2b-ml-nav">\r
6953  *          <ul role="tree">\r
6954  *             <li aria-label="{{child.name}}" tabindex="-1" b2b-ml-nav="{{child.type}}" role="treeitem" ng-repeat="child in treeStructure">\r
6955  *                  <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
6956  *                      <!-- Below UL tag is RECURSIVE to generate n-childs -->\r
6957  *                      <ul role="group" ng-if="child.child">\r
6958  *                          <li aria-label="{{child.name}}" b2b-ml-nav="{{child.type}}" tabindex="-1" role="treeitem" ng-repeat="child in child.child">\r
6959  *                          <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
6960  *                               <!-- RECURSIVE UL tag goes here -->\r
6961  *                          </li>\r
6962  *                      </ul>\r
6963  *             </li>\r
6964  *           </ul>\r
6965  *        </div>\r
6966  *\r
6967  * @example\r
6968  *  <section id="code">\r
6969         <example module="b2b.att">\r
6970             <file src="src/multiLevelNavigation/docs/demo.html" />\r
6971             <file src="src/multiLevelNavigation/docs/demo.js" />\r
6972        </example>\r
6973     </section>\r
6974  *\r
6975  */\r
6976 angular.module('b2b.att.multiLevelNavigation', ['b2b.att.utilities'])\r
6977     //directive b2bMlNav Test coverage 100% on 5/13\r
6978     .directive('b2bMlNav', ['keymap', function (keymap) {\r
6979         return {\r
6980             restrict: 'EA',\r
6981             link: function (scope, element) {\r
6982                 var rootE, parentE, upE, downE, lastE, homeE, endE;\r
6983                 //default root tree element tabindex set zero\r
6984                 if (element.parent().parent().hasClass('b2b-ml-nav') && (element[0].previousElementSibling === null)) {\r
6985                     element.attr('tabindex', 0);\r
6986                 }\r
6987                 //check root via class\r
6988                 var isRoot = function (elem) {\r
6989                         if (elem.parent().parent().eq(0).hasClass('b2b-ml-nav')) {\r
6990                             return true;\r
6991                         } else {\r
6992                             return false;\r
6993                         }\r
6994 \r
6995                     }\r
6996                     //for any expandable tree item on click\r
6997                 var toggleState = function (e) {\r
6998                     if (angular.element(e.target).attr("b2b-ml-nav") !== "endNode") {\r
6999                         var eLink = element.find('a').eq(0);\r
7000                         if (eLink.hasClass('active')) {\r
7001                             eLink.removeClass('active');\r
7002                             eLink.parent().attr("aria-expanded", "false");\r
7003                             eLink.find('i').eq(0).removeClass('icon-primary-expanded');\r
7004                             eLink.find('i').eq(0).addClass('icon-primary-collapsed');\r
7005                         } else {\r
7006                             eLink.addClass('active');\r
7007                             eLink.parent().attr("aria-expanded", "true");\r
7008                             eLink.find('i').eq(0).removeClass('icon-primary-collapsed');\r
7009                             eLink.find('i').eq(0).addClass('icon-primary-expanded');\r
7010                         }\r
7011                     }\r
7012                 };\r
7013                 //function finds the main root-item from particular tree-group\r
7014                 var findRoot = function (elem) {\r
7015                     if (isRoot(elem)) {\r
7016                         rootE = elem;\r
7017                         return;\r
7018                     }\r
7019                     if (elem.attr("b2b-ml-nav") === "middleNode" || elem.attr("b2b-ml-nav") === "endNode") {\r
7020                         parentE = elem.parent().parent();\r
7021                     } else {\r
7022                         parentE = elem;\r
7023                     }\r
7024                     if (parentE.attr("b2b-ml-nav") === "rootNode") {\r
7025                         rootE = parentE;\r
7026                     } else {\r
7027                         findRoot(parentE);\r
7028                     }\r
7029                 };\r
7030                 //finds the last visible node of the previous tree-group\r
7031                 var findPreActive = function (elem) {\r
7032                     if (!(elem.hasClass("active"))) {\r
7033                         return;\r
7034                     } else {\r
7035                         var childElems = angular.element(elem[0].nextElementSibling.children);\r
7036                         lastE = angular.element(childElems[childElems.length - 1]);\r
7037                         if (lastE.attr("b2b-ml-nav") === "middleNode" && lastE.find('a').eq(0).hasClass('active')) {\r
7038                             findPreActive(lastE.find('a').eq(0));\r
7039                         }\r
7040                         upE = lastE;\r
7041                     }\r
7042                 };\r
7043                 //find above visible link\r
7044                 var findUp = function (elem) {\r
7045                     if (elem[0].previousElementSibling !== null) {\r
7046                         upE = angular.element(elem[0].previousElementSibling);\r
7047                     } else {\r
7048                         upE = elem.parent().parent();\r
7049                     }\r
7050                     if (isRoot(elem) || (upE.attr('b2b-ml-nav') === "middleNode" && upE[0] !== elem.parent().parent()[0])) {\r
7051                         findPreActive(upE.find('a').eq(0)); \r
7052                     }\r
7053                 };\r
7054                 //find below visible link\r
7055                 var findDown = function (elem) {\r
7056                     if (elem.hasClass('active')) {\r
7057                         downE = elem.next().find('li').eq(0);\r
7058                     } else {\r
7059                         if (elem.parent().next().length !== 0) {\r
7060                             downE = elem.parent().next().eq(0);\r
7061                         } else {\r
7062                             if (elem.parent().parent().parent().next().length !== 0) {\r
7063                                 downE = elem.parent().parent().parent().next().eq(0);\r
7064                                 return;\r
7065                             }\r
7066                             downE = elem.parent().eq(0);\r
7067                         }\r
7068                     }\r
7069                 };\r
7070                 //finds last root-group element of the tree\r
7071                 var findEnd = function (elem) {\r
7072                     findRoot(elem);\r
7073                     endE = angular.element(rootE.parent()[0].children[rootE.parent()[0].children.length - 1]);\r
7074                 };\r
7075                 //finds first root element of tree\r
7076                 var findHome = function (elem) {\r
7077                     findRoot(elem);\r
7078                     homeE = angular.element(rootE.parent()[0].children[0]);\r
7079                 };\r
7080                 element.bind('click', function (e) {\r
7081                     if(element.attr("b2b-ml-nav") !== "endNode") { \r
7082                         toggleState(e); \r
7083                     }\r
7084                     e.stopPropagation();\r
7085                 });\r
7086                 element.bind('focus', function (e) {\r
7087                     if(element.attr("b2b-ml-nav") !== "endNode") {\r
7088                         if(element.find('a').eq(0).hasClass('active')) {\r
7089                             element.attr("aria-expanded", true);\r
7090                         }\r
7091                         else {\r
7092                             element.attr("aria-expanded", false);\r
7093                         }\r
7094                         \r
7095                     }\r
7096                 })\r
7097                 //Keyboard functionality approach:\r
7098                 //find keycode\r
7099                 //set set tabindex -1 on the current focus element\r
7100                 //find the next element to be focussed, set tabindex 0 and throw focus\r
7101                 element.bind('keydown', function (evt) {\r
7102                     switch (evt.keyCode) {\r
7103                     case keymap.KEY.ENTER:\r
7104                     case keymap.KEY.SPACE:\r
7105                         element.triggerHandler('click');\r
7106                         evt.stopPropagation();\r
7107                         evt.preventDefault();\r
7108                         break;\r
7109                     case keymap.KEY.END:\r
7110                         evt.preventDefault();\r
7111                         element.attr('tabindex', -1);\r
7112                         findEnd(element);\r
7113                         endE.eq(0).attr('tabindex', 0);\r
7114                         endE[0].focus();\r
7115                         evt.stopPropagation();\r
7116                         break;\r
7117                     case keymap.KEY.HOME:\r
7118                         evt.preventDefault();\r
7119                         element.attr('tabindex', -1);\r
7120                         findHome(element);\r
7121                         homeE.eq(0).attr('tabindex', 0);\r
7122                         homeE[0].focus();\r
7123                         evt.stopPropagation();\r
7124                         break;\r
7125                     case keymap.KEY.LEFT:\r
7126                         evt.preventDefault();\r
7127                         if (!isRoot(element)) {\r
7128                             element.attr('tabindex', -1);\r
7129                             parentE = element.parent().parent();\r
7130                             parentE.eq(0).attr('tabindex', 0);\r
7131                             parentE[0].focus();\r
7132                             parentE.eq(0).triggerHandler('click');\r
7133                         } else {\r
7134                             if (element.find('a').eq(0).hasClass('active')) {\r
7135                                 element.triggerHandler('click');\r
7136                             }\r
7137                         }\r
7138                         evt.stopPropagation();\r
7139                         break;\r
7140                     case keymap.KEY.UP:\r
7141                         evt.preventDefault();\r
7142                         if (!(isRoot(element) && element[0].previousElementSibling === null)) {\r
7143                             element.attr('tabindex', -1);\r
7144                             findUp(element);\r
7145                             upE.eq(0).attr('tabindex', 0);\r
7146                             upE[0].focus();\r
7147                         }\r
7148                         evt.stopPropagation();\r
7149                         break;\r
7150                     case keymap.KEY.RIGHT:\r
7151                         evt.preventDefault();\r
7152                         if (element.attr("b2b-ml-nav") !== "endNode") {\r
7153                             if (!element.find('a').eq(0).hasClass('active')) {\r
7154                                 element.triggerHandler('click');\r
7155                             }\r
7156                             element.attr('tabindex', -1);\r
7157                             findDown(element.find('a').eq(0));\r
7158                             downE.eq(0).attr('tabindex', 0);\r
7159                             downE[0].focus();\r
7160                         }\r
7161                         evt.stopPropagation();\r
7162                         break;\r
7163                     case keymap.KEY.DOWN:\r
7164                         evt.preventDefault();\r
7165                         element.attr('tabindex', -1);\r
7166                         if (!(element.attr("b2b-ml-nav") === "middleNode" && element.find('a').eq(0).hasClass('active')) && (element.next().length === 0)) {\r
7167                             if(element.parent().parent().attr("b2b-ml-nav") !== "rootNode" && element.parent().parent()[0].nextElementSibling !== null)\r
7168                             {\r
7169                                 findDown(element.find('a').eq(0));\r
7170                                 downE.eq(0).attr('tabindex', 0);\r
7171                                 downE[0].focus();\r
7172                                 evt.stopPropagation();\r
7173                                 break;\r
7174                             }\r
7175                             findRoot(element);\r
7176                             if (!(rootE.next().length === 0)) {\r
7177                                 rootE.next().eq(0).attr('tabindex', 0);\r
7178                                 rootE.next()[0].focus();\r
7179                             } else {\r
7180                                 rootE.eq(0).attr('tabindex', 0);\r
7181                                 rootE[0].focus();\r
7182                             }\r
7183                             evt.stopPropagation();\r
7184                             break;\r
7185                         }\r
7186                         findDown(element.find('a').eq(0));\r
7187                         downE.eq(0).attr('tabindex', 0);\r
7188                         downE[0].focus();\r
7189                         evt.stopPropagation();\r
7190                         break;\r
7191                     default:\r
7192                         break;\r
7193                     }\r
7194                 });\r
7195             }\r
7196         };\r
7197     }]);\r
7198 /**\r
7199  * @ngdoc directive\r
7200  * @name Tabs, tables & accordions.att:multipurposeExpander\r
7201  *\r
7202  * @description\r
7203  *  <file src="src/multipurposeExpander/docs/readme.md" />\r
7204  *\r
7205  * @usage\r
7206  * <!--With Close Other -->\r
7207  * <b2b-expander-group close-others="true">\r
7208  *  <b2b-expanders class="mpc-expanders" is-open="testmpc">            \r
7209  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc, 'b2b-toggle-header-inactive': testmpc } ">Heading content goes here</b2b-expander-heading>               \r
7210  *      <b2b-expander-body>\r
7211             <p>body content goes here</p>\r
7212         </b2b-expander-body>\r
7213  *  </b2b-expanders>\r
7214  *  </b2b-expander-group>\r
7215  *  \r
7216  * <!-- Without Close Other -->\r
7217  *  <b2b-expanders class="mpc-expanders" is-open="testmpc2">            \r
7218  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc2, 'b2b-toggle-header-inactive': testmpc2 } ">Heading content goes here</b2b-expander-heading>               \r
7219  *      <b2b-expander-body>\r
7220             <p>body content goes here</p>\r
7221         </b2b-expander-body>\r
7222  *  </b2b-expanders>\r
7223  *  \r
7224  * @example\r
7225  *  <section id="code">\r
7226         <example module="b2b.att.multipurposeExpander">\r
7227             <file src="src/multipurposeExpander/docs/demo.html" />\r
7228             <file src="src/multipurposeExpander/docs/demo.js" />\r
7229         </example>\r
7230     </section>\r
7231  *\r
7232  */\r
7233 \r
7234 angular.module('b2b.att.multipurposeExpander', ['b2b.att', 'b2b.att.collapse'])\r
7235 .directive('b2bExpanderGroup', function () {\r
7236     return {\r
7237         restrict: 'EA',\r
7238         transclude: true,\r
7239         template: "<ng-transclude></ng-transclude>",\r
7240         controller:['$scope','$attrs', function($scope,$attrs){\r
7241             this.groups = [];\r
7242             this.index = -1;            \r
7243             this.scope = $scope;\r
7244             \r
7245             this.addGroup = function (groupScope) {\r
7246                 var that = this;\r
7247                 groupScope.index = this.groups.length;\r
7248                 this.groups.push(groupScope);\r
7249                 if(this.groups.length > 0){\r
7250                     this.index = 0;\r
7251                 }\r
7252                 groupScope.$on('$destroy', function () {\r
7253                 that.removeGroup(groupScope);\r
7254             });\r
7255             };\r
7256 \r
7257             this.closeOthers = function (openGroup) {\r
7258                 var closeOthers = angular.isDefined($attrs.closeOthers);\r
7259                 if (closeOthers && !$scope.forceExpand) {\r
7260                     angular.forEach(this.groups, function (group) {\r
7261                         if (group !== openGroup) {\r
7262                             group.isOpen = false;\r
7263                         }\r
7264                     });\r
7265                 }\r
7266                 if (this.groups.indexOf(openGroup) === (this.groups.length - 1) && $scope.forceExpand) {\r
7267                     $scope.forceExpand = false;\r
7268                 }\r
7269             };\r
7270             this.removeGroup = function (group) {\r
7271             var index = this.groups.indexOf(group);\r
7272             if (index !== -1) {\r
7273                 this.groups.splice(this.groups.indexOf(group), 1);\r
7274             }\r
7275         };\r
7276         }]\r
7277        \r
7278     };\r
7279     \r
7280 })\r
7281 .directive('b2bExpanders', function () {\r
7282     return{\r
7283         restrict: 'EA',\r
7284         replace: true,\r
7285         require:['b2bExpanders','?^b2bExpanderGroup'],\r
7286         transclude: true,\r
7287         scope:{isOpen:'=?'},\r
7288         template: "<div ng-transclude></div>",\r
7289         controller: ['$scope', function ($scope){\r
7290                 var bodyScope = null;\r
7291                 var expanderScope = null;\r
7292                 this.isOpened = function(){                \r
7293                     if($scope.isOpen)\r
7294                     {\r
7295                         return  true;\r
7296                     }else\r
7297                     {\r
7298                         return false;\r
7299                     }\r
7300                 };                \r
7301                 this.setScope = function (scope) {\r
7302                     bodyScope = scope; \r
7303                     bodyScope.isOpen = $scope.isOpen;                   \r
7304                 };                \r
7305                 this.setExpanderScope = function (scope) {\r
7306                     expanderScope = scope;                                   \r
7307                 };\r
7308                 this.toggle = function () {\r
7309                     $scope.isOpen = bodyScope.isOpen = !bodyScope.isOpen;                    \r
7310                     return bodyScope.isOpen;\r
7311                     \r
7312                 };\r
7313                 this.watchToggle = function(io){ \r
7314                     bodyScope.isOpen = io;\r
7315                     expanderScope.updateIcons(io);\r
7316                 };  \r
7317             }],\r
7318         link: function (scope, elem, attr, myCtrl)\r
7319         {\r
7320             //scope.isOpen = false; \r
7321             if(myCtrl[1]){\r
7322                 myCtrl[1].addGroup(scope);\r
7323             }\r
7324             scope.$watch('isOpen', function(val){                               \r
7325                 myCtrl[0].watchToggle(scope.isOpen);\r
7326                 if(val && myCtrl[1]){\r
7327                     myCtrl[1].closeOthers(scope);\r
7328                 }\r
7329             });            \r
7330         }\r
7331     };\r
7332 })\r
7333 \r
7334 .directive('b2bExpanderHeading', function () {\r
7335     return{\r
7336         require: "^b2bExpanders",\r
7337         restrict: 'EA',\r
7338         replace: true,\r
7339         transclude: true,\r
7340         scope: true,\r
7341         template: "<div style='padding:10px 10px 10px 0 !important' ng-transclude></div>"\r
7342     };\r
7343 })\r
7344 \r
7345 .directive('b2bExpanderBody', function () {\r
7346     return{\r
7347         restrict: 'EA',\r
7348         require: "^b2bExpanders",\r
7349         replace: true,\r
7350         transclude: true,\r
7351         scope: {},\r
7352         template: "<div b2b-collapse='!isOpen' ><div ng-transclude></div></div>",\r
7353         link: function (scope, elem, attr, myCtrl) {\r
7354             scope.isOpen = false;\r
7355             myCtrl.setScope(scope);\r
7356         }\r
7357     };\r
7358 })\r
7359 \r
7360 .directive('b2bExpanderToggle', function () {\r
7361     return{\r
7362         restrict: 'EA',\r
7363         require: "^b2bExpanders",\r
7364         scope: {\r
7365             expandIcon: '@',\r
7366             collapseIcon: '@'\r
7367         },\r
7368         \r
7369         link: function (scope, element, attr, myCtrl)\r
7370         {\r
7371             myCtrl.setExpanderScope(scope);\r
7372             var isOpen = myCtrl.isOpened();   \r
7373 \r
7374             scope.setIcon = function () {\r
7375                 element.attr("role", "tab");\r
7376 \r
7377                 if (scope.expandIcon && scope.collapseIcon)\r
7378                 {\r
7379                     if (isOpen) {\r
7380                         element.removeClass(scope.expandIcon);\r
7381                         element.addClass(scope.collapseIcon);\r
7382 \r
7383                         element.attr("aria-expanded", "true");\r
7384                     }\r
7385                     else {\r
7386                         element.removeClass(scope.collapseIcon);\r
7387                         element.addClass(scope.expandIcon);\r
7388 \r
7389                         element.attr("aria-expanded", "false");\r
7390                     }\r
7391                 }                               \r
7392             };\r
7393             \r
7394             element.bind('click', function (){\r
7395                 scope.toggleit();\r
7396             });\r
7397             scope.updateIcons = function(nStat){\r
7398                 isOpen = nStat;\r
7399                 scope.setIcon();                \r
7400             };\r
7401             scope.toggleit = function (){\r
7402                 isOpen = myCtrl.toggle();\r
7403                 scope.setIcon();\r
7404                 scope.$apply();\r
7405             };                    \r
7406             scope.setIcon();\r
7407         }\r
7408     };\r
7409 });\r
7410 /**\r
7411  * @ngdoc directive\r
7412  * @name Messages, modals & alerts.att:notesMessagesAndErrors\r
7413  *\r
7414  * @description\r
7415  *  <file src="src/notesMessagesAndErrors/docs/readme.md" />\r
7416  *\r
7417  * @usage\r
7418  *  See Demo\r
7419  *\r
7420  * @example\r
7421  *  <section id="code">\r
7422         <example module="b2b.att">\r
7423             <file src="src/notesMessagesAndErrors/docs/demo.html" />\r
7424             <file src="src/notesMessagesAndErrors/docs/demo.js" />\r
7425        </example>\r
7426         </section>\r
7427  *\r
7428  */\r
7429 angular.module('b2b.att.notesMessagesAndErrors', []);\r
7430 /** \r
7431  * @ngdoc directive \r
7432  * @name Template.att:Notification Card\r
7433  * \r
7434  * @description \r
7435  *  <file src="src/notificationCardTemplate/docs/readme.md" /> \r
7436  * \r
7437  * @example \r
7438  *  <section id="code"> \r
7439         <b>HTML + AngularJS</b> \r
7440         <example module="b2b.att"> \r
7441             <file src="src/notificationCardTemplate/docs/demo.html" /> \r
7442             <file src="src/notificationCardTemplate/docs/demo.js" /> \r
7443        </example> \r
7444     </section>    \r
7445  * \r
7446  */\r
7447 angular.module('b2b.att.notificationCardTemplate', [])\r
7448   \r
7449 /** \r
7450  * @ngdoc directive \r
7451  * @name Template.att:Order Confirmation Template\r
7452  * \r
7453  * @description \r
7454  *  <file src="src/orderConfirmationTemplate/docs/readme.md" /> \r
7455  * \r
7456  * @example \r
7457  *  <section id="code"> \r
7458         <b>HTML + AngularJS</b> \r
7459         <example module="b2b.att"> \r
7460             <file src="src/orderConfirmationTemplate/docs/demo.html" /> \r
7461             <file src="src/orderConfirmationTemplate/docs/demo.js" /> \r
7462        </example> \r
7463     </section>    \r
7464  * \r
7465  */\r
7466 angular.module('b2b.att.orderConfirmationTemplate', []);\r
7467   \r
7468 /**\r
7469  * @ngdoc directive\r
7470  * @name Navigation.att:pagination\r
7471  *\r
7472  * @description\r
7473  *  <file src="src/pagination/docs/readme.md" />\r
7474  *\r
7475  * @usage\r
7476  *   <div b2b-pagination="" input-id="goto-page-2" total-pages="totalPages1" current-page="currentPage1" click-handler="customHandler" show-input="showInput"></div> \r
7477  *\r
7478  * @example\r
7479  *  <section id="code">\r
7480         <example module="b2b.att">\r
7481             <file src="src/pagination/docs/demo.html" />\r
7482             <file src="src/pagination/docs/demo.js" />\r
7483        </example>\r
7484         </section>\r
7485  *\r
7486  */\r
7487 angular.module('b2b.att.pagination', ['b2b.att.utilities', 'ngTouch'])\r
7488     .directive('b2bPagination', ['b2bUserAgent', 'keymap', '$window', '$timeout', function (b2bUserAgent, keymap, $window, $timeout) {\r
7489         return {\r
7490             restrict: 'A',\r
7491             scope: {\r
7492                 totalPages: '=',\r
7493                 currentPage: '=',\r
7494                 showInput: '=',\r
7495                 clickHandler: '=?',\r
7496                 inputId: '='\r
7497             },\r
7498             replace: true,\r
7499             templateUrl: 'b2bTemplate/pagination/b2b-pagination.html',\r
7500             link: function (scope, elem) {\r
7501                 scope.isMobile = b2bUserAgent.isMobile();\r
7502                 scope.notMobile = b2bUserAgent.notMobile();\r
7503                 scope.focusedPage;\r
7504                 scope.meanVal = 3;\r
7505                 scope.$watch('totalPages', function (value) {\r
7506                     if (angular.isDefined(value) && value !== null) {\r
7507                         scope.pages = [];\r
7508                         if (value < 1) {\r
7509                             scope.totalPages = 1;\r
7510                             return;\r
7511                         }\r
7512                         if (value <= 10) {\r
7513                             for (var i = 1; i <= value; i++) {\r
7514                                 scope.pages.push(i);\r
7515                             }\r
7516                         } else if (value > 10) {\r
7517                             var midVal = Math.ceil(value / 2);\r
7518                             scope.pages = [midVal - 2, midVal - 1, midVal, midVal + 1, midVal + 2];\r
7519                         }\r
7520                         if(scope.currentPage === undefined || scope.currentPage === 1)\r
7521                         {\r
7522                             currentPageChanged(1);\r
7523                         }\r
7524                     }\r
7525                 });\r
7526                 scope.$watch('currentPage', function (value) {\r
7527                     currentPageChanged(value);\r
7528                     callbackHandler(value);\r
7529                 });\r
7530                 var callbackHandler = function (num) {\r
7531                     if (angular.isFunction(scope.clickHandler)) {\r
7532                         scope.clickHandler(num);\r
7533                     }\r
7534                 };\r
7535 \r
7536                 function currentPageChanged(value) {\r
7537                     if (angular.isDefined(value) && value !== null) {\r
7538                         if (!value || value < 1) {\r
7539                             value = 1;\r
7540                         }\r
7541                         if (value > scope.totalPages) {\r
7542                             value = scope.totalPages;\r
7543                         }\r
7544                         if (scope.currentPage !== value) {\r
7545                             scope.currentPage = value;\r
7546                             callbackHandler(scope.currentPage);\r
7547                         }\r
7548                         if (scope.totalPages > 10) {\r
7549                             var val = parseInt(value);\r
7550                             if (val <= 6) {\r
7551                                 scope.pages = [1, 2, 3, 4, 5, 6, 7, 8];\r
7552                             } else if (val > 6 && val <= scope.totalPages - 5) {\r
7553                                 scope.pages = [val - 1, val, val + 1];\r
7554                             } else if (val >= scope.totalPages - 5) {\r
7555                                 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
7556                             }\r
7557                         }\r
7558                         if (scope.isMobile) {\r
7559                             var inWidth = $window.innerWidth;\r
7560                             var viewLimit = 7;\r
7561                             if (inWidth <= 400) {\r
7562                                 viewLimit = 7;\r
7563                             } else if (inWidth > 400 && inWidth < 500) {\r
7564                                 viewLimit = 9;\r
7565                             } else if (inWidth >= 500 && inWidth < 600) {\r
7566                                 viewLimit = 11;\r
7567                             } else if (inWidth >= 600 && inWidth < 700) {\r
7568                                 viewLimit = 13;\r
7569                             } else if (inWidth >= 700 && inWidth < 800) {\r
7570                                 viewLimit = 15;\r
7571                             }\r
7572 \r
7573                             var val = parseInt(value);\r
7574 \r
7575                             scope.meanVal = Math.floor(viewLimit / 2);\r
7576                             var lowerLimit = (val - scope.meanVal) < 1 ? 1 : val - scope.meanVal;\r
7577                             var upperLimit = (lowerLimit + viewLimit - 1) > scope.totalPages ? scope.totalPages : lowerLimit + viewLimit - 1;\r
7578                             scope.pages = [];\r
7579                             for (var i = lowerLimit; i <= upperLimit; i++) {\r
7580                                 scope.pages.push(i);\r
7581                             }\r
7582                         }\r
7583                     }\r
7584                 }\r
7585                 scope.gotoKeyClick = function (keyEvent) {\r
7586                   if (keyEvent.which === keymap.KEY.ENTER) {\r
7587                     scope.gotoBtnClick()\r
7588                   }\r
7589                 }\r
7590                 scope.gotoBtnClick = function () {\r
7591                     currentPageChanged(parseInt(scope.gotoPage)); \r
7592                     callbackHandler(scope.currentPage);\r
7593                     var qResult = elem[0].querySelector('button');\r
7594                     angular.element(qResult).attr('disabled','true');\r
7595                     $timeout(function(){\r
7596                         elem[0].querySelector('.b2b-pager__item--active').focus();\r
7597                     }, 50); \r
7598                     scope.gotoPage = null;               \r
7599                 }\r
7600                 scope.onfocusIn = function(evt)\r
7601                 {\r
7602                     var qResult = elem[0].querySelector('button');\r
7603                     angular.element(qResult).removeAttr('disabled');\r
7604                 }\r
7605                 scope.onfocusOut = function(evt)\r
7606                 {\r
7607                     if(evt.target.value === "")\r
7608                     {\r
7609                         var qResult = elem[0].querySelector('button');\r
7610                         angular.element(qResult).attr('disabled','true');\r
7611                     }                    \r
7612                 }\r
7613                 scope.next = function (event) {\r
7614                     if (event != undefined) {\r
7615                         event.preventDefault();\r
7616                     }\r
7617                     if (scope.currentPage < scope.totalPages) {\r
7618                         scope.currentPage += 1;\r
7619                         callbackHandler(scope.currentPage);\r
7620                     }\r
7621                 };\r
7622                 scope.prev = function (event) {\r
7623                     if (event != undefined) {\r
7624                         event.preventDefault();\r
7625                     }\r
7626                     if (scope.currentPage > 1) {\r
7627                         scope.currentPage -= 1;\r
7628                         callbackHandler(scope.currentPage);\r
7629                     }\r
7630                 };\r
7631                 scope.selectPage = function (value, event) {\r
7632                     event.preventDefault();\r
7633                     scope.currentPage = value;\r
7634                     scope.focusedPage = value;\r
7635                     callbackHandler(scope.currentPage);\r
7636                 };\r
7637                 scope.checkSelectedPage = function (value) {\r
7638                     if (scope.currentPage === value) {\r
7639                         return true;\r
7640                     }\r
7641                     return false;\r
7642                 };\r
7643                 scope.isFocused = function (page) {\r
7644                     return scope.focusedPage === page;\r
7645                 };\r
7646             }\r
7647         };\r
7648     }]);\r
7649 /**\r
7650  * @ngdoc directive\r
7651  * @name Navigation.att:paneSelector\r
7652  *\r
7653  * @description\r
7654  *  <file src="src/paneSelector/docs/readme.md" />\r
7655  *\r
7656  * @usage\r
7657  *  Please refer demo.html tab in Example section below.\r
7658  *\r
7659  * @example\r
7660     <section id="code">\r
7661         <b>HTML + AngularJS</b>\r
7662         <example module="b2b.att">\r
7663             <file src="src/paneSelector/docs/demo.html" />\r
7664             <file src="src/paneSelector/docs/demo.js" />\r
7665         </example>\r
7666     </section>\r
7667  */\r
7668 \r
7669 angular.module('b2b.att.paneSelector', ['b2b.att.tabs', 'b2b.att.utilities'])\r
7670 \r
7671 .filter('paneSelectorSelectedItemsFilter', [function () {\r
7672     return function (listOfItemsArray) {\r
7673 \r
7674         if (!listOfItemsArray) {\r
7675             listOfItemsArray = [];\r
7676         }\r
7677 \r
7678         var returnArray = [];\r
7679 \r
7680         for (var i = 0; i < listOfItemsArray.length; i++) {\r
7681             if (listOfItemsArray[i].isSelected) {\r
7682                 returnArray.push(listOfItemsArray[i]);\r
7683             }\r
7684         }\r
7685 \r
7686         return returnArray;\r
7687     };\r
7688 }])\r
7689 \r
7690 .filter('paneSelectorFetchChildItemsFilter', [function () {\r
7691     return function (listOfItemsArray) {\r
7692 \r
7693         if (!listOfItemsArray) {\r
7694             listOfItemsArray = [];\r
7695         }\r
7696 \r
7697         var returnArray = [];\r
7698 \r
7699         for (var i = 0; i < listOfItemsArray.length; i++) {\r
7700             for (var j = 0; j < listOfItemsArray[i].childItems.length; j++) {\r
7701                 returnArray.push(listOfItemsArray[i].childItems[j]);\r
7702             }\r
7703         }\r
7704 \r
7705         return returnArray;\r
7706     };\r
7707 }])\r
7708 \r
7709 .directive('b2bPaneSelector', [function () {\r
7710     return {\r
7711         restrict: 'AE',\r
7712         replace: true,\r
7713         templateUrl: 'b2bTemplate/paneSelector/paneSelector.html',\r
7714         transclude: true,\r
7715         scope: {}\r
7716     };\r
7717 }])\r
7718 \r
7719 .directive('b2bPaneSelectorPane', [ function () {\r
7720     return {\r
7721         restrict: 'AE',\r
7722         replace: true,\r
7723         templateUrl: 'b2bTemplate/paneSelector/paneSelectorPane.html',\r
7724         transclude: true,\r
7725         scope: {}\r
7726     };\r
7727 }])\r
7728 \r
7729 .directive('b2bTabVertical', ['$timeout', 'keymap', function ($timeout, keymap) {\r
7730     return {\r
7731         restrict: 'A',\r
7732         require: '^b2bTab',\r
7733         link: function (scope, element, attr, b2bTabCtrl) {\r
7734 \r
7735             if (!b2bTabCtrl) {\r
7736                 return;\r
7737             }\r
7738 \r
7739             // retreive the isolateScope\r
7740             var iScope = angular.element(element).isolateScope();\r
7741 \r
7742             $timeout(function () {\r
7743                 angular.element(element[0].querySelector('a')).unbind('keydown');\r
7744                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {\r
7745 \r
7746                     if (!(evt.keyCode)) {\r
7747                         evt.keyCode = evt.which;\r
7748                     }\r
7749 \r
7750                     switch (evt.keyCode) {\r
7751                         case keymap.KEY.DOWN:\r
7752                             evt.preventDefault();\r
7753                             iScope.nextKey();\r
7754                             break;\r
7755 \r
7756                         case keymap.KEY.UP:\r
7757                             evt.preventDefault();\r
7758                             iScope.previousKey();\r
7759                             break;\r
7760 \r
7761                         default:;\r
7762                     }\r
7763                 });\r
7764             });\r
7765         }\r
7766     };\r
7767 }]);\r
7768 /**\r
7769  * @ngdoc directive\r
7770  * @name Forms.att:phoneNumberInput\r
7771  *\r
7772  * @description\r
7773  *  <file src="src/phoneNumberInput/docs/readme.md" />\r
7774  *\r
7775  * @usage\r
7776 <form name="userForm1">\r
7777     <div class="form-row" ng-class="{'error':!userForm1.text.$valid && userForm1.text.$dirty}">\r
7778         <label>Phone Mask<span style="color:red">*</span>: (npa) nxx-line &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Model Value: {{mask.text}}</label>\r
7779         <div>\r
7780             <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
7781             <div ng-messages="userForm1.text.$error" class="error-msg" aria-live="polite" aria-atomic="true">\r
7782                 <span ng-message="required" role="alert">This field is mandatory!</span>\r
7783                 <span ng-message="invalidPhoneNumber" role="alert">Please enter valid phone number!</span>\r
7784                 <span ng-message="mask" role="alert">Please enter valid phone number!</span>\r
7785             </div>\r
7786         </div>\r
7787     </div>\r
7788 </form>\r
7789  *\r
7790  * @example\r
7791  *  <section id="code">\r
7792         <example module="b2b.att">\r
7793             <file src="src/phoneNumberInput/docs/demo.html" />\r
7794             <file src="src/phoneNumberInput/docs/demo.js" />\r
7795        </example>\r
7796     </section>\r
7797  *\r
7798  */\r
7799 angular.module('b2b.att.phoneNumberInput', ['ngMessages', 'b2b.att.utilities'])\r
7800     .constant("CoreFormsUiConfig", {\r
7801         phoneMask: '(___) ___-____',\r
7802         phoneMaskDot: '___.___.____',\r
7803         phoneMaskHyphen: '___-___-____'\r
7804     })\r
7805     .directive('b2bPhoneMask', ['$parse', 'CoreFormsUiConfig', 'keymap', function ($parse, CoreFormsUiConfig, keymap) {\r
7806         return {\r
7807             require: 'ngModel',\r
7808             scope: {\r
7809                 ngModel: '='\r
7810             },\r
7811             link: function (scope, iElement, iAttrs, ctrl) {\r
7812                 var navigatorAgent = navigator.userAgent.toLowerCase(),\r
7813                     isAndroid = navigatorAgent.indexOf("android") > -1,\r
7814                     oldIE = navigatorAgent.indexOf('msie 8.0') !== -1;\r
7815                 var mask = '';\r
7816                 var validPhoneNumber = false;\r
7817                 var currentKey = '';\r
7818                 if (isAndroid) {\r
7819                     mask = "__________";\r
7820                 } else {\r
7821                     switch (iAttrs.b2bPhoneMask) {\r
7822                     case "phoneMask":\r
7823                         mask = CoreFormsUiConfig.phoneMask;\r
7824                         break;\r
7825                     case "phoneMaskDot":\r
7826                         mask = CoreFormsUiConfig.phoneMaskDot;\r
7827                         break;\r
7828                     case "phoneMaskHyphen":\r
7829                         mask = CoreFormsUiConfig.phoneMaskHyphen;\r
7830                         break;\r
7831                     default:\r
7832                         mask = CoreFormsUiConfig.phoneMask;\r
7833                     }\r
7834                 }\r
7835                 iElement.attr("maxlength", mask.length);\r
7836                 var checkValidity = function (unmaskedValue, rawValue) {\r
7837                     var valid = false;\r
7838                     if (angular.isUndefined(rawValue) || rawValue === '') {\r
7839                         valid = true;\r
7840                     } else if (unmaskedValue) {\r
7841                         valid = (unmaskedValue.length === 10);\r
7842                     }\r
7843                     ctrl.$setValidity('invalidPhoneNumber', validPhoneNumber);\r
7844                     ctrl.$setValidity('mask', valid);\r
7845                     return valid;\r
7846                 };\r
7847                 var handleKeyup = function (evt) {\r
7848 \r
7849                     if (evt && evt.keyCode === keymap.KEY.SHIFT) {\r
7850                         return;\r
7851                     }\r
7852 \r
7853                     var index, formattedNumber;\r
7854                     if (ctrl.$modelValue) {\r
7855                         formattedNumber = ctrl.$modelValue;\r
7856                     } else {\r
7857                         formattedNumber = iElement.val();\r
7858                     }\r
7859                     if (!formattedNumber.length && currentKey === '') {\r
7860                         return;\r
7861                     }\r
7862                     var maskLength, inputNumbers, maskArray, tempArray, maskArrayLength;\r
7863                     tempArray = [];\r
7864                     maskArray = mask.split("");\r
7865                     maskArrayLength = maskArray.length;\r
7866                     maskLength = formattedNumber.substring(0, mask.length);\r
7867                     inputNumbers = formattedNumber.replace(/[^0-9]/g, "").split("");\r
7868                     for (index = 0; index < maskArrayLength; index++) {\r
7869                         tempArray.push(maskArray[index] === "_" ? inputNumbers.shift() : maskArray[index]);\r
7870                         if (inputNumbers.length === 0) {\r
7871                             break;\r
7872                         }\r
7873                     }\r
7874                     formattedNumber = tempArray.join("");\r
7875                     if (formattedNumber === '(') {\r
7876                         formattedNumber = '';\r
7877                     }\r
7878 \r
7879                     if ( (angular.isDefined(evt) && evt.which) && currentKey !== '') {\r
7880                         if (maskArray[0] === currentKey && formattedNumber === '') {\r
7881                             formattedNumber = '(';\r
7882                         } else if (evt.which === keymap.KEY.SPACE && currentKey === ' ') {\r
7883                             formattedNumber = formattedNumber + ') ';\r
7884                         } else if (maskArray[0] === currentKey && formattedNumber === '') {\r
7885                             formattedNumber = formattedNumber + currentKey;\r
7886                         } else if (maskArray[formattedNumber.length] === currentKey) {\r
7887                             formattedNumber = formattedNumber + currentKey;\r
7888                         }\r
7889                         currentKey = '';\r
7890                     }\r
7891 \r
7892                     ctrl.$setViewValue(formattedNumber);\r
7893                     ctrl.$render();\r
7894                     return formattedNumber;\r
7895                 };\r
7896 \r
7897 \r
7898                 // since we are only allowing 0-9, why even let the keypress go forward?\r
7899                 // also added in delete... in case they want to delete :)\r
7900                 var handlePress = function (e) {\r
7901                     if (e.which) {\r
7902                         if ((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105)) {\r
7903                             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
7904                                 // Allow: Ctrl+V/v\r
7905                                 (!(e.ctrlKey) && (e.which !== '118' || e.which !== '86')) &&\r
7906                                 // Allow: Ctrl+C/c\r
7907                                 (!(e.ctrlKey) && (e.which !== '99' || e.which !== '67')) &&\r
7908                                 // Allow: Ctrl+X/x\r
7909                                 (!(e.ctrlKey) && (e.which !== '120' || e.which !== '88'))) {\r
7910                                 e.preventDefault ? e.preventDefault() : e.returnValue = false;\r
7911                                 iElement.attr("aria-label", "Only numbers are allowed");\r
7912                                 validPhoneNumber = false;\r
7913                             }\r
7914                         } else {\r
7915                             iElement.removeAttr("aria-label");\r
7916                             validPhoneNumber = true;\r
7917                         }\r
7918 \r
7919                         setCurrentKey(e);\r
7920                     }\r
7921                     scope.$apply();\r
7922                 };\r
7923                 // i moved this out because i thought i might need focus as well..\r
7924                 // to handle setting the model as the view changes\r
7925                 var parser = function (fromViewValue) {\r
7926                     var letters = /^[A-Za-z]+$/;\r
7927                     var numbers = /^[0-9]+$/;\r
7928                     if (angular.isUndefined(fromViewValue) || fromViewValue === '') {\r
7929                         validPhoneNumber = true;\r
7930                     } else {\r
7931                         if (fromViewValue.match(letters)) {\r
7932                             validPhoneNumber = false;\r
7933                         }\r
7934                         if (fromViewValue.match(numbers)) {\r
7935                             validPhoneNumber = true;\r
7936                         }\r
7937                     }\r
7938                     var clean = "";\r
7939                     if (fromViewValue && fromViewValue.length > 0) {\r
7940                         clean = fromViewValue.replace(/[^0-9]/g, '');\r
7941                     }\r
7942                     checkValidity(clean, fromViewValue);\r
7943                     return clean;\r
7944                 };\r
7945 \r
7946                 //to handle reading the model and formatting it\r
7947                 var formatter = function (fromModelView) {\r
7948                     var input = '';\r
7949                     checkValidity(fromModelView);\r
7950                     if (fromModelView) {\r
7951                         input = handleKeyup();\r
7952                     }\r
7953                     return input;\r
7954                 };\r
7955 \r
7956                 var setCurrentKey = function (e) {\r
7957                     switch (e.which) {\r
7958                     case 189:\r
7959                     case 109:\r
7960                         currentKey = '-';\r
7961                         break;\r
7962                     case 190:\r
7963                     case 110:\r
7964                         currentKey = '.';\r
7965                         break;\r
7966                     case 57:\r
7967                         if (e.shiftKey === true) {\r
7968                             currentKey = '(';\r
7969                         }\r
7970                         break;\r
7971                     case 48:\r
7972                         if (e.shiftKey === true) {\r
7973                             currentKey = ')';\r
7974                         }\r
7975                         break;\r
7976                     case 32:\r
7977                         currentKey = ' ';\r
7978                         break;\r
7979                     }\r
7980                 };\r
7981 \r
7982                 if (angular.isDefined(scope.ngModel)) {\r
7983                     parser(scope.ngModel);\r
7984                 }\r
7985 \r
7986                 ctrl.$parsers.push(parser);\r
7987                 ctrl.$formatters.push(formatter);\r
7988                 iElement.bind('keyup', handleKeyup);\r
7989                 iElement.bind('keydown', handlePress);\r
7990             }\r
7991         };\r
7992 }]);\r
7993 /** \r
7994  * @ngdoc directive \r
7995  * @name Template.att:Profile Blocks \r
7996  * \r
7997  * @description \r
7998  *  <file src="src/profileBlockTemplate/docs/readme.md" /> \r
7999  * @example \r
8000  *  <section id="code">  \r
8001         <example module="b2b.att"> \r
8002             <file src="src/profileBlockTemplate/docs/demo.html" /> \r
8003             <file src="src/profileBlockTemplate/docs/demo.js" /> \r
8004        </example>  \r
8005     </section>  \r
8006  *  \r
8007  */   \r
8008 \r
8009 angular.module('b2b.att.profileBlockTemplate', [])\r
8010     \r
8011      \r
8012   \r
8013 /**\r
8014  * @ngdoc directive\r
8015  * @name Layouts.att:profileCard\r
8016  *\r
8017  * @description\r
8018  *  <file src="src/profileCard/docs/readme.md" />\r
8019  *\r
8020  * @usage\r
8021  *  <b2b-profile-card></b2b-profile-card>\r
8022  *\r
8023  * @example\r
8024     <section id="code">   \r
8025         <example module="b2b.att">\r
8026             <file src="src/profileCard/docs/demo.html" />\r
8027             <file src="src/profileCard/docs/demo.js" />\r
8028         </example>\r
8029     </section>\r
8030  */\r
8031 \r
8032 angular.module('b2b.att.profileCard', ['b2b.att'])\r
8033 .constant('profileStatus',{\r
8034     status: {\r
8035         ACTIVE: {\r
8036             status: "Active",\r
8037             color: "green"\r
8038         },\r
8039         DEACTIVATED: {\r
8040             status: "Deactivated",\r
8041             color: "red"\r
8042         },\r
8043         LOCKED: {\r
8044             status: "Locked",\r
8045             color: "red"\r
8046         },\r
8047         IDLE: {\r
8048             status: "Idle",\r
8049             color: "yellow"\r
8050         },\r
8051         PENDING: {\r
8052             status: "Pending",\r
8053             color: "blue"\r
8054         }\r
8055     },\r
8056     role: "COMPANY ADMINISTRATOR"\r
8057 \r
8058 })\r
8059 .directive('b2bProfileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {\r
8060    return {\r
8061         restrict: 'EA',\r
8062         replace: 'true',\r
8063         templateUrl: function(element, attrs){\r
8064             if(!attrs.addUser){\r
8065                 return 'b2bTemplate/profileCard/profileCard.html';\r
8066             }\r
8067             else{\r
8068                 return 'b2bTemplate/profileCard/profileCard-addUser.html';\r
8069             }\r
8070         },\r
8071         scope: {\r
8072             profile:'=',\r
8073             characterLimit: '@'\r
8074         },\r
8075         link: function(scope, elem, attr){\r
8076             scope.characterLimit = parseInt(attr.characterLimit, 10) || 25;\r
8077             scope.shouldClip = function(str) {\r
8078                 return str.length > scope.characterLimit;\r
8079             };\r
8080 \r
8081             scope.showEmailTooltip = false;\r
8082 \r
8083             scope.image=true;\r
8084             function isImage(src) {\r
8085                 var deferred = $q.defer();\r
8086                 var image = new Image();\r
8087                 image.onerror = function() {\r
8088                     deferred.reject(false);\r
8089                 };\r
8090                 image.onload = function() {\r
8091                     deferred.resolve(true);\r
8092                 };\r
8093                 if(src !== undefined && src.length>0 ){\r
8094                     image.src = src;\r
8095                 } else {\r
8096                      deferred.reject(false);\r
8097                 }\r
8098                 return deferred.promise;\r
8099             }\r
8100             if(!attr.addUser){\r
8101             scope.image=false;\r
8102             isImage(scope.profile.img).then(function(img) {\r
8103                 scope.image=img;\r
8104             });\r
8105             var splitName=(scope.profile.name).split(' ');\r
8106             scope.initials='';\r
8107             for(var i=0;i<splitName.length;i++){\r
8108                 scope.initials += splitName[i][0];\r
8109             }\r
8110             if(scope.profile.role.toUpperCase() === profileStatus.role){\r
8111                 scope.badge=true;\r
8112             }\r
8113             var profileState=profileStatus.status[scope.profile.state.toUpperCase()];\r
8114             if(profileState) {\r
8115                 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;\r
8116                 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;\r
8117                 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){\r
8118                         scope.profile.lastLogin=scope.profile.state;\r
8119                 }\r
8120             }\r
8121             var today=new Date().getTime();\r
8122             var lastlogin=new Date(scope.profile.lastLogin).getTime();\r
8123             var diff=(today-lastlogin)/(1000*60*60*24);\r
8124             if(diff<=1){\r
8125                 scope.profile.lastLogin="Today";\r
8126             }\r
8127             else if(diff<=2){\r
8128                 scope.profile.lastLogin="Yesterday";\r
8129             }\r
8130         }\r
8131     }\r
8132 };\r
8133 }]);\r
8134 /**\r
8135  * @ngdoc directive\r
8136  * @name Forms.att:radios\r
8137  *\r
8138  * @description\r
8139  *  <file src="src/radios/docs/readme.md" />\r
8140  *\r
8141  * @usage\r
8142  *  See demo section\r
8143  *\r
8144  * @param {boolean} refreshRadioGroup - A trigger that recalculates and updates the accessibility roles on radios in a group.\r
8145  * \r
8146  * @example\r
8147     <section id="code">\r
8148                <b>HTML + AngularJS</b>\r
8149                <example module="b2b.att">\r
8150                 <file src="src/radios/docs/demo.html" />\r
8151                 <file src="src/radios/docs/demo.js" />\r
8152                </example>\r
8153             </section>\r
8154  */\r
8155 angular.module('b2b.att.radios', ['b2b.att.utilities'])\r
8156 .directive('b2bRadioGroupAccessibility', ['$timeout', 'b2bUserAgent', function($timeout, b2bUserAgent) {\r
8157     return {\r
8158         restrict: "A",\r
8159         scope: {\r
8160             refreshRadioGroup: "=",\r
8161         },\r
8162         link: function(scope, ele, attr) {\r
8163 \r
8164             var roleRadioElement, radioProductSelectElement, radioInputTypeElement;\r
8165 \r
8166             $timeout(calculateNumberOfRadio);\r
8167 \r
8168             scope.$watch('refreshRadioGroup', function(value) {\r
8169                 if (value === true) {\r
8170                     addingRoleAttribute();\r
8171                     $timeout(calculateNumberOfRadio);\r
8172                     scope.refreshRadioGroup = false;\r
8173                 } else {\r
8174                     return;\r
8175                 }\r
8176             })\r
8177 \r
8178 \r
8179             function calculateNumberOfRadio() {\r
8180                 roleRadioElement = ele[0].querySelectorAll('[role="radio"]');\r
8181 \r
8182                 radioProductSelectElement = ele[0].querySelectorAll('[role="radiogroup"] li.radio-box');\r
8183 \r
8184                 radioInputTypeElement = ele[0].querySelectorAll('input[type="radio"]');\r
8185 \r
8186                 for (var i = 0; i < radioInputTypeElement.length; i++) {\r
8187                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';\r
8188                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';\r
8189                     var numOfx = i + 1 + ' of ' + radioInputTypeElement.length;\r
8190                     angular.element(roleRadioElement[i]).attr({\r
8191                         'aria-checked': isChecked,\r
8192                         'aria-disabled': isDisabled,\r
8193                         'data-opNum': numOfx\r
8194                     });\r
8195                     if (b2bUserAgent.notMobile()) {\r
8196                         angular.element(roleRadioElement[i]).removeAttr("role");\r
8197                     }\r
8198 \r
8199                     if (radioProductSelectElement.length) {\r
8200                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');\r
8201                     }\r
8202 \r
8203                     if (/Android/i.test(navigator.userAgent)) {\r
8204                         angular.element(roleRadioElement[i]).append('<span class="hidden-spoken">. ' + numOfx + '.</span>');\r
8205                     }\r
8206 \r
8207 \r
8208                     angular.element(radioInputTypeElement[i]).bind('click', radioStateChangeonClick);\r
8209 \r
8210                 }\r
8211             }\r
8212 \r
8213             function addingRoleAttribute() {\r
8214                 for (var i = 0; i < radioInputTypeElement.length; i++) {\r
8215                     if (b2bUserAgent.notMobile()) {\r
8216                         angular.element(roleRadioElement[i]).attr("role", "radio");\r
8217                     }\r
8218                 }\r
8219             }\r
8220 \r
8221             function radioStateChangeonClick() {\r
8222                 for (var i = 0; i < radioInputTypeElement.length; i++) {\r
8223                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';\r
8224                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';\r
8225                     if (radioProductSelectElement.length) {\r
8226                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');\r
8227                     }\r
8228                     angular.element(roleRadioElement[i]).attr({\r
8229                         'aria-checked': isChecked,\r
8230                         'aria-disabled': isDisabled\r
8231                     });\r
8232                 }\r
8233 \r
8234             }\r
8235         }\r
8236     }\r
8237 \r
8238 }]);\r
8239 \r
8240 /**\r
8241  * @ngdoc directive\r
8242  * @name Forms.att:searchField\r
8243  *\r
8244  * @description\r
8245  *  <file src="src/searchField/docs/readme.md" />\r
8246  *\r
8247  * @usage\r
8248  *  <div b2b-search-field dropdown-list="listdata" on-click-callback="clickFn(value)" class="span12" input-model='typedString' config-obj='keyConfigObj'></div>\r
8249  *\r
8250  * @example\r
8251  <section id="code">\r
8252     <example module="b2b.att">\r
8253     <file src="src/searchField/docs/demo.html" />\r
8254     <file src="src/searchField/docs/demo.js" />\r
8255     </example>\r
8256 </section>\r
8257  */\r
8258 \r
8259 angular.module('b2b.att.searchField', ['b2b.att.utilities', 'b2b.att.position'])\r
8260     .filter('b2bFilterInput', [function() {\r
8261         return function(list, str, keyArray, displayListKey, isContainsSearch, searchSeperator) {\r
8262             var res = [];\r
8263             var searchLabel;\r
8264             var searchCondition;\r
8265             var conditionCheck = function(searchSeperator, listItem, displayListKey, splitString) {\r
8266                 var displayTitle = null;\r
8267                 if (splitString) {\r
8268                     for (var i = 0; i < displayListKey.length; i++) {\r
8269                         if (i <= 0) {\r
8270                             displayTitle = listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase()) > -1;\r
8271                         } else {\r
8272                             displayTitle = (splitString[i]) ? displayTitle && listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase().trim()) > -1 : displayTitle;\r
8273                         }\r
8274                     }\r
8275                 } else {\r
8276                     angular.forEach(displayListKey, function(value) {\r
8277                         if (!displayTitle) {\r
8278                             displayTitle = listItem[value];\r
8279                         } else {\r
8280                             displayTitle = displayTitle + (listItem[value] ? searchSeperator + ' ' + listItem[value] : '');\r
8281                         }\r
8282                     });\r
8283                 }\r
8284                 return displayTitle;\r
8285             }\r
8286             angular.forEach(list, function(listItem) {\r
8287                 var splitString = str.indexOf(searchSeperator) > -1 ? str.split(searchSeperator) : false;\r
8288                 var displayList = conditionCheck(searchSeperator, listItem, displayListKey, splitString)\r
8289                 for (var i = 0; i < keyArray.length; i++) {\r
8290                     searchLabel = keyArray[i];\r
8291                     if (listItem[searchLabel]) {\r
8292                         if (isContainsSearch) {\r
8293                             var displaySearchList = listItem[searchLabel].toLowerCase().indexOf(str.toLowerCase()) > -1;\r
8294                             if (splitString.length > 1) {\r
8295                                 displaySearchList = (splitString.length <= keyArray.length) ? displayList : false;\r
8296                             }\r
8297                             searchCondition = displaySearchList;\r
8298                         } else {\r
8299                             searchCondition = listItem[searchLabel].match(new RegExp('^' + str, 'gi'));\r
8300                         }\r
8301                         if (searchCondition) {\r
8302                             res.push({\r
8303                                 'title': conditionCheck(searchSeperator, listItem, displayListKey),\r
8304                                 'valueObj': listItem\r
8305                             });\r
8306                             break;\r
8307                         }\r
8308                     }\r
8309                 }\r
8310             });\r
8311             return res;\r
8312         };\r
8313     }]).directive('b2bSearchField', ['$filter', 'b2bFilterInputFilter', 'keymap', '$documentBind', '$isElement', '$document', 'events', '$timeout', function($filter, b2bFilterInput, keymap, $documentBind, $isElement, $document, events, $timeout) {\r
8314         return {\r
8315             restrict: 'A',\r
8316             scope: {\r
8317                 dataList: '=dropdownList',\r
8318                 onClickCallback: '&',\r
8319                 inputModel: '=',\r
8320                 configObj: '=',\r
8321                 objModel: '=',\r
8322                 inputDeny: '=?',\r
8323                 disabled: '=?'\r
8324             },\r
8325             replace: true,\r
8326             templateUrl: 'b2bTemplate/searchField/searchField.html',\r
8327             controller: ['$scope', function($scope) {\r
8328                 this.searchKeyArray = [];\r
8329                 if ($scope.configObj.searchKeys) {\r
8330                     this.searchKeyArray = $scope.configObj.searchKeys;\r
8331                 }\r
8332                 if (angular.isUndefined($scope.disabled)) {\r
8333                     $scope.disabled = false;\r
8334                 }\r
8335                 this.triggerInput = function(searchString) {\r
8336                     $scope.originalInputModel = searchString;\r
8337                     if (searchString === '') {\r
8338                         $scope.currentIndex = -1;\r
8339                         $scope.filterList = [];\r
8340                         $scope.showListFlag = false;\r
8341                     } else if (searchString !== '' && !$scope.isFilterEnabled) {\r
8342                         $scope.filterList = $filter('b2bFilterInput')($scope.dataList, searchString, this.searchKeyArray, $scope.configObj.displayListDataKey, $scope.configObj.isContainsSearch, $scope.configObj.searchSeperator);\r
8343                         $scope.showListFlag = true;\r
8344                     }\r
8345                 };\r
8346                 this.denyRegex = function() {\r
8347                     return $scope.inputDeny;\r
8348                 };\r
8349             }],\r
8350             link: function(scope, elem) {\r
8351                 scope.isFilterEnabled = false;\r
8352                 scope.showListFlag = false;\r
8353                 scope.currentIndex = -1;\r
8354                 scope.setCurrentIdx = function(idx) {\r
8355                     scope.currentIndex = idx;\r
8356                     if (idx > -1) {\r
8357                         scope.inputModel = scope.filterList[idx].title;\r
8358                         scope.objModel = scope.filterList[idx];\r
8359                     }\r
8360                 };\r
8361                 scope.isActive = function(index, dropdownLength) {\r
8362                     scope.dropdownLength = dropdownLength;\r
8363                     return scope.currentIndex === index;\r
8364                 };\r
8365                 scope.selectItem = function(idx) {\r
8366                     scope.setCurrentIdx(idx);\r
8367                     scope.onClickCallback({\r
8368                         value: scope.inputModel,\r
8369                         objValue: scope.objModel\r
8370                     });\r
8371                     scope.showListFlag = false;\r
8372                     $timeout(function() {\r
8373                         elem.find('div').find('input')[0].focus();\r
8374                     }, 150);\r
8375                 };\r
8376                 scope.startSearch = function() {\r
8377                     scope.onClickCallback({\r
8378                         value: scope.inputModel,\r
8379                         objValue: scope.objModel\r
8380                     });\r
8381                 };\r
8382                 scope.selectPrev = function() {\r
8383                     if (scope.currentIndex > 0 && scope.filterList.length > 0) {\r
8384                         scope.currentIndex = scope.currentIndex - 1;\r
8385                         scope.setCurrentIdx(scope.currentIndex);\r
8386                     } else if (scope.currentIndex === 0) {\r
8387                         scope.currentIndex = scope.currentIndex - 1;\r
8388                         scope.inputModel = scope.originalInputModel;\r
8389                         scope.isFilterEnabled = true;\r
8390                     }\r
8391                 };\r
8392                 scope.selectNext = function() {\r
8393                     if (scope.currentIndex < scope.configObj.noOfItemsDisplay - 1) {\r
8394                         if (scope.currentIndex < scope.filterList.length - 1) {\r
8395                             scope.currentIndex = scope.currentIndex + 1;\r
8396                             scope.setCurrentIdx(scope.currentIndex);\r
8397                         }\r
8398                     }\r
8399                 };\r
8400                 scope.selectCurrent = function() {\r
8401                     scope.selectItem(scope.currentIndex);\r
8402                 };\r
8403                 scope.selectionIndex = function(e) {\r
8404                     switch (e.keyCode) {\r
8405                         case keymap.KEY.DOWN:\r
8406                             events.preventDefault(e);\r
8407                             scope.isFilterEnabled = true;\r
8408                             scope.selectNext();\r
8409                             break;\r
8410                         case keymap.KEY.UP:\r
8411                             events.preventDefault(e);\r
8412                             scope.isFilterEnabled = true;\r
8413                             scope.selectPrev();\r
8414                             break;\r
8415                         case keymap.KEY.ENTER:\r
8416                             events.preventDefault(e);\r
8417                             scope.isFilterEnabled = true;\r
8418                             scope.selectCurrent();\r
8419                             break;\r
8420                         case keymap.KEY.ESC:\r
8421                             events.preventDefault(e);\r
8422                             scope.isFilterEnabled = false;\r
8423                             scope.showListFlag = false;\r
8424                             scope.inputModel = '';\r
8425                             break;\r
8426                         default:\r
8427                             scope.isFilterEnabled = false;\r
8428                             break;\r
8429                     }\r
8430                     if (elem[0].querySelector('.filtercontainer')) {\r
8431                         elem[0].querySelector('.filtercontainer').scrollTop = (scope.currentIndex - 1) * 35;\r
8432                     }\r
8433                 };\r
8434                 scope.$watch('filterList', function(newVal, oldVal) {\r
8435                     if (newVal !== oldVal) {\r
8436                         scope.currentIndex = -1;\r
8437                     }\r
8438                 });\r
8439                 scope.blurInput = function() {\r
8440                     $timeout(function() {\r
8441                         scope.showListFlag = false;\r
8442                     }, 150);\r
8443                 };\r
8444                 var outsideClick = function(e) {\r
8445                     var isElement = $isElement(angular.element(e.target), elem.find('ul').eq(0), $document);\r
8446                     if (!isElement && document.activeElement.tagName.toLowerCase() !== 'input') {\r
8447                         scope.showListFlag = false;\r
8448                         scope.$apply();\r
8449                     }\r
8450                 };\r
8451                 $documentBind.click('showListFlag', outsideClick, scope);\r
8452             }\r
8453         };\r
8454     }])\r
8455     .directive('b2bSearchInput', [function() {\r
8456         return {\r
8457             restrict: 'A',\r
8458             require: ['ngModel', '^b2bSearchField'],\r
8459             link: function(scope, elem, attr, ctrl) {\r
8460                 var ngModelCtrl = ctrl[0];\r
8461                 var attSearchBarCtrl = ctrl[1];\r
8462                 var REGEX = ctrl[1].denyRegex();\r
8463                 var parser = function(viewValue) {\r
8464                     attSearchBarCtrl.triggerInput(viewValue);\r
8465                     return viewValue;\r
8466                 };\r
8467                 ngModelCtrl.$parsers.push(parser);\r
8468 \r
8469                 if (REGEX !== undefined || REGEX !== '') {\r
8470                     elem.bind('input', function() {\r
8471                         var inputString = ngModelCtrl.$viewValue && ngModelCtrl.$viewValue.replace(REGEX, '');\r
8472                         if (inputString !== ngModelCtrl.$viewValue) {\r
8473                             ngModelCtrl.$setViewValue(inputString);\r
8474                             ngModelCtrl.$render();\r
8475                             scope.$apply();\r
8476                         }\r
8477                     });\r
8478                 }\r
8479             }\r
8480         };\r
8481     }]);\r
8482 \r
8483 /**\r
8484  * @ngdoc directive\r
8485  * @name Buttons, links & UI controls.att:Seek bar\r
8486  *\r
8487  * @description\r
8488  *  <file src="src/seekBar/docs/readme.md" />\r
8489  *\r
8490  * @usage\r
8491  *  Horizontal Seek Bar\r
8492  *  <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
8493 \r
8494  *  Vertical Seek Bar\r
8495  *  <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
8496  *\r
8497  * @example\r
8498     <section id="code">   \r
8499         <b>HTML + AngularJS</b>\r
8500         <example module="b2b.att">\r
8501             <file src="src/seekBar/docs/demo.html" />\r
8502             <file src="src/seekBar/docs/demo.js" />\r
8503         </example>\r
8504     </section>\r
8505  */\r
8506 \r
8507 angular.module('b2b.att.seekBar', ['b2b.att.utilities','b2b.att.position'])\r
8508         .constant('b2bSeekBarConfig', {\r
8509             'min': 0,\r
8510             'max': 100,\r
8511             'step': 1,\r
8512             'skipInterval': 1\r
8513         })\r
8514         .directive('b2bSeekBar', ['$documentBind', 'events', 'b2bSeekBarConfig', 'keymap', '$compile', function($documentBind, events, b2bSeekBarConfig, keymap, $compile) {\r
8515                 return {\r
8516                     restrict: 'AE',\r
8517                     replace: true,\r
8518                     require: 'ngModel',\r
8519                     templateUrl: 'b2bTemplate/seekBar/seekBar.html',\r
8520                     scope: {\r
8521                         onDragEnd: '&?',\r
8522                         onDragInit: '&?'\r
8523                     },\r
8524                     link: function(scope, elm, attr, ngModelCtrl) {\r
8525                         scope.isDragging = false;\r
8526                         scope.verticalSeekBar = false;\r
8527                         var min;\r
8528                         var max;\r
8529                         var step = b2bSeekBarConfig.step;\r
8530                         var skipInterval = b2bSeekBarConfig.skipInterval;\r
8531                         var knob = angular.element(elm[0].querySelector('.b2b-seek-bar-knob-container'));\r
8532                         var seekBarKnob = angular.element(knob[0].querySelector('.b2b-seek-bar-knob'));\r
8533                         var trackContainer = angular.element(elm[0].querySelector('.b2b-seek-bar-track-container'));\r
8534                         var trackFill = angular.element(elm[0].querySelector('.b2b-seek-bar-track-fill'));\r
8535                         var trackContainerRect = {};\r
8536                         var axisPosition;\r
8537                         var trackFillOrderPositioning;\r
8538 \r
8539                         if (angular.isDefined(attr.vertical)) {\r
8540                             scope.verticalSeekBar = true;\r
8541                             axisPosition = "clientY";\r
8542                         }\r
8543                         else {\r
8544                             scope.verticalSeekBar = false;\r
8545                             axisPosition = "clientX";\r
8546                         }\r
8547                         var getValidStep = function(val) {\r
8548                             val = parseFloat(val);\r
8549                             // in case $modelValue came in string number\r
8550                             if (angular.isNumber(val)) {\r
8551                                 val = Math.round((val - min) / step) * step + min;\r
8552                                 return Math.round(val * 1000) / 1000;\r
8553                             }\r
8554                         };\r
8555 \r
8556                         var getPositionToPercent = function(x) {\r
8557                             if (scope.verticalSeekBar) {\r
8558                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));\r
8559                             }\r
8560                             else {\r
8561                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));\r
8562                             }\r
8563                         };\r
8564 \r
8565                         var getPercentToValue = function(percent) {\r
8566                             return (min + percent * (max - min));\r
8567                         };\r
8568 \r
8569                         var getValueToPercent = function(val) {\r
8570                             return (val - min) / (max - min);\r
8571                         };\r
8572 \r
8573                         var getValidMinMax = function(val) {\r
8574                             return Math.max(min, Math.min(max, val));\r
8575                         };\r
8576 \r
8577                         var updateTrackContainerRect = function() {\r
8578                             trackContainerRect = trackContainer[0].getBoundingClientRect();\r
8579                             if (scope.verticalSeekBar) {\r
8580                                 if (!trackContainerRect.height) {\r
8581                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;\r
8582                                 } else {\r
8583                                     trackFillOrderPositioning = trackContainerRect.height;\r
8584                                 }\r
8585                             }\r
8586                             else {\r
8587                                 if (!trackContainerRect.width) {\r
8588                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;\r
8589                                 } else {\r
8590                                     trackFillOrderPositioning = trackContainerRect.width;\r
8591                                 }\r
8592 \r
8593                             }\r
8594 \r
8595                         };\r
8596 \r
8597                         var updateKnobPosition = function(percent) {\r
8598                             var percentStr = (percent * 100) + '%';\r
8599                             if (scope.verticalSeekBar) {\r
8600                                 knob.css('bottom', percentStr);\r
8601                                 trackFill.css('height', percentStr);\r
8602                             }\r
8603                             else {\r
8604                                 knob.css('left', percentStr);\r
8605                                 trackFill.css('width', percentStr);\r
8606                             }\r
8607                         };\r
8608 \r
8609                         var modelRenderer = function() {\r
8610                             if (isNaN(ngModelCtrl.$viewValue)) {\r
8611                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;\r
8612                             }\r
8613 \r
8614                             var viewVal = ngModelCtrl.$viewValue;\r
8615                             scope.currentModelValue = viewVal;\r
8616 \r
8617                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation\r
8618                             if ((min || min === 0) && max && step) {\r
8619                                 updateKnobPosition(getValueToPercent(viewVal));\r
8620                             }\r
8621                         };\r
8622 \r
8623                         var setModelValue = function(val) {\r
8624                             scope.currentModelValue = getValidMinMax(getValidStep(val));\r
8625                             ngModelCtrl.$setViewValue(scope.currentModelValue);\r
8626                         };\r
8627 \r
8628                         var updateMin = function(val) {\r
8629                             min = parseFloat(val);\r
8630                             if(isNaN(min)){\r
8631                                min = b2bSeekBarConfig.min; \r
8632                             }\r
8633                             modelRenderer();\r
8634                         };\r
8635 \r
8636                         var updateMax = function(val) {\r
8637                             max = parseFloat(val);\r
8638                             if(isNaN(max)){\r
8639                                max = b2bSeekBarConfig.max; \r
8640                             }\r
8641                             modelRenderer();\r
8642                         };\r
8643 \r
8644                         var updateStep = function(val) {\r
8645                             step = parseFloat(val);\r
8646                             if (!attr['skipInterval']) {\r
8647                                 skipInterval = step;\r
8648                             }\r
8649                         };\r
8650 \r
8651                         var updateSkipInterval = function(val) {\r
8652                             skipInterval = step * Math.ceil(val / (step!==0?step:1));\r
8653                         };\r
8654 \r
8655                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(b2bSeekBarConfig.min);\r
8656                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(b2bSeekBarConfig.max);\r
8657                         if (angular.isDefined(attr.step)) {\r
8658                             attr.$observe('step', updateStep);\r
8659                         }\r
8660                         if (angular.isDefined(attr.skipInterval)) {\r
8661                             attr.$observe('skipInterval', updateSkipInterval);\r
8662                         }\r
8663                         scope.currentModelValue = getValidMinMax(getValidStep(min));\r
8664                         var onMouseDown = function(e) {\r
8665                             switch (e.which) {\r
8666                                 case 1:\r
8667                                     // left mouse button\r
8668                                     break;\r
8669                                 case 2:\r
8670                                 case 3:\r
8671                                     // right or middle mouse button\r
8672                                     return;\r
8673                             }\r
8674                             ;\r
8675 \r
8676                             scope.isDragging = true;\r
8677                             seekBarKnob[0].focus();\r
8678                             updateTrackContainerRect();\r
8679                             if (attr['onDragInit']) {\r
8680                                 scope.onDragInit();\r
8681                             }\r
8682                             events.stopPropagation(e);\r
8683                             events.preventDefault(e);\r
8684                              scope.$apply(function() {\r
8685                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
8686                             });\r
8687                         };\r
8688 \r
8689                         var onMouseUp = function() {\r
8690 \r
8691                             if (attr['onDragEnd']) {\r
8692                                 scope.onDragEnd();\r
8693                             }\r
8694                             scope.isDragging = false;\r
8695                             scope.$digest();\r
8696                         };\r
8697 \r
8698                         var onMouseMove = function(e) {\r
8699                             if (scope.isDragging) {\r
8700                                 events.stopPropagation(e);\r
8701                                 events.preventDefault(e);\r
8702 \r
8703                                 scope.$apply(function() {\r
8704                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
8705                                 });\r
8706                             }\r
8707                         };\r
8708 \r
8709                         function onKeyDown(e) {\r
8710                             if (!(e.keyCode)) {\r
8711                                 e.keyCode = e.which;\r
8712                             }\r
8713                             var updateStep;\r
8714                             switch (e.keyCode) {\r
8715                                 case keymap.KEY.LEFT:\r
8716                                     if (!scope.verticalSeekBar) {\r
8717                                         updateStep = -skipInterval;\r
8718                                     }\r
8719                                     break;\r
8720                                 case keymap.KEY.RIGHT:\r
8721                                     if (!scope.verticalSeekBar) {\r
8722                                         updateStep = skipInterval;\r
8723                                     }\r
8724                                     break;\r
8725                                 case keymap.KEY.UP:\r
8726                                     if (scope.verticalSeekBar) {\r
8727                                         updateStep = skipInterval;\r
8728                                     }\r
8729                                     break;\r
8730                                 case keymap.KEY.DOWN:\r
8731                                     if (scope.verticalSeekBar) {\r
8732                                         updateStep = -skipInterval;\r
8733                                     }\r
8734                                     break;\r
8735                                 default:\r
8736                                     return;\r
8737                             }\r
8738 \r
8739                             if (updateStep) {\r
8740                                 events.stopPropagation(e);\r
8741                                 events.preventDefault(e);\r
8742                                 scope.$apply(function() {\r
8743                                     setModelValue(ngModelCtrl.$viewValue + updateStep);\r
8744                                 });\r
8745                                 if (attr['onDragEnd']) {\r
8746                                 scope.onDragEnd();\r
8747                             }\r
8748                             }\r
8749                         }\r
8750 \r
8751                         elm.on('keydown', onKeyDown);\r
8752                         elm.on('mousedown', onMouseDown);\r
8753 \r
8754                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);\r
8755                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);\r
8756 \r
8757                         ngModelCtrl.$render = function() {\r
8758                             if (!scope.isDragging) {\r
8759                                 modelRenderer();\r
8760                             }\r
8761                         };\r
8762                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);\r
8763                         ngModelCtrl.$formatters.push(getValidMinMax);\r
8764                         ngModelCtrl.$formatters.push(getValidStep);\r
8765                     }\r
8766                 };\r
8767             }]);\r
8768 /**\r
8769  * @ngdoc directive\r
8770  * @name Forms.att:selectorModule\r
8771  *\r
8772  * @description\r
8773  *  <file src="src/selectorModule/docs/readme.md" />\r
8774  *\r
8775  * @usage\r
8776  * <select name="myNameBig" type="large" b2b-dropdown ng-model="Controller Variable here">\r
8777  *   <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>\r
8778  * </select>\r
8779  *\r
8780  * <select name="myNameBig" type="large" b2b-dropdown ng-model="Controller Variable here">\r
8781  * <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>\r
8782  * </select>\r
8783  *\r
8784  * <select name="myNameBig" b2b-dropdown ng-model="Controller Variable here">\r
8785  *   <optgroup b2b-dropdown-group label="Group Label here">\r
8786  *     <option b2b-dropdown-list option-repeat="option data here" imgsrc="image path" value="value">List Text</option>\r
8787  *   </optgroup>\r
8788  * </select>\r
8789  *\r
8790  *  @example\r
8791  *  <section id="code">\r
8792         <example module="b2b.att">\r
8793             <file src="src/selectorModule/docs/demo.html" />\r
8794             <file src="src/selectorModule/docs/demo.js" />\r
8795        </example>\r
8796     </section>\r
8797  *\r
8798  */\r
8799 angular.module('b2b.att.selectorModule', ['b2b.att.dropdowns']);\r
8800 /**\r
8801  * @ngdoc directive\r
8802  * @name Layouts.att:separators\r
8803  *\r
8804  * @description\r
8805  *  <file src="src/separators/docs/readme.md" />\r
8806  *\r
8807  * @usage\r
8808 \r
8809  *\r
8810  * @example\r
8811  *  <section id="code">   \r
8812  <b>HTML + AngularJS</b>\r
8813  <example module="b2b.att">\r
8814  <file src="src/separators/docs/demo.html" />\r
8815  <file src="src/separators/docs/demo.js" />\r
8816  </example>\r
8817  </section>\r
8818  *\r
8819  */\r
8820 \r
8821 angular.module('b2b.att.separators', []);\r
8822 /**\r
8823  * @ngdoc directive\r
8824  * @name Buttons, links & UI controls.att:slider\r
8825  *\r
8826  * @description\r
8827  *  <file src="src/slider/docs/readme.md" />\r
8828  *\r
8829  * @usage\r
8830  *  <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
8831  *\r
8832  * @example\r
8833     <section id="code">   \r
8834         <b>HTML + AngularJS</b>\r
8835         <example module="b2b.att">\r
8836             <file src="src/slider/docs/demo.html" />\r
8837             <file src="src/slider/docs/demo.js" />\r
8838         </example>\r
8839     </section>\r
8840  */\r
8841 \r
8842 angular.module('b2b.att.slider', ['b2b.att.utilities'])\r
8843         .constant('SliderConfig', {\r
8844             'min': 0,\r
8845             'max': 100,\r
8846             'step': 1,\r
8847             'skipInterval': 1\r
8848         })\r
8849         .directive('b2bSlider', ['$documentBind', 'SliderConfig', 'keymap', '$compile', '$log', function($documentBind, SliderConfig, keymap, $compile, $log) {\r
8850                 return {\r
8851                     restrict: 'AE',\r
8852                     replace: true,\r
8853                     require: 'ngModel',\r
8854                     templateUrl: 'b2bTemplate/slider/slider.html',\r
8855                     scope: {\r
8856                         onDragEnd: '&?',\r
8857                         onDragInit: '&?',\r
8858                         trackFillColor: '=?',\r
8859                         preAriaLabel: '=?',\r
8860                         postAriaLabel: '=?',\r
8861                         onRenderEnd: '&?',\r
8862                         sliderSnapPoints: '=?',\r
8863                         customAriaLabel: '=?',\r
8864                         labelId: '@?'\r
8865                     },\r
8866                     link: function(scope, elm, attr, ngModelCtrl) {\r
8867                         scope.isDragging = false;\r
8868                         scope.verticalSlider = false;\r
8869                         var min;\r
8870                         var max;\r
8871                         var step = SliderConfig.step;\r
8872                         var skipInterval = SliderConfig.skipInterval;\r
8873                         var knob = angular.element(elm[0].querySelector('.slider-knob-container'));\r
8874                         var sliderKnob = angular.element(knob[0].querySelector('.slider-knob'));\r
8875                         var trackContainer = angular.element(elm[0].querySelector('.slider-track-container'));\r
8876                         var trackFill = angular.element(elm[0].querySelector('.slider-track-fill'));\r
8877                         var trackContainerRect = {};\r
8878                         var axisPosition = "clientX";\r
8879                         var trackFillOrderPositioning;\r
8880 \r
8881                         //Forcefully disabling the vertical Slider code.\r
8882                         if (angular.isDefined(attr.vertical)) {\r
8883                             scope.verticalSlider = true;\r
8884                             axisPosition = "clientY";\r
8885                         }\r
8886 \r
8887                         if (angular.isDefined(scope.noAriaLabel) && scope.noAriaLabel !== '') {\r
8888                             $log.warn('no-aria-label has been deprecated. This will be removed in v0.6.0.');\r
8889                         }\r
8890                         if (angular.isDefined(scope.preAriaLabel) && scope.preAriaLabel !== '') {\r
8891                             $log.warn('pre-aria-label has been deprecated. Please use label-id instead. This will be removed in v0.6.0.');\r
8892                         }\r
8893                         if (angular.isDefined(scope.customAriaLabel) && scope.customAriaLabel !== '') {\r
8894                             $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
8895                         }\r
8896 \r
8897                         var binarySearchNearest = function (num, arr) {\r
8898                             var mid;\r
8899                             var lo = 0;\r
8900                             var hi = arr.length - 1;\r
8901                             \r
8902                             while (hi - lo > 1) {\r
8903                                 mid = Math.floor((lo + hi) / 2);\r
8904                                 if (arr[mid] < num) {\r
8905                                     lo = mid;\r
8906                                 } else {\r
8907                                     hi = mid;\r
8908                                 }\r
8909                             }\r
8910                             if (num - arr[lo] < arr[hi] - num) {\r
8911                                 return arr[lo];\r
8912                             }\r
8913                             return arr[hi];\r
8914                         };\r
8915                         \r
8916                         var getValidStep = function(val) {\r
8917                             val = parseFloat(val);\r
8918                             // in case $modelValue came in string number\r
8919                             if (!isNaN(val)) {\r
8920                                 \r
8921                                 if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
8922                                     val = binarySearchNearest(val, scope.sliderSnapPoints);\r
8923                                 }\r
8924                                 else {\r
8925                                     val = Math.round((val - min) / step) * step + min;\r
8926                                 }\r
8927                                 \r
8928                                 return Math.round(val * 1000) / 1000;\r
8929                             }\r
8930                         };\r
8931 \r
8932                         var getPositionToPercent = function(x) {\r
8933                             if (scope.verticalSlider) {\r
8934                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));\r
8935                             }\r
8936                             else {\r
8937                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));\r
8938                             }\r
8939                         };\r
8940 \r
8941                         var getPercentToValue = function(percent) {\r
8942                             return (min + percent * (max - min));\r
8943                         };\r
8944 \r
8945                         var getValueToPercent = function(val) {\r
8946                             return (val - min) / (max - min);\r
8947                         };\r
8948 \r
8949                         var getValidMinMax = function(val) {\r
8950                             return Math.max(min, Math.min(max, val));\r
8951                         };\r
8952 \r
8953                         var updateTrackContainerRect = function() {\r
8954                             trackContainerRect = trackContainer[0].getBoundingClientRect();\r
8955                             if (scope.verticalSlider) {\r
8956                                 if (!trackContainerRect.height) {\r
8957                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;\r
8958                                 } else {\r
8959                                     trackFillOrderPositioning = trackContainerRect.height;\r
8960                                 }\r
8961                             }\r
8962                             else {\r
8963                                 if (!trackContainerRect.width) {\r
8964                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;\r
8965                                 } else {\r
8966                                     trackFillOrderPositioning = trackContainerRect.width;\r
8967                                 }\r
8968 \r
8969                             }\r
8970 \r
8971                         };\r
8972 \r
8973                         var updateKnobPosition = function(percent) {\r
8974                             var percentStr = (percent * 100) + '%';\r
8975                             if (scope.verticalSlider) {\r
8976                                 knob.css('bottom', percentStr);\r
8977                                 trackFill.css('height', percentStr);\r
8978                             }\r
8979                             else {\r
8980                                 knob.css('left', percentStr);\r
8981                                 trackFill.css('width', percentStr);\r
8982                             }\r
8983                         };\r
8984 \r
8985                         var modelRenderer = function() {\r
8986 \r
8987                             if(attr['disabled']){\r
8988                                 return;\r
8989                             }\r
8990 \r
8991                             if (isNaN(ngModelCtrl.$viewValue)) {\r
8992                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;\r
8993                             }\r
8994 \r
8995                             var viewVal = ngModelCtrl.$viewValue;\r
8996                             scope.currentModelValue = viewVal;\r
8997 \r
8998                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation\r
8999                             if ((min || min === 0) && max && step) {\r
9000                                 updateKnobPosition(getValueToPercent(viewVal));\r
9001                             }\r
9002                         };\r
9003 \r
9004                         var setModelValue = function(val) {\r
9005                             scope.currentModelValue = getValidMinMax(getValidStep(val));\r
9006                             ngModelCtrl.$setViewValue(scope.currentModelValue);\r
9007                         };\r
9008 \r
9009                         var updateMin = function(val) {\r
9010                             min = parseFloat(val);\r
9011                             if(isNaN(min)){\r
9012                                min = SliderConfig.min; \r
9013                             }\r
9014                             scope.min = min;\r
9015                             modelRenderer();\r
9016                         };\r
9017 \r
9018                         var updateMax = function(val) {\r
9019                             max = parseFloat(val);\r
9020                             if(isNaN(max)){\r
9021                                max = SliderConfig.max; \r
9022                             }\r
9023                             scope.max = max;\r
9024                             modelRenderer();\r
9025                         };\r
9026 \r
9027                         var updateStep = function(val) {\r
9028                             step = parseFloat(val);\r
9029                             if (!attr['skipInterval']) {\r
9030                                 skipInterval = step;\r
9031                             }\r
9032                         };\r
9033 \r
9034                         var updateSkipInterval = function(val) {\r
9035                             skipInterval = step * Math.ceil(val / (step!==0?step:1));\r
9036                         };\r
9037 \r
9038                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(SliderConfig.min);\r
9039                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(SliderConfig.max);\r
9040                         if (angular.isDefined(attr.step)) {\r
9041                             attr.$observe('step', updateStep);\r
9042                         }\r
9043                         if (angular.isDefined(attr.skipInterval)) {\r
9044                             attr.$observe('skipInterval', updateSkipInterval);\r
9045                         }\r
9046                         scope.currentModelValue = getValidMinMax(getValidStep(min));\r
9047                         var onMouseDown = function(e) {\r
9048 \r
9049                             if(attr['disabled']){\r
9050                                 return;\r
9051                             }\r
9052 \r
9053                             switch (e.which) {\r
9054                                 case 1:\r
9055                                     // left mouse button\r
9056                                     break;\r
9057                                 case 2:\r
9058                                 case 3:\r
9059                                     // right or middle mouse button\r
9060                                     return;\r
9061                             }\r
9062 \r
9063                             scope.isDragging = true;\r
9064                             sliderKnob[0].focus();\r
9065                             updateTrackContainerRect();\r
9066                             if (attr['onDragInit']) {\r
9067                                 scope.onDragInit();\r
9068                             }\r
9069                             e.stopPropagation();\r
9070                             e.preventDefault();\r
9071                              scope.$apply(function() {\r
9072                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
9073                             });\r
9074                         };\r
9075 \r
9076                         var onMouseUp = function() {\r
9077 \r
9078                             if (attr['onDragEnd']) {\r
9079                                 scope.onDragEnd();\r
9080                             }\r
9081                             scope.isDragging = false;\r
9082                             scope.$digest();\r
9083                         };\r
9084 \r
9085                         var onMouseMove = function(e) {\r
9086                             if (scope.isDragging) {\r
9087                                 e.stopPropagation();\r
9088                                 e.preventDefault();\r
9089 \r
9090                                 scope.$apply(function() {\r
9091                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));\r
9092                                 });\r
9093                             }\r
9094                         };\r
9095 \r
9096                         function onKeyDown(e) {\r
9097                             if (!(e.keyCode)) {\r
9098                                 e.keyCode = e.which;\r
9099                             }\r
9100                             var updateStep;\r
9101                             switch (e.keyCode) {\r
9102                                 case keymap.KEY.DOWN:\r
9103                                 case keymap.KEY.LEFT:\r
9104                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9105                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);\r
9106                                         if (currentIndex > 0) {\r
9107                                             currentIndex--;\r
9108                                         }\r
9109                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9110                                     }\r
9111                                     else {\r
9112                                         updateStep = ngModelCtrl.$viewValue - skipInterval;\r
9113                                     }\r
9114                                     break;\r
9115                                 case keymap.KEY.UP:\r
9116                                 case keymap.KEY.RIGHT:\r
9117                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9118                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);\r
9119                                         if (currentIndex < scope.sliderSnapPoints.length-1) {\r
9120                                             currentIndex++;\r
9121                                         }\r
9122                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9123                                     }\r
9124                                     else {\r
9125                                         updateStep = ngModelCtrl.$viewValue + skipInterval;\r
9126                                     }\r
9127                                     break;\r
9128                                 case keymap.KEY.END:\r
9129                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9130                                         currentIndex = scope.sliderSnapPoints.length-1;\r
9131                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9132                                     } else {\r
9133                                         setModelValue(scope.max);\r
9134                                     }\r
9135                                     e.preventDefault();\r
9136                                     e.stopPropagation();\r
9137                                     break;\r
9138                                 case keymap.KEY.HOME:\r
9139                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {\r
9140                                         currentIndex = 0;\r
9141                                         updateStep = scope.sliderSnapPoints[currentIndex];\r
9142                                     } else {\r
9143                                         setModelValue(scope.min);\r
9144                                     }\r
9145                                     e.preventDefault();\r
9146                                     e.stopPropagation();\r
9147                                     break;\r
9148                                 default:\r
9149                                     return;\r
9150                             }\r
9151 \r
9152                             if (angular.isNumber(updateStep) && !attr['disabled']) {\r
9153                                 e.stopPropagation();\r
9154                                 e.preventDefault();\r
9155                                 scope.$apply(function() {\r
9156                                     setModelValue(updateStep);\r
9157                                 });\r
9158                                 if (attr['onDragEnd']) {\r
9159                                     scope.onDragEnd();\r
9160                                 }\r
9161                             }\r
9162                         }\r
9163 \r
9164                         elm.on('keydown', onKeyDown);\r
9165                         elm.on('mousedown', onMouseDown);\r
9166 \r
9167                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);\r
9168                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);\r
9169 \r
9170                         attr.$observe('disabled', function (disabled) {\r
9171                             if (disabled) {\r
9172                                 sliderKnob.removeAttr('tabindex');\r
9173                             } else {\r
9174                                 sliderKnob.attr('tabindex', '0');\r
9175                                 disabled = false;\r
9176                             }\r
9177 \r
9178                             elm.toggleClass("slider-disabled", disabled);\r
9179 \r
9180                             if (angular.isDefined(attr.hideDisabledKnob)) {\r
9181                                 scope.hideKnob = disabled;\r
9182                             }\r
9183                         });\r
9184 \r
9185                         ngModelCtrl.$render = function() {\r
9186                             if (!scope.isDragging) {\r
9187                                 modelRenderer();\r
9188                                 if (attr['onRenderEnd'] && !attr['disabled']) {\r
9189                                     scope.onRenderEnd({currentModelValue: scope.currentModelValue});\r
9190                                 }\r
9191                             }\r
9192                         };\r
9193                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);\r
9194                         ngModelCtrl.$formatters.push(getValidMinMax);\r
9195                         ngModelCtrl.$formatters.push(getValidStep);\r
9196                     }\r
9197                 };\r
9198             }]);\r
9199 /**\r
9200  * @ngdoc directive\r
9201  * @name Forms.att:spinButton\r
9202  *\r
9203  * @param {String} spin-button-id - An ID for the input field\r
9204  * @param {Integer} min - Minimum value for the input\r
9205  * @param {Integer} max - Maximum value for the input\r
9206  * @param {Integer} step - Value by which input field increments or decrements on up/down arrow keys\r
9207  * @param {Integer} page-step - Value by which input field increments or decrements on page up/down keys\r
9208  * @param {boolean} input-model-key - Default value for input field\r
9209  * @param {boolean} disabled-flag - A boolean that triggers directive once the min or max value has reached\r
9210  *\r
9211  * @description\r
9212  *  <file src="src/spinButton/docs/readme.md" />\r
9213  *\r
9214  * @example\r
9215  *  <section id="code">\r
9216         <example module="b2b.att">\r
9217             <file src="src/spinButton/docs/demo.html" />\r
9218             <file src="src/spinButton/docs/demo.js" />\r
9219        </example>\r
9220     </section>\r
9221  * \r
9222  */\r
9223 angular.module('b2b.att.spinButton', ['b2b.att.utilities'])\r
9224     .constant('b2bSpinButtonConfig', {\r
9225         min: 1,\r
9226         max: 10,\r
9227         step: 1,\r
9228         pageStep: 10,\r
9229         inputModelKey: 'value',\r
9230         disabledFlag: false\r
9231     })\r
9232     .directive('b2bSpinButton', ['keymap', 'b2bSpinButtonConfig', 'b2bUserAgent', function (keymap, b2bSpinButtonConfig, userAgent) {\r
9233         return {\r
9234             restrict: 'EA',\r
9235             require: '?ngModel',\r
9236             transclude: false,\r
9237             replace: true,\r
9238             scope: {\r
9239                 min: '=min',\r
9240                 max: '=max',\r
9241                 step: '=step',\r
9242                 pageStep: '=pageStep',\r
9243                 spinButtonId: '@',\r
9244                 inputValue: '=ngModel',\r
9245                 inputModelKey: '@',\r
9246                 disabledFlag: "=?"\r
9247             },\r
9248             templateUrl: 'b2bTemplate/spinButton/spinButton.html',\r
9249             controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {\r
9250 \r
9251                 scope.isMobile = userAgent.isMobile();\r
9252                 scope.notMobile = userAgent.notMobile();\r
9253 \r
9254                 scope.min = attrs.min ? scope.min : b2bSpinButtonConfig.min;\r
9255                 scope.max = attrs.max ? scope.max : b2bSpinButtonConfig.max;\r
9256                 scope.step = attrs.step ? scope.step : b2bSpinButtonConfig.step;\r
9257                 scope.pageStep = attrs.pageStep ? scope.pageStep : b2bSpinButtonConfig.pageStep;\r
9258                 scope.inputModelKey = attrs.inputModelKey ? scope.inputModelKey : b2bSpinButtonConfig.inputModelKey;\r
9259                 scope.disabledFlag = attrs.disabledFlag ? scope.disabledFlag : b2bSpinButtonConfig.disabledFlag;\r
9260                 \r
9261                 if (scope.min < 0) {\r
9262                     scope.min = 0;\r
9263                 }\r
9264                 if (scope.max > 999) {\r
9265                     scope.max = 999;\r
9266                 }\r
9267 \r
9268                 scope.isPlusDisabled = function () {\r
9269                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] >= scope.max);\r
9270                 };\r
9271                 scope.isMinusDisabled = function () {\r
9272                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] <= scope.min);\r
9273                 };\r
9274 \r
9275                 scope.getValidateInputValue = function (value) {\r
9276                     if (value <= scope.min) {\r
9277                         return scope.min;\r
9278                     } else if (value >= scope.max) {\r
9279                         return scope.max;\r
9280                     } else {\r
9281                         return value;\r
9282                     }\r
9283                 };\r
9284 \r
9285                 scope.plus = function () {\r
9286                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.step);\r
9287                 };\r
9288                 scope.minus = function () {\r
9289                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.step);\r
9290                 };\r
9291                 scope.pagePlus = function () {\r
9292                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.pageStep);\r
9293                 };\r
9294                 scope.pageMinus = function () {\r
9295                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.pageStep);\r
9296                 };\r
9297 \r
9298             }],\r
9299             link: function (scope, elem) {\r
9300 \r
9301                 if (scope.notMobile) {\r
9302                     angular.element(elem).find('input').attr('aria-live', 'off');\r
9303                     angular.element(elem).find('input').attr('role', 'spinbutton');\r
9304                 }\r
9305 \r
9306                 elem.find('input').bind('keydown', function (e) {\r
9307                     if (e.keyCode === keymap.KEY.UP) {\r
9308                         scope.plus();\r
9309                     } else if (e.keyCode === keymap.KEY.DOWN){\r
9310                         scope.minus();\r
9311                     } else if (e.keyCode === keymap.KEY.HOME) {\r
9312                         scope.inputValue[scope.inputModelKey] = parseInt(scope.min);\r
9313                     } else if (e.keyCode === keymap.KEY.END) {\r
9314                         scope.inputValue[scope.inputModelKey] = parseInt(scope.max);\r
9315                     } else if (e.keyCode === keymap.KEY.PAGE_UP) {\r
9316                         scope.pagePlus();\r
9317                     } else if (e.keyCode === keymap.KEY.PAGE_DOWN) {\r
9318                         scope.pageMinus();\r
9319                     }\r
9320                     scope.$apply();\r
9321                 });\r
9322 \r
9323                 elem.find('input').bind('keyup', function () {\r
9324                     if (scope.inputValue[scope.inputModelKey] === null ||\r
9325                         scope.inputValue[scope.inputModelKey] === '' ||\r
9326                         scope.inputValue[scope.inputModelKey] < scope.min) {\r
9327                         scope.inputValue[scope.inputModelKey] = scope.min;\r
9328                         scope.$apply();\r
9329                     } else if (angular.isUndefined(scope.inputValue[scope.inputModelKey]) || \r
9330                                scope.inputValue[scope.inputModelKey] > scope.max) {\r
9331                         scope.inputValue[scope.inputModelKey] = scope.max;\r
9332                         scope.$apply();\r
9333                     }\r
9334                 });\r
9335 \r
9336                 scope.focusInputSpinButton = function (evt) {\r
9337                     evt.preventDefault();\r
9338                     if (scope.notMobile) {\r
9339                         elem[0].querySelector('input').focus();\r
9340                     }\r
9341                 };\r
9342 \r
9343             }\r
9344         };  \r
9345     }]);\r
9346 /** \r
9347  * @ngdoc directive \r
9348  * @name Template.att:Static Route\r
9349  * \r
9350  * @description \r
9351  *  <file src="src/staticRouteTemplate/docs/readme.md" /> \r
9352  * \r
9353  * @example \r
9354  *  <section id="code"> \r
9355         <example module="b2b.att"> \r
9356             <file src="src/staticRouteTemplate/docs/demo.html" /> \r
9357             <file src="src/staticRouteTemplate/docs/demo.js" /> \r
9358        </example> \r
9359     </section>    \r
9360  * \r
9361  */\r
9362 angular.module('b2b.att.staticRouteTemplate', ['b2b.att.utilities'])\r
9363   \r
9364 /**\r
9365  * @ngdoc directive\r
9366  * @name Progress & usage indicators.att:statusTracker\r
9367  *\r
9368  * @scope\r
9369  * @param {array} statuses - An array of status objects\r
9370  * @description\r
9371  * <file src="src/statusTracker/docs/readme.md" />\r
9372  *\r
9373  * @usage\r
9374  *\r
9375 <div ng-controller="statusTrackerController">\r
9376     <b2b-status-tracker statuses="statusObject"></b2b-status-tracker>\r
9377 </div>\r
9378 \r
9379  * @example\r
9380     <section id="code">   \r
9381         <b>HTML + AngularJS</b>\r
9382         <example module="b2b.att">\r
9383             <file src="src/statusTracker/docs/demo.html" />\r
9384             <file src="src/statusTracker/docs/demo.js" />\r
9385         </example>\r
9386     </section>\r
9387  */\r
9388 \r
9389 angular.module('b2b.att.statusTracker', ['b2b.att.utilities'])\r
9390 .constant('b2bStatusTrackerConfig', {\r
9391     'maxViewItems': 3\r
9392 })\r
9393 .directive('b2bStatusTracker', ['b2bStatusTrackerConfig', function(b2bStatusTrackerConfig) {\r
9394         return {\r
9395             restrict: 'EA',\r
9396             transclude: false,\r
9397             replace: true,\r
9398             scope:{\r
9399                 statuses: '='\r
9400             },\r
9401             templateUrl: function(scope) {\r
9402                 return 'b2bTemplate/statusTracker/statusTracker.html';\r
9403             },\r
9404             link: function(scope, element, attr) {\r
9405                 scope.currentViewIndex = 0;\r
9406                 scope.b2bStatusTrackerConfig = b2bStatusTrackerConfig;\r
9407 \r
9408                 scope.nextStatus = function() {\r
9409                     if (scope.currentViewIndex+1 <= scope.statuses.length) {\r
9410                         scope.currentViewIndex++;\r
9411                     }\r
9412                 };\r
9413                 scope.previousStatus = function() {\r
9414                     if (scope.currentViewIndex-1 >= 0) {\r
9415                         scope.currentViewIndex--;\r
9416                     }\r
9417                 };\r
9418                 scope.isInViewport = function(index) {\r
9419                     return (index < scope.currentViewIndex+3 && index >= scope.currentViewIndex);  // && index > scope.currentViewIndex-2\r
9420                 };\r
9421                 scope.currentStatus = function(index) {\r
9422                     if(index != undefined){\r
9423                         if(!scope.statuses[index].complete) {\r
9424                             if(index > 0 && scope.statuses[index-1].complete) {\r
9425                                 return true;\r
9426                             } else if(index == 0 && !scope.statuses[index].complete){\r
9427                                 return true;\r
9428                             } else {\r
9429                                 return false;\r
9430                             }\r
9431                         }\r
9432                     }\r
9433                 };\r
9434             }\r
9435         };\r
9436     }]);\r
9437 /**\r
9438  * @ngdoc directive\r
9439  * @name Progress & usage indicators.att:stepTracker\r
9440  *\r
9441  * @scope\r
9442  * @param {array} stepsItemsObject - An array of step objects\r
9443  * @param {Integer} currenIindex - This indicates the current running step\r
9444  * @param {Integer} viewportIndex - This is optional. This can used to start the view port rather than 1 item.\r
9445  * @description\r
9446  * <file src="src/stepTracker/docs/readme.md" />\r
9447  *\r
9448  * @usage\r
9449  *\r
9450  *  <b2b-step-tracker steps-items-object="stepsObject" current-index="currentStepIndex" step-indicator-heading="stepHeading"></b2b-step-tracker>\r
9451  *\r
9452 \r
9453  * @example\r
9454     <section id="code">   \r
9455         <b>HTML + AngularJS</b>\r
9456         <example module="b2b.att">\r
9457             <file src="src/stepTracker/docs/demo.html" />\r
9458             <file src="src/stepTracker/docs/demo.js" />\r
9459         </example>\r
9460     </section>\r
9461  */\r
9462 angular.module('b2b.att.stepTracker', ['b2b.att.utilities'])\r
9463     .constant('b2bStepTrackerConfig', {\r
9464         'maxViewItems': 5\r
9465     })\r
9466     .directive('b2bStepTracker', ['b2bStepTrackerConfig', function(b2bStepTrackerConfig) {\r
9467         return {\r
9468             restrict: 'EA',\r
9469             transclude: true,\r
9470             scope:{\r
9471                 stepsItemsObject:"=",\r
9472                 currentIndex:"=",\r
9473                 viewportIndex:"=?"\r
9474             },\r
9475             templateUrl: 'b2bTemplate/stepTracker/stepTracker.html',\r
9476             link: function(scope, ele, attr) {\r
9477                 if (angular.isDefined(scope.viewportIndex)) {\r
9478                     scope.currentViewIndex = scope.viewportIndex - 1;   \r
9479                 }else{\r
9480                     scope.currentViewIndex = 0;\r
9481                 }\r
9482                \r
9483                scope.b2bStepTrackerConfig = b2bStepTrackerConfig;\r
9484                scope.nextStatus = function() {\r
9485                     if (scope.currentViewIndex+1 <= scope.stepsItemsObject.length) {\r
9486                         scope.currentViewIndex++;\r
9487                     }\r
9488                 };\r
9489                 scope.previousStatus = function() {\r
9490                     if (scope.currentViewIndex-1 >= 0) {\r
9491                         scope.currentViewIndex--;\r
9492                     }\r
9493                 };\r
9494                 scope.isInViewport = function(index) {\r
9495                     return (index < scope.currentViewIndex+b2bStepTrackerConfig.maxViewItems && index >= scope.currentViewIndex);\r
9496                 };\r
9497             }\r
9498         };\r
9499     }]);\r
9500      \r
9501 /**\r
9502  * @ngdoc directive\r
9503  * @name Buttons, links & UI controls.att:switches\r
9504  *\r
9505  * @description\r
9506  *  <file src="src/switches/docs/readme.md" />\r
9507  *\r
9508  * @usage\r
9509  *  \r
9510  *  <!-- On / Off Toggle switch -->\r
9511  *  <label for="switch1" class="controlled-text-wrap"> This is ON\r
9512  *      <input type="checkbox" role="checkbox" b2b-switches id="switch1" ng-model="switch1.value">\r
9513  *  </label>\r
9514  *\r
9515  *  <!-- On / Off Toggle switch and DISABLED -->\r
9516  *  <label for="switch2" class="controlled-text-wrap"> This is ON (disabled)\r
9517  *      <input type="checkbox" role="checkbox" b2b-switches id="switch2" ng-model="switch1.value" ng-disabled="true" >\r
9518  *  </label> \r
9519  *\r
9520  *\r
9521  * @example\r
9522  *  <section id="code">\r
9523         <b>HTML + AngularJS</b>\r
9524         <example module="b2b.att">\r
9525             <file src="src/switches/docs/demo.js" />\r
9526             <file src="src/switches/docs/demo.html" />\r
9527         </example>\r
9528     </section>\r
9529  */\r
9530 angular.module('b2b.att.switches', ['b2b.att.utilities'])\r
9531     .directive('b2bSwitches', ['$compile', '$templateCache', 'keymap', 'events', function ($compile, $templateCache, keymap, events) {\r
9532         return {\r
9533             restrict: 'EA',\r
9534             require: ['ngModel'],\r
9535             link: function (scope, element, attrs, ctrl) {\r
9536                 var ngModelController = ctrl[0];\r
9537         \r
9538                 element.parent().bind("keydown", function (e) {\r
9539                     if (!attrs.disabled && (e.keyCode === keymap.KEY.ENTER || e.keyCode === keymap.KEY.SPACE)) {\r
9540                         events.preventDefault(e);\r
9541                         ngModelController.$setViewValue(!ngModelController.$viewValue);\r
9542                         element.prop("checked", ngModelController.$viewValue);\r
9543                     }\r
9544                 });\r
9545 \r
9546                 element.wrap('<div class="btn-switch">');\r
9547                 //element.attr("tabindex", -1);\r
9548                 if (navigator.userAgent.match(/iphone/i)){\r
9549                     element.attr("aria-live", "polite");\r
9550                 }\r
9551                 else {\r
9552                     element.removeAttr('aria-live');\r
9553                 }\r
9554 \r
9555                 var templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches.html"));\r
9556                 if (angular.isDefined(attrs.typeSpanish)) {\r
9557                     templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches-spanish.html"));\r
9558                 }\r
9559 \r
9560                 templateSwitch = $compile(templateSwitch)(scope);\r
9561                 element.parent().append(templateSwitch);\r
9562 \r
9563                 element.bind("focus", function (e) {\r
9564                     element.parent().addClass('focused');\r
9565                 });\r
9566 \r
9567                 element.bind("blur", function (e) {\r
9568                     element.parent().removeClass('focused');\r
9569                 });\r
9570             }\r
9571         };\r
9572     }]);\r
9573 /**\r
9574  * @ngdoc directive\r
9575  * @name Messages, modals & alerts.att:tableMessages\r
9576  *\r
9577  * @description\r
9578  *  <file src="src/tableMessages/docs/readme.md" />\r
9579  *\r
9580  * @usage\r
9581     <!-- no matching results -->\r
9582     <b2b-table-message msg-type="'noMatchingResults'">\r
9583        <p>No Matching Results</p>\r
9584     </b2b-table-message>\r
9585   \r
9586     <!-- info could not load -->\r
9587     <b2b-table-message msg-type="'infoCouldNotLoad'" on-refresh-click="refreshClicked()">\r
9588     </b2b-table-message>\r
9589    \r
9590     <!-- magnify search -->\r
9591     <b2b-table-message msg-type="'magnifySearch'">\r
9592     </b2b-table-message>\r
9593    \r
9594     <!-- loading data -->\r
9595     <b2b-table-message msg-type="'loadingTable'">\r
9596           <!-- custom html -->\r
9597           <p>The data is currently loading...</p>\r
9598     </b2b-table-message>\r
9599 \r
9600  * @example\r
9601     <section id="code">   \r
9602         <b>HTML + AngularJS</b>\r
9603         <example module="b2b.att">\r
9604             <file src="src/tableMessages/docs/demo.html" />\r
9605             <file src="src/tableMessages/docs/demo.js" />\r
9606         </example>\r
9607     </section>\r
9608  */\r
9609 angular.module('b2b.att.tableMessages', [])\r
9610     .directive('b2bTableMessage', [function() {\r
9611         return {\r
9612             restrict: 'AE',\r
9613             replace: true,\r
9614             transclude: true,\r
9615             scope: {\r
9616                 msgType: '=',\r
9617                 onRefreshClick: '&'\r
9618             },\r
9619             templateUrl: 'b2bTemplate/tableMessages/tableMessage.html',\r
9620             link: function(scope) {\r
9621                 scope.refreshAction = function(evt) {\r
9622                     scope.onRefreshClick(evt);\r
9623                 };\r
9624             }\r
9625         };\r
9626     }]);\r
9627 \r
9628 /**\r
9629  * @ngdoc directive\r
9630  * @name Tabs, tables & accordions.att:tableScrollbar\r
9631  *\r
9632  * @description\r
9633  *  <file src="src/tableScrollbar/docs/readme.md" />\r
9634  *\r
9635  * @usage\r
9636  * \r
9637 <b2b-table-scrollbar>\r
9638     <table>\r
9639         <thead type="header">\r
9640             <tr>\r
9641                 <th role="columnheader" scope="col" key="Id" id="col1">Id</th>\r
9642                 .....\r
9643             </tr>\r
9644         </thead>\r
9645         <tbody type="body">\r
9646             <tr>\r
9647                 <td id="rowheader0" headers="col1">1002</td>\r
9648                 .....\r
9649             </tr>\r
9650         </tbody>\r
9651     </table>\r
9652 </b2b-table-scrollbar>\r
9653  *\r
9654  * @example\r
9655  *  <section id="code">\r
9656         <example module="b2b.att">\r
9657             <file src="src/tableScrollbar/docs/demo.html" />\r
9658             <file src="src/tableScrollbar/docs/demo.js" />\r
9659        </example>\r
9660     </section>\r
9661  *\r
9662  */\r
9663 angular.module('b2b.att.tableScrollbar', [])\r
9664     .directive('b2bTableScrollbar', ['$timeout', function ($timeout) {\r
9665         return {\r
9666             restrict: 'E',\r
9667             scope: true,\r
9668             transclude: true,\r
9669             templateUrl: 'b2bTemplate/tableScrollbar/tableScrollbar.html',\r
9670             link: function (scope, element, attrs, ctrl) {\r
9671                 var firstThWidth, firstTdWidth, firstColumnWidth, firstColumnHeight, trHeight = 0;\r
9672                 var pxToScroll = '';\r
9673                 var tableElement = element.find('table');\r
9674                 var thElements = element.find('th');\r
9675                 var tdElements = element.find('td');\r
9676                 var innerContainer = angular.element(element[0].querySelector('.b2b-table-inner-container'));\r
9677                 var outerContainer = angular.element(element[0].querySelector('.b2b-table-scrollbar'));\r
9678 \r
9679                 scope.disableLeft = true;\r
9680                 scope.disableRight = false;\r
9681 \r
9682                 if (angular.isDefined(thElements[0])) {\r
9683                     firstThWidth = thElements[0].offsetWidth;\r
9684                 }\r
9685                 if (angular.isDefined(tdElements[0])) {\r
9686                     firstTdWidth = tdElements[0].offsetWidth;\r
9687                 }\r
9688                 firstColumnWidth = (firstThWidth > firstTdWidth) ? firstThWidth : firstTdWidth;\r
9689 \r
9690                 innerContainer.css({\r
9691                     'padding-left': (firstColumnWidth + 2) + 'px'\r
9692                 });\r
9693 \r
9694                 angular.forEach(element.find('tr'), function (eachTr, index) {\r
9695                     trObject = angular.element(eachTr);\r
9696                     firstColumn = angular.element(trObject.children()[0]);\r
9697 \r
9698                     angular.element(firstColumn).css({\r
9699                         'margin-left': -(firstColumnWidth + 2) + 'px',\r
9700                         'width': (firstColumnWidth + 2) + 'px',\r
9701                         'position': 'absolute'\r
9702                     });\r
9703 \r
9704                     trHeight = trObject[0].offsetHeight;\r
9705                     firstColumnHeight = firstColumn[0].offsetHeight;\r
9706                     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {\r
9707                         firstColumnHeight += 1;\r
9708                     }\r
9709 \r
9710                     if (trHeight !== firstColumnHeight - 1) {\r
9711                         if (trHeight > firstColumnHeight) {\r
9712                             if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {\r
9713                                 trHeight -= 1;\r
9714                             }\r
9715                             angular.element(firstColumn).css({\r
9716                                 'height': (trHeight + 1) + 'px'\r
9717                             });\r
9718                         } else {\r
9719                             angular.element(trObject).css({\r
9720                                 'height': (firstColumnHeight - 1) + 'px'\r
9721                             });\r
9722                         }\r
9723                     }\r
9724 \r
9725                 });\r
9726 \r
9727                 pxToScroll = outerContainer[0].offsetWidth - firstColumnWidth;\r
9728 \r
9729                 scope.scrollLeft = function () {\r
9730                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + 20 - pxToScroll;\r
9731                 };\r
9732 \r
9733                 scope.scrollRight = function () {\r
9734                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + pxToScroll - 20;\r
9735                 };\r
9736 \r
9737                 scope.checkScrollArrows = function () {\r
9738                     if (innerContainer[0].scrollLeft == 0) {\r
9739                         scope.disableLeft = true;\r
9740                     } else {\r
9741                         scope.disableLeft = false;\r
9742                     }\r
9743 \r
9744                     if (((innerContainer[0].offsetWidth - firstColumnWidth) + innerContainer[0].scrollLeft) >= tableElement[0].offsetWidth) {\r
9745                         scope.disableRight = true;\r
9746                     } else {\r
9747                         scope.disableRight = false;\r
9748                     }\r
9749                 };\r
9750 \r
9751                 innerContainer.bind('scroll', function () {\r
9752                     $timeout(function () {\r
9753                         scope.checkScrollArrows();\r
9754                     }, 1);\r
9755                 });\r
9756 \r
9757             }\r
9758         };\r
9759     }]);\r
9760 /**\r
9761  * @ngdoc directive\r
9762  * @name Tabs, tables & accordions.att:tables\r
9763  *\r
9764  * @description\r
9765  *  <file src="src/tables/docs/readme.md" />\r
9766  *\r
9767  * @usage\r
9768  *   \r
9769  Table\r
9770  <table b2b-table table-data="tableData" search-string="searchString">\r
9771     <thead b2b-table-row type="header">\r
9772         <tr>\r
9773             <th b2b-table-header key="requestId" default-sort="a" id="col1">Header 1</th>\r
9774             <th b2b-table-header key="requestType" sortable="false" id="col2">Header 2</th>\r
9775         </tr>\r
9776     </thead>\r
9777     <tbody b2b-table-row type="body" row-repeat="rowData in tableData">\r
9778         <tr>\r
9779             <td b2b-table-body id="rowheader{{$index}}" headers="col1" ng-bind="rowData['requestId']"> </td>\r
9780             <td b2b-table-body ng-bind="rowData['requestType']"></td>\r
9781         </tr>\r
9782     </tbody>\r
9783  </table>\r
9784  *\r
9785  * @example\r
9786  *  <section id="code">\r
9787         <example module="b2b.att">\r
9788             <file src="src/tables/docs/demo.html" />\r
9789             <file src="src/tables/docs/demo.js" />\r
9790        </example>\r
9791     </section>\r
9792  *\r
9793  */\r
9794 angular.module('b2b.att.tables', ['b2b.att.utilities'])\r
9795     .constant('b2bTableConfig', {\r
9796         defaultSortPattern: false, // true for descending & false for ascending\r
9797         highlightSearchStringClass: 'tablesorter-search-highlight',\r
9798         zebraStripCutOff: 6, // > zebraStripCutOff\r
9799         tableBreakpoints: [ // breakpoints are >= min and < max\r
9800             {\r
9801                 min: 0,\r
9802                 max: 480,\r
9803                 columns: 2\r
9804             },\r
9805             {\r
9806                 min: 480,\r
9807                 max: 768,\r
9808                 columns: 3\r
9809             },\r
9810             {\r
9811                 min: 768,\r
9812                 max: 1025,\r
9813                 columns: 5\r
9814             },\r
9815             {\r
9816                 min: 1025,\r
9817                 max: 1920,\r
9818                 columns: 7\r
9819             }\r
9820         ]\r
9821     })\r
9822     .directive('b2bTable', ['$filter', '$window', 'b2bTableConfig', '$timeout', function ($filter, $window, b2bTableConfig, $timeout) {\r
9823         return {\r
9824             restrict: 'EA',\r
9825             replace: true,\r
9826             transclude: true,\r
9827             scope: {\r
9828                 tableData: "=",\r
9829                 viewPerPage: "=",\r
9830                 currentPage: "=",\r
9831                 totalPage: "=",\r
9832                 searchCategory: "=",\r
9833                 searchString: "=",\r
9834                 nextSort: '='\r
9835             },\r
9836             require: 'b2bTable',\r
9837             templateUrl: 'b2bTemplate/tables/b2bTable.html',\r
9838             controller: ['$scope', '$attrs', function ($scope, $attrs) {\r
9839                 this.headers = [];\r
9840                 this.currentSortIndex = null;\r
9841                 this.responsive = $scope.responsive = $attrs.responsive;\r
9842                 this.maxTableColumns = -1;\r
9843                 this.totalTableColums = 0;\r
9844                 this.active = $scope.active = false;\r
9845                 this.responsiveRowScopes = [];\r
9846                 this.hideColumnPriority = [];\r
9847                 this.hiddenColumn = [];\r
9848                 this.setIndex = function (headerScope, priority) {\r
9849                     this.headers.push(headerScope);\r
9850                     if (this.responsive) {\r
9851                         this.totalTableColums++;\r
9852                         if (!isNaN(priority)) {\r
9853                             this.hideColumnPriority[priority] = this.totalTableColums - 1;\r
9854                         } else {\r
9855                             this.hideColumnPriority[this.totalTableColums - 1] = this.totalTableColums - 1;\r
9856                         }\r
9857                     }\r
9858                     return this.totalTableColums - 1;\r
9859                 };\r
9860                 this.getIndex = function (headerName) {\r
9861                     for (var i = 0; i < this.headers.length; i++) {\r
9862                         if (this.headers[i].headerName === headerName) {\r
9863                             return this.headers[i].index;\r
9864                         }\r
9865                     }\r
9866                     return null;\r
9867                 };\r
9868                 this.setResponsiveRow = function (responsiveRowScope) {\r
9869                     this.responsiveRowScopes.push(responsiveRowScope);\r
9870                 }\r
9871                 $scope.nextSort = '';\r
9872                 this.sortData = function (columnIndex, reverse, externalSort) {\r
9873                     if ($scope.$parent && $scope.$parent !== undefined) {\r
9874                         $scope.$parent.columnIndex = columnIndex;\r
9875                         $scope.$parent.reverse = reverse;\r
9876                     }\r
9877                     this.currentSortIndex = columnIndex;\r
9878                     if (externalSort === true) {\r
9879                         if (!reverse) {\r
9880                             $scope.nextSort = 'd'\r
9881                         } else {\r
9882                             $scope.nextSort = 'a'\r
9883                         }\r
9884                     }\r
9885                     $scope.currentPage = 1;\r
9886                     this.resetSortPattern();\r
9887                 };\r
9888                 this.getSearchString = function () {\r
9889                     return $scope.searchString;\r
9890                 };\r
9891                 this.resetSortPattern = function () {\r
9892                     for (var i = 0; i < this.headers.length; i++) {\r
9893                         var currentScope = this.headers[i];\r
9894                         if (currentScope.index !== this.currentSortIndex) {\r
9895                             currentScope.resetSortPattern();\r
9896                         }\r
9897                     }\r
9898                 };\r
9899 \r
9900                 $scope.$watch('nextSort', function (val) {\r
9901                     if ($scope.$parent && $scope.$parent !== undefined) {\r
9902                         $scope.$parent.nextSort = val;\r
9903                     }\r
9904 \r
9905                 });\r
9906             }],\r
9907             link: function (scope, elem, attr, ctrl) {\r
9908                 scope.searchCriteria = {};\r
9909                 scope.tableBreakpoints = attr.tableConfig ? scope.$parent.$eval(attr.tableConfig) : angular.copy(b2bTableConfig.tableBreakpoints);\r
9910                 scope.$watchCollection('tableData', function (value) {\r
9911                     if (value && !isNaN(value.length)) {\r
9912                         scope.totalRows = value.length;\r
9913                     }\r
9914                 });\r
9915                 scope.$watch('currentPage', function (val) {\r
9916                     if (scope.$parent && scope.$parent !== undefined) {\r
9917                         scope.$parent.currentPage = val;\r
9918                     }\r
9919 \r
9920                 });\r
9921                 scope.$watch('viewPerPage', function (val) {\r
9922                     if (scope.$parent && scope.$parent !== undefined) {\r
9923                         scope.$parent.viewPerPage = val;\r
9924                     }\r
9925                 });\r
9926                 scope.$watch('totalRows', function (val) {\r
9927                     if (scope.$parent && scope.$parent !== undefined) {\r
9928                         if (val > b2bTableConfig.zebraStripCutOff) {\r
9929                             scope.$parent.zebraStripFlag = true;\r
9930                         } else {\r
9931                             scope.$parent.zebraStripFlag = false;\r
9932                         }\r
9933                     }\r
9934                 });\r
9935                 scope.$watch(function () {\r
9936                     return scope.totalRows / scope.viewPerPage;\r
9937                 }, function (value) {\r
9938                     if (!isNaN(value)) {\r
9939                         scope.totalPage = Math.ceil(value);\r
9940                         scope.currentPage = 1;\r
9941                     }\r
9942                 });\r
9943                 var searchValCheck = function (val) {\r
9944                     if (angular.isDefined(val) && val !== null && val !== "") {\r
9945                         return true;\r
9946                     }\r
9947                 };\r
9948                 var setSearchCriteria = function (v1, v2) {\r
9949                     if (searchValCheck(v1) && searchValCheck(v2)) {\r
9950                         var index = ctrl.getIndex(v2);\r
9951                         scope.searchCriteria = {};\r
9952                         if (index !== null) {\r
9953                             scope.searchCriteria[index] = v1;\r
9954                         }\r
9955                     } else if (searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")) {\r
9956                         scope.searchCriteria = {\r
9957                             $: v1\r
9958                         };\r
9959                     } else {\r
9960                         scope.searchCriteria = {};\r
9961                     }\r
9962                 };\r
9963                 scope.$watch('searchCategory', function (newVal, oldVal) {\r
9964                     if (newVal !== oldVal) {\r
9965                         setSearchCriteria(scope.searchString, newVal);\r
9966                     }\r
9967                 });\r
9968                 scope.$watch('searchString', function (newVal, oldVal) {\r
9969                     if (newVal !== oldVal) {\r
9970                         setSearchCriteria(newVal, scope.searchCategory);\r
9971                     }\r
9972                 });\r
9973                 scope.$watchCollection('searchCriteria', function (val) {\r
9974                     if (scope.$parent && scope.$parent !== undefined) {\r
9975                         scope.$parent.searchCriteria = val;\r
9976                     }\r
9977                     scope.totalRows = scope.tableData && ($filter('filter')(scope.tableData, val, false)).length || 0;\r
9978                     scope.currentPage = 1;\r
9979                 });\r
9980                 var window = angular.element($window);\r
9981                 var findMaxTableColumns = function () {\r
9982                     var windowWidth;\r
9983                     windowWidth = $window.innerWidth;\r
9984                     ctrl.maxTableColumns = -1;\r
9985                     for (var i in scope.tableBreakpoints) {\r
9986                         if (windowWidth >= scope.tableBreakpoints[i].min && windowWidth < scope.tableBreakpoints[i].max) {\r
9987                             ctrl.maxTableColumns = scope.tableBreakpoints[i].columns;\r
9988                             break;\r
9989                         }\r
9990                     }\r
9991                     if (ctrl.maxTableColumns > -1 && ctrl.totalTableColums > ctrl.maxTableColumns) {\r
9992                         ctrl.active = true;\r
9993                     } else {\r
9994                         ctrl.active = false;\r
9995                     }\r
9996                     for (var i in ctrl.responsiveRowScopes) {\r
9997                         ctrl.responsiveRowScopes[i].setActive(ctrl.active);\r
9998                     }\r
9999                 };\r
10000                 var findHiddenColumn = function () {\r
10001                     var columnDiffenence = ctrl.maxTableColumns > -1 ? ctrl.totalTableColums - ctrl.maxTableColumns : 0;\r
10002                     ctrl.hiddenColumn = [];\r
10003                     if (columnDiffenence > 0) {\r
10004                         var tempHideColumnPriority = angular.copy(ctrl.hideColumnPriority);\r
10005                         for (var i = 0; i < columnDiffenence; i++) {\r
10006                             ctrl.hiddenColumn.push(tempHideColumnPriority.pop());\r
10007                         }\r
10008                     }\r
10009                 };\r
10010                 var resizeListener = function () {\r
10011                     findMaxTableColumns();\r
10012                     findHiddenColumn();\r
10013                 };\r
10014                 if (ctrl.responsive) {\r
10015                     window.bind('resize', function () {\r
10016                         resizeListener();\r
10017                         scope.$apply();\r
10018                     });\r
10019                     $timeout(function () {\r
10020                         resizeListener();\r
10021                     }, 100);\r
10022                 }\r
10023             }\r
10024         };\r
10025     }])\r
10026     .directive('b2bTableRow', [function () {\r
10027         return {\r
10028             restrict: 'EA',\r
10029             compile: function (elem, attr) {\r
10030                 if (attr.type === 'header') {\r
10031                     angular.noop();\r
10032                 } else if (attr.type === 'body') {\r
10033                     var html = elem.children();\r
10034                     if (attr.rowRepeat) {\r
10035                         html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false "));\r
10036                     }\r
10037                     html.attr('ng-class', "{'odd': $odd && zebraStripFlag}");\r
10038                     html.attr('class', 'data-row');\r
10039                     html.attr('b2b-responsive-row', '{{$index}}');\r
10040                     elem.append(html);\r
10041                 }\r
10042             }\r
10043         };\r
10044     }])\r
10045     .directive('b2bTableHeader', ['b2bTableConfig', function (b2bTableConfig) {\r
10046         return {\r
10047             restrict: 'EA',\r
10048             replace: true,\r
10049             transclude: true,\r
10050             scope: {\r
10051                 sortable: '@',\r
10052                 defaultSort: '@',\r
10053                 index: '@key'\r
10054             },\r
10055             require: '^b2bTable',\r
10056             templateUrl: function (elem, attr) {\r
10057                 if (attr.sortable === 'false') {\r
10058                     return 'b2bTemplate/tables/b2bTableHeaderUnsortable.html';\r
10059                 } else {\r
10060                     return 'b2bTemplate/tables/b2bTableHeaderSortable.html';\r
10061                 }\r
10062             },\r
10063             link: function (scope, elem, attr, ctrl) {\r
10064                 var reverse = b2bTableConfig.defaultSortPattern;\r
10065                 scope.headerName = elem.text();\r
10066                 scope.headerId = elem.attr('id');\r
10067                 scope.sortPattern = null;\r
10068                 var priority = parseInt(attr.priority, 10);\r
10069                 scope.columnIndex = ctrl.setIndex(scope, priority);\r
10070 \r
10071                 scope.isHidden = function () {\r
10072                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);\r
10073                 };\r
10074 \r
10075                 scope.$watch(function () {\r
10076                     return elem.text();\r
10077                 }, function (value) {\r
10078                     scope.headerName = value;\r
10079                 });\r
10080                 scope.sort = function (sortType) {\r
10081                     if (typeof sortType === 'boolean') {\r
10082                         reverse = sortType;\r
10083                     }\r
10084                     ctrl.sortData(scope.index, reverse, false);\r
10085                     scope.sortPattern = reverse ? 'descending' : 'ascending';\r
10086                     reverse = !reverse;\r
10087                 };\r
10088                 scope.$watch(function () {\r
10089                     return ctrl.currentSortIndex;\r
10090                 }, function (value) {\r
10091                     if (value !== scope.index) {\r
10092                         scope.sortPattern = null;\r
10093                     }\r
10094                 });\r
10095 \r
10096                 if (scope.sortable === undefined || scope.sortable === 'true' || scope.sortable === true) {\r
10097                     scope.sortable = 'true';\r
10098                 } else if (scope.sortable === false || scope.sortable === 'false') {\r
10099                     scope.sortable = 'false';\r
10100                 }\r
10101 \r
10102                 if (scope.sortable !== 'false') {\r
10103                     if (scope.defaultSort === 'A' || scope.defaultSort === 'a') {\r
10104                         scope.sort(false);\r
10105                     } else if (scope.defaultSort === 'D' || scope.defaultSort === 'd') {\r
10106                         scope.sort(true);\r
10107                     }\r
10108                 }\r
10109                 scope.resetSortPattern = function () {\r
10110                     reverse = b2bTableConfig.defaultSortPattern;\r
10111                 };\r
10112             }\r
10113         };\r
10114     }])\r
10115     .directive('b2bResponsiveRow', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {\r
10116         return {\r
10117             restrict: 'EA',\r
10118             require: '^b2bTable',\r
10119             controller: ['$scope', function ($scope) {\r
10120                 this.rowValues = $scope.rowValues = [];\r
10121                 this.setRowValues = function (rowValue) {\r
10122                     this.rowValues.push(rowValue);\r
10123                 };\r
10124                 var columnIndexCounter = -1;\r
10125                 this.getIndex = function () {\r
10126                     columnIndexCounter++;\r
10127                     return columnIndexCounter;\r
10128                 };\r
10129             }],\r
10130             link: function (scope, elem, attr, ctrl) {\r
10131                 if (ctrl.responsive) {\r
10132                     scope.rowIndex = attr.b2bResponsiveRow;\r
10133                     scope.active = false;\r
10134                     scope.expandFlag = false;\r
10135                     scope.headerValues = ctrl.headers;\r
10136                     ctrl.setResponsiveRow(scope);\r
10137                     var firstTd = elem.find('td').eq(0);\r
10138                     scope.setActive = function (activeFlag) {\r
10139                         scope.active = activeFlag;\r
10140                         if (scope.active) {\r
10141                             elem.addClass('has-button');\r
10142                             firstTd.attr('role', 'rowheader');\r
10143                             firstTd.parent().attr('role', 'row');\r
10144                         } else {\r
10145                             elem.removeClass('has-button');\r
10146                             firstTd.removeAttr('role');\r
10147                             firstTd.parent().removeAttr('role');\r
10148                         }\r
10149                     };\r
10150                     scope.toggleExpandFlag = function (expandFlag) {\r
10151                         if (angular.isDefined(expandFlag)) {\r
10152                             scope.expandFlag = expandFlag;\r
10153                         } else {\r
10154                             scope.expandFlag = !scope.expandFlag;\r
10155                         }\r
10156                         if (scope.expandFlag) {\r
10157                             elem.addClass('opened');\r
10158                         } else {\r
10159                             elem.removeClass('opened');\r
10160                         }\r
10161                     };\r
10162 \r
10163                     firstTd.attr('scope', 'row');\r
10164                     firstTd.addClass('col-1');\r
10165                     scope.$on('$destroy', function () {\r
10166                         elem.next().remove();\r
10167                     });\r
10168                     $timeout(function () {\r
10169                         scope.firstTdId = firstTd.attr('id');\r
10170                         var firstTdContent = firstTd.html();\r
10171                         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
10172                         toggleButtonTemplate = $compile(toggleButtonTemplate)(scope);\r
10173                         firstTd.html('');\r
10174                         firstTd.prepend(toggleButtonTemplate);\r
10175 \r
10176                         var template = $templateCache.get('b2bTemplate/tables/b2bResponsiveRow.html');\r
10177                         template = $compile(template)(scope);\r
10178                         elem.after(template);\r
10179                     }, 100);\r
10180                 }\r
10181             }\r
10182         };\r
10183     }])\r
10184     .directive('b2bResponsiveList', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {\r
10185         return {\r
10186             restrict: 'EA',\r
10187             require: '^b2bTable',\r
10188             link: function (scope, elem, attr, ctrl) {\r
10189                 scope.columnIndex = parseInt(attr.b2bResponsiveList, 10);\r
10190                 scope.isVisible = function () {\r
10191                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);\r
10192                 };\r
10193             }\r
10194         };\r
10195     }])\r
10196     .directive('b2bTableBody', ['$filter', '$timeout', 'b2bTableConfig', function ($filter, $timeout, b2bTableConfig) {\r
10197         return {\r
10198             restrict: 'EA',\r
10199             require: ['^b2bTable', '?^b2bResponsiveRow'],\r
10200             scope: true,\r
10201             replace: true,\r
10202             transclude: true,\r
10203             templateUrl: 'b2bTemplate/tables/b2bTableBody.html',\r
10204             link: function (scope, elem, attr, ctrl) {\r
10205                 var b2bTableCtrl = ctrl[0];\r
10206                 var b2bResponsiveRowCtrl = ctrl[1];\r
10207                 var highlightSearchStringClass = b2bTableConfig.highlightSearchStringClass;\r
10208                 var searchString = "";\r
10209                 var wrapElement = function (elem) {\r
10210                     var text = elem.text();\r
10211                     elem.html($filter('b2bHighlight')(text, searchString, highlightSearchStringClass));\r
10212                 };\r
10213                 var traverse = function (elem) {\r
10214                     var innerHtml = elem.children();\r
10215                     if (innerHtml.length > 0) {\r
10216                         for (var i = 0; i < innerHtml.length; i++) {\r
10217                             traverse(innerHtml.eq(i));\r
10218                         }\r
10219                     } else {\r
10220                         wrapElement(elem);\r
10221                         return;\r
10222                     }\r
10223                 };\r
10224                 var clearWrap = function (elem) {\r
10225                     var elems = elem.find('*');\r
10226                     for (var i = 0; i < elems.length; i++) {\r
10227                         if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {\r
10228                             var text = elems.eq(i).text();\r
10229                             elems.eq(i).replaceWith(text);\r
10230                         }\r
10231                     }\r
10232                 };\r
10233                 if (b2bResponsiveRowCtrl) {\r
10234                     scope.columnIndex = b2bResponsiveRowCtrl.getIndex();\r
10235                     scope.isHidden = function () {\r
10236                         return (b2bTableCtrl.hiddenColumn.indexOf(scope.columnIndex) > -1);\r
10237                     };\r
10238                 }\r
10239                 $timeout(function () {\r
10240                     var actualHtml = elem.children();\r
10241                     scope.$watch(function () {\r
10242                         return b2bTableCtrl.getSearchString();\r
10243                     }, function (val) {\r
10244                         searchString = val;\r
10245                         clearWrap(elem);\r
10246                         if (actualHtml.length > 0) {\r
10247                             traverse(elem);\r
10248                         } else {\r
10249                             wrapElement(elem);\r
10250                         }\r
10251                     });\r
10252                     if (b2bResponsiveRowCtrl) {\r
10253                         b2bResponsiveRowCtrl.setRowValues(elem.html());\r
10254                     }\r
10255                 }, 50);\r
10256             }\r
10257         };\r
10258     }])\r
10259     .directive('b2bTableSort', ['b2bTableConfig','$timeout', function (b2bTableConfig,$timeout) {\r
10260         return {\r
10261             restrict: 'EA',\r
10262             replace: true,\r
10263             require: '^b2bTable',\r
10264             link: function (scope, elem, attr, ctrl) {\r
10265                 var initialSort = '',\r
10266                     nextSort = '',\r
10267                     tempsort = '';\r
10268                 initialSort = attr.initialSort;\r
10269 \r
10270                 scope.sortTable = function (msg) {\r
10271                     $timeout(function(){\r
10272                         if (nextSort.length > 0) {\r
10273 \r
10274                         if (nextSort === 'd' || nextSort === 'D') {\r
10275                             tempsort = nextSort\r
10276                             ctrl.sortData(msg, true, true);\r
10277                             nextSort = 'a';\r
10278                              $timeout(function(){\r
10279                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10280                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10281                                 }   \r
10282                             },100);\r
10283                             \r
10284                         } else {\r
10285                             tempsort = nextSort\r
10286                             ctrl.sortData(msg, false, true);\r
10287                             nextSort = 'd';\r
10288                              $timeout(function(){\r
10289                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10290                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10291                                 }   \r
10292                             },100);\r
10293                         }\r
10294                     } else if (initialSort.length > 0) {\r
10295 \r
10296                         if (initialSort === 'd' || initialSort === 'D') {\r
10297                             tempsort = nextSort\r
10298                             ctrl.sortData(msg, true, true);\r
10299                             nextSort = 'a';\r
10300                             $timeout(function(){\r
10301                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10302                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10303                                 }   \r
10304                             },100);\r
10305                              \r
10306                         } else {\r
10307                             tempsort = nextSort\r
10308                             ctrl.sortData(msg, false, true);\r
10309                             nextSort = 'd';\r
10310                              $timeout(function(){\r
10311                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){\r
10312                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();\r
10313                                 }   \r
10314                             },100);\r
10315 \r
10316                              \r
10317                         }\r
10318                     }\r
10319                     },10)\r
10320 \r
10321                 };\r
10322 \r
10323                 scope.sortDropdown = function(msg) {\r
10324 \r
10325                     if(tempsort==='') {\r
10326 \r
10327                         tempsort='a'\r
10328                     }\r
10329                     if(tempsort === 'd' || tempsort === 'D' ) {\r
10330                         ctrl.sortData(msg, true, false);       \r
10331                     } else {\r
10332                        ctrl.sortData(msg, false, false);\r
10333                     }\r
10334 \r
10335                 };\r
10336             }\r
10337         };\r
10338     }]);\r
10339 /**\r
10340  * @ngdoc directive\r
10341  * @name Tabs, tables & accordions.att:tabs\r
10342  *\r
10343  * @description\r
10344  *  <file src="src/tabs/docs/readme.md" />\r
10345  *\r
10346  * @usage\r
10347  *  <b2b-tabset tab-id-selected="activeTabsId">\r
10348         <b2b-tab ng-repeat="tab in gTabs" tab-item="tab" \r
10349                  id="{{tab.uniqueId}}" aria-controls="{{tab.tabPanelId}}"\r
10350                  ng-disabled="tab.disabled">\r
10351             {{tab.title}}\r
10352         </b2b-tab>\r
10353     </b2b-tabset>\r
10354  *\r
10355  * @example\r
10356  *  <section id="code">\r
10357         <example module="b2b.att">\r
10358             <file src="src/tabs/docs/demo.html" />\r
10359             <file src="src/tabs/docs/demo.js" />\r
10360         </example>\r
10361     </section>\r
10362  *\r
10363  */\r
10364 \r
10365 angular.module('b2b.att.tabs', ['b2b.att.utilities'])\r
10366     .directive('b2bTabset', function () {\r
10367         return {\r
10368             restrict: 'EA',\r
10369             transclude: true,\r
10370             replace: true,\r
10371             scope: {\r
10372                 tabIdSelected: '='\r
10373             },\r
10374             templateUrl: 'b2bTemplate/tabs/b2bTabset.html',\r
10375             controller: ['$scope', function ($scope) {\r
10376 \r
10377                 this.setTabIdSelected = function (tab) {\r
10378                     $scope.tabIdSelected = tab.id;\r
10379                 };\r
10380 \r
10381                 this.getTabIdSelected = function () {\r
10382                     return $scope.tabIdSelected;\r
10383                 };\r
10384             }]\r
10385         };\r
10386     })\r
10387     .directive('b2bTab', ['keymap', function (keymap) {\r
10388         return {\r
10389             restrict: 'EA',\r
10390             transclude: true,\r
10391             replace: true,\r
10392             require: '^b2bTabset',\r
10393             scope: {\r
10394                 tabItem: "="\r
10395             },\r
10396             templateUrl: 'b2bTemplate/tabs/b2bTab.html',\r
10397             controller: [function(){}],\r
10398             link: function (scope, element, attr, b2bTabsetCtrl) {\r
10399 \r
10400                 if (scope.tabItem && !scope.tabItem.disabled) {\r
10401                     scope.tabItem.disabled = false;\r
10402                 }\r
10403 \r
10404                 scope.isTabActive = function () {\r
10405                     return (scope.tabItem.id === b2bTabsetCtrl.getTabIdSelected());\r
10406                 };\r
10407 \r
10408                 scope.clickTab = function () {\r
10409                     if (attr.disabled) {\r
10410                         return;\r
10411                     }\r
10412                     b2bTabsetCtrl.setTabIdSelected(scope.tabItem);\r
10413                 };\r
10414 \r
10415                 scope.nextKey = function () {\r
10416                     var el = angular.element(element[0])[0];\r
10417                     var elementToFocus = null;\r
10418                     while (el && el.nextElementSibling) {\r
10419                         el = el.nextElementSibling;\r
10420                         if (!el.querySelector('a').disabled) {\r
10421                             elementToFocus = el.querySelector('a');\r
10422                             break;\r
10423                         }\r
10424                     }\r
10425 \r
10426                     if (!elementToFocus) {\r
10427                         var childTabs = element.parent().children();\r
10428                         for (var i = 0; i < childTabs.length; i++) {\r
10429                             if (!childTabs[i].querySelector('a').disabled) {\r
10430                                 elementToFocus = childTabs[i].querySelector('a');\r
10431                                 break;\r
10432                             }\r
10433                         }\r
10434                     }\r
10435 \r
10436                     if (elementToFocus) {\r
10437                         elementToFocus.focus();\r
10438                     }\r
10439                 };\r
10440 \r
10441                 scope.previousKey = function () {\r
10442                     var el = angular.element(element[0])[0];\r
10443                     var elementToFocus = null;\r
10444 \r
10445                     while (el && el.previousElementSibling) {\r
10446                         el = el.previousElementSibling;\r
10447                         if (!el.querySelector('a').disabled) {\r
10448                             elementToFocus = el.querySelector('a');\r
10449                             break;\r
10450                         }\r
10451                     }\r
10452 \r
10453                     if (!elementToFocus) {\r
10454                         var childTabs = element.parent().children();\r
10455                         for (var i = childTabs.length - 1; i > 0; i--) {\r
10456                             if (!childTabs[i].querySelector('a').disabled) {\r
10457                                 elementToFocus = childTabs[i].querySelector('a');\r
10458                                 break;\r
10459                             }\r
10460                         }\r
10461                     }\r
10462 \r
10463                     if (elementToFocus) {\r
10464                         elementToFocus.focus();\r
10465                     }\r
10466                 };\r
10467 \r
10468                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {\r
10469 \r
10470                     if (!(evt.keyCode)) {\r
10471                         evt.keyCode = evt.which;\r
10472                     }\r
10473 \r
10474                     switch (evt.keyCode) {\r
10475                         case keymap.KEY.RIGHT:\r
10476                             evt.preventDefault();\r
10477                             scope.nextKey();\r
10478                             break;\r
10479 \r
10480                         case keymap.KEY.LEFT:\r
10481                             evt.preventDefault();\r
10482                             scope.previousKey();\r
10483                             break;\r
10484 \r
10485                         default:;\r
10486                     }\r
10487                 });\r
10488             }\r
10489         };\r
10490     }]);\r
10491 /**\r
10492  * @ngdoc directive\r
10493  * @name Messages, modals & alerts.att:tagBadges\r
10494  *\r
10495  * @description\r
10496  *  <file src="src/tagBadges/docs/readme.md" />\r
10497  *\r
10498  * @example\r
10499  *  <section id="code">\r
10500         <example module="b2b.att">\r
10501             <file src="src/tagBadges/docs/demo.html" />\r
10502             <file src="src/tagBadges/docs/demo.js" />\r
10503         </example>\r
10504     </section>\r
10505  *\r
10506  */\r
10507 angular.module('b2b.att.tagBadges', ['b2b.att.utilities'])\r
10508         .directive('b2bTagBadge',['$timeout',function($timeout){\r
10509             return{\r
10510                 restrict: 'EA',\r
10511                 link: function(scope,elem,attr,ctrl){\r
10512                     elem.addClass('b2b-tags');\r
10513                     if(angular.element(elem[0].querySelector('.icon-primary-close')).length>0) {\r
10514                         var item = angular.element(elem[0].querySelector('.icon-primary-close'));\r
10515                         item.bind('click',function(){\r
10516                         elem.css({'height':'0','width':'0','padding':'0','border':'0'});\r
10517                         elem.attr('tabindex','0');\r
10518                         elem[0].focus();\r
10519                         item.parent().remove();\r
10520                         elem[0].bind('blur',function(){\r
10521                             elem[0].remove();\r
10522                         });\r
10523                     });  \r
10524                     }\r
10525                   \r
10526 \r
10527 \r
10528 \r
10529                 }\r
10530             };   \r
10531 }]);\r
10532 /**\r
10533  * @ngdoc directive\r
10534  * @name Forms.att:textArea\r
10535  *\r
10536  * @description\r
10537  *  <file src="src/textArea/docs/readme.md" />\r
10538  *\r
10539  * @usage\r
10540  *  <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
10541  *\r
10542  * @example\r
10543     <section id="code">\r
10544         <b>HTML + AngularJS</b>\r
10545         <example module="b2b.att">\r
10546             <file src="src/textArea/docs/demo.html" />\r
10547             <file src="src/textArea/docs/demo.js" />\r
10548         </example>\r
10549     </section>\r
10550  */\r
10551 angular.module('b2b.att.textArea', ['b2b.att.utilities'])\r
10552 \r
10553 .directive('b2bResetTextarea', [ function () {\r
10554     return {\r
10555         restrict: 'A',\r
10556         require: 'b2bReset',\r
10557         link: function (scope, element, attrs, ctrl) {\r
10558 \r
10559             var resetButton = ctrl.getResetButton();\r
10560             \r
10561             var computeScrollbarAndAddClass = function () {\r
10562                 if (element.prop('scrollHeight') > element[0].clientHeight) {\r
10563                     element.addClass('hasScrollbar');\r
10564                 } else {\r
10565                     element.removeClass('hasScrollbar');\r
10566                 }\r
10567             };\r
10568             \r
10569             computeScrollbarAndAddClass();\r
10570 \r
10571             element.on('focus keyup', function(){\r
10572                 computeScrollbarAndAddClass();\r
10573             });\r
10574         }\r
10575     };\r
10576 }]);\r
10577 \r
10578 /**\r
10579  * @ngdoc directive\r
10580  * @name Forms.att:tooltipsForForms\r
10581  *\r
10582  * @description\r
10583  *  <file src="src/tooltipsForForms/docs/readme.md" />\r
10584  *\r
10585  * @example\r
10586  <example module="b2b.att">\r
10587  <file src="src/tooltipsForForms/docs/demo.html" />\r
10588  <file src="src/tooltipsForForms/docs/demo.js" />\r
10589  </example>\r
10590  */\r
10591 angular.module('b2b.att.tooltipsForForms', ['b2b.att.utilities'])\r
10592         .directive('b2bTooltip', ['$document', '$window', '$isElement', function ($document, $window, $isElement) {\r
10593                 return  {\r
10594                     restrict: 'A',\r
10595                     link: function (scope, elem, attr, ctrl) {\r
10596                         var icon = elem[0].querySelector('a.tooltip-element');\r
10597                         var btnIcon = elem[0].querySelector('.btn.tooltip-element');\r
10598                         var tooltipText = elem[0].querySelector('.helpertext');\r
10599                         var tooltipWrapper = elem[0].querySelector('.tooltip-size-control');\r
10600                         if (elem.hasClass('tooltip-onfocus')) {\r
10601                             var inputElm = angular.element(elem[0].querySelector("input"));\r
10602                             var textAreaElm = angular.element(elem[0].querySelector("textarea"));\r
10603                         }\r
10604                         angular.element(icon).attr({'aria-expanded': false});\r
10605                         angular.element(btnIcon).attr({'aria-expanded': false});\r
10606                         var calcTooltip = function () {\r
10607                             if (!elem.hasClass('tooltip active')) {\r
10608                                 if (elem.hasClass('tooltip-onfocus')) {\r
10609                                     angular.element(elem[0].querySelector("input")).triggerHandler('focusout');\r
10610                                 }\r
10611                                 if (elem.hasClass('tooltip-onclick')) {\r
10612                                     return false;\r
10613                                 }\r
10614                                 angular.element(icon).removeClass('active');\r
10615                                 angular.element(icon).attr({'aria-expanded': true});\r
10616                                 angular.element(icon).attr({'aria-describedby': angular.element(tooltipText).attr('id')});\r
10617                                 angular.element(tooltipText).attr({'aria-hidden': false});\r
10618                                 elem.addClass('active');\r
10619 \r
10620                                 var tooltipIconPos = angular.element(icon).prop('offsetLeft'),\r
10621                                         tooltipPosition = angular.element(tooltipText).prop('offsetWidth') / 2,\r
10622                                         tipOffset = (tooltipIconPos - 30) - tooltipPosition,\r
10623                                         maxRightPos = (($window.innerWidth - 72) - (tooltipPosition * 2)) - 14.5;\r
10624 \r
10625                                 if ($window.innerWidth >= '768') {\r
10626                                     if (tipOffset < 0) {// if icon on far left side of page\r
10627                                         tipOffset = 15;\r
10628                                     }\r
10629                                     else if (tooltipIconPos > maxRightPos) {// if icon is far right side of page\r
10630                                         tipOffset = maxRightPos;\r
10631                                     }\r
10632                                     else {// if tooltip in the middle somewhere\r
10633                                         tipOffset = tipOffset;\r
10634                                     }\r
10635                                     angular.element(tooltipWrapper).css({left: tipOffset + 'px'});\r
10636                                 }\r
10637                             }\r
10638                         };\r
10639                         \r
10640                         // TOOLTIP LINK ONCLICK AND FOCUS\r
10641                         angular.element(icon).on('click mouseover mouseout focus blur', function (e) {\r
10642                             if (e.type == 'mouseover') {\r
10643                                 calcTooltip();\r
10644                             }\r
10645                             else if (e.type == 'mouseout' && elem.hasClass('active')) {\r
10646                                 if (!elem.hasClass('activeClick')) {\r
10647                                     angular.element(tooltipText).attr({\r
10648                                         'aria-hidden': true,\r
10649                                         'tabindex': '-1'\r
10650                                     });\r
10651                                     elem.removeClass('active');\r
10652                                 } else if (elem.hasClass('activeClick') && navigator.userAgent.match(/iphone/i)) {\r
10653                                     elem.removeClass('active activeClick');\r
10654                                 }\r
10655                             }\r
10656 \r
10657                             else {\r
10658                                 if (elem.hasClass('activeClick')) {\r
10659                                     angular.element(icon).attr({'aria-expanded': false});\r
10660                                     angular.element(tooltipText).attr({'aria-hidden': true});\r
10661                                     angular.element(icon).removeAttr('aria-describedby');\r
10662                                     elem.removeClass('activeClick active');\r
10663                                     e.preventDefault();\r
10664                                 }\r
10665                                 else if (e.type == 'click') {\r
10666                                     elem.addClass('activeClick');\r
10667                                     calcTooltip();\r
10668                                     e.preventDefault();\r
10669                                 }\r
10670                                 else {\r
10671                                     angular.element(icon).on('keydown', function (e) {\r
10672                                         if (e.keyCode == '32') {\r
10673                                             (elem.hasClass('active')) ? elem.removeClass('active') : elem.addClass('value');\r
10674                                             angular.element(icon).triggerHandler('click');\r
10675                                             e.preventDefault();\r
10676                                         } else if (e.keyCode == '27') {\r
10677                                             (elem.hasClass('active')) ? elem.removeClass('active activeClick') : elem.addClass('value');\r
10678                                         }\r
10679                                     });\r
10680                                     e.preventDefault();\r
10681                                 }\r
10682                             }\r
10683                             e.preventDefault();\r
10684                         });\r
10685 \r
10686                         // TOOLTIP BUTTON INSIDE A TEXT FIELD\r
10687                         angular.element(btnIcon).on('click', function (e) {\r
10688                             var $this = angular.element(this);\r
10689                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {\r
10690                                 elem.removeClass('active');\r
10691                                 $this.removeClass('active');\r
10692                                 angular.element(tooltipText).removeAttr('aria-live');\r
10693                                 $this.attr({'aria-expanded': 'false'});\r
10694                                 $this.removeAttr('aria-describedby');\r
10695                             } else {\r
10696                                 elem.addClass('active');\r
10697                                 $this.addClass('active');\r
10698                                 $this.attr({'aria-expanded': 'true', 'aria-describedby': angular.element(tooltipText).attr('id')});\r
10699                                 angular.element(tooltipText).attr({'aria-live': 'polite'});\r
10700                             }\r
10701                         });\r
10702 \r
10703                         angular.element(btnIcon).on('blur', function (e) {\r
10704                             var $this = angular.element(this);\r
10705                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {\r
10706                                 elem.removeClass('active');\r
10707                                 $this.removeClass('active');\r
10708                                 angular.element(tooltipText).removeAttr('aria-live');\r
10709                                 $this.attr({'aria-expanded': 'false'});\r
10710                                 $this.removeAttr('aria-describedby');\r
10711                             }\r
10712                         });  \r
10713 \r
10714                         angular.element(btnIcon).on('keydown', function (e) {\r
10715                             var $this = angular.element(this);\r
10716                             if (e.keyCode == '27') {\r
10717                                 var $this = angular.element(this);\r
10718                                 if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {\r
10719                                     elem.removeClass('active');\r
10720                                     $this.removeClass('active');\r
10721                                     angular.element(tooltipText).removeAttr('aria-live');\r
10722                                     $this.attr({'aria-expanded': 'false'});\r
10723                                     $this.removeAttr('aria-describedby');\r
10724                                 }\r
10725                             }\r
10726                         });\r
10727 \r
10728                         // close all tooltips if clicking something else\r
10729                         $document.bind('click', function (e) {\r
10730                             var isElement = $isElement(angular.element(e.target), elem, $document);\r
10731                             if (!isElement) {\r
10732                                 elem.removeClass('active');\r
10733                                 angular.element(elem[0].querySelector('.tooltip-element')).removeClass('active');\r
10734                                 angular.element(tooltipText).removeAttr('aria-live');\r
10735                                 angular.element(elem[0].querySelector('.tooltip-element')).attr({'aria-expanded': 'false'});\r
10736                                 angular.element(elem[0].querySelector('.tooltip-element')).removeAttr('aria-describedby');\r
10737                             };\r
10738                         });\r
10739 \r
10740                         angular.element(inputElm).on('keydown', function (e) {\r
10741                             if (e.keyCode == '27'){\r
10742                                 elem.removeClass('active');\r
10743                                 angular.element(tooltipText).css('display', 'none');\r
10744                                 angular.element(tooltipText).removeAttr('aria-live');\r
10745 \r
10746                                 if (angular.element(this).attr('aria-describedby') === undefined){\r
10747 \r
10748                                 }\r
10749 \r
10750                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){\r
10751 \r
10752                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);\r
10753 \r
10754                                     angular.element(this).attr('aria-describedby', describedByValue);\r
10755 \r
10756                                 }\r
10757                                 else {\r
10758                                     angular.element(this).removeAttr('aria-describedby');\r
10759                                 }\r
10760                             }\r
10761                         });\r
10762 \r
10763                         angular.element(textAreaElm).on('keydown', function (e) {\r
10764                             if (e.keyCode == '27'){\r
10765                                 elem.removeClass('active');\r
10766                                 angular.element(tooltipText).css('display', 'none');\r
10767                                 angular.element(tooltipText).removeAttr('aria-live');\r
10768                                 if (angular.element(this).attr('aria-describedby') === undefined){\r
10769 \r
10770                                 }\r
10771 \r
10772                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){\r
10773 \r
10774                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);\r
10775 \r
10776                                     angular.element(this).attr('aria-describedby', describedByValue);\r
10777 \r
10778                                 }\r
10779                                 else {\r
10780                                     angular.element(this).removeAttr('aria-describedby');\r
10781                                 }\r
10782                             }\r
10783                         });\r
10784 \r
10785                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXT FIELD\r
10786                         angular.element(inputElm).on('focus', function (e) {\r
10787                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');\r
10788                             for (var i = 0; i < allTooltip.length; i++) {\r
10789                                 if (angular.element(allTooltip[i]).hasClass('active')) {\r
10790                                     angular.element(allTooltip[i]).triggerHandler('click');\r
10791                                 }\r
10792                             };\r
10793                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});\r
10794                             angular.element(tooltipText).css('display', 'block');\r
10795                             angular.element(tooltipText).attr({'aria-live': 'polite'});\r
10796                             elem.addClass('active');\r
10797                         });\r
10798                         angular.element(inputElm).on('blur', function (e) {\r
10799                             elem.removeClass('active');\r
10800                             angular.element(tooltipText).css('display', 'none');\r
10801                             angular.element(tooltipText).removeAttr('aria-live');\r
10802                             angular.element(this).removeAttr('aria-describedby');\r
10803                         });\r
10804 \r
10805                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXTAREA\r
10806                         angular.element(textAreaElm).on('focus', function (e) {\r
10807                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');\r
10808                             for (var i = 0; i < allTooltip.length; i++) {\r
10809                                 if (angular.element(allTooltip[i]).hasClass('active')) {\r
10810                                     angular.element(allTooltip[i]).triggerHandler('click');\r
10811                                 }\r
10812                             };\r
10813                             elem.addClass('active');\r
10814                             angular.element(tooltipText).css('display', 'block');\r
10815                             angular.element(tooltipText).attr({'aria-live': 'polite'});\r
10816                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});\r
10817                         });\r
10818                         angular.element(textAreaElm).on('blur', function (e) {\r
10819                             elem.removeClass('active');\r
10820                             angular.element(tooltipText).css('display', 'none');\r
10821                             angular.element(tooltipText).removeAttr('aria-live');\r
10822                             angular.element(this).removeAttr('aria-describedby');\r
10823                         });\r
10824                     }\r
10825                 };\r
10826             }]); \r
10827 /**\r
10828  * @ngdoc directive\r
10829  * @name Navigation.att:TreeNavigation\r
10830  *\r
10831  *\r
10832  * @scope\r
10833  * @param {String} setRole - This value needs to be "tree". This is required to incorporate CATO requirements.\r
10834  * @param {Boolean} groupIt - This value needs to be "false" for top-level tree rendered.\r
10835  *\r
10836  * @description\r
10837  *  <file src="src/treeNav/docs/readme.md" />\r
10838  *\r
10839  * @usage\r
10840  *      <div class="b2b-tree">\r
10841  *                <b2b-tree-nav collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-nav>\r
10842  *            </div>\r
10843  * @example\r
10844  *  <section id="code">\r
10845         <example module="b2b.att">\r
10846             <file src="src/treeNav/docs/demo.html" />\r
10847             <file src="src/treeNav/docs/demo.js" />\r
10848        </example>\r
10849     </section>\r
10850  *\r
10851  */\r
10852 angular.module('b2b.att.treeNav', ['b2b.att.utilities'])\r
10853     .directive('b2bTreeNav', function () {\r
10854         return {\r
10855             restrict: "E",\r
10856             replace: true,\r
10857             scope: {\r
10858                 collection: '=',\r
10859                 groupIt: '=',\r
10860                 setRole: '@'\r
10861             },\r
10862             templateUrl: function (element, attrs) {\r
10863                 if (attrs.groupIt === 'true') {\r
10864                     return "b2bTemplate/treeNav/groupedTree.html";\r
10865                 } else {\r
10866                     return "b2bTemplate/treeNav/ungroupedTree.html";\r
10867                 }\r
10868             },\r
10869             link: function (scope) {               \r
10870                 if (!(scope.setRole === 'tree')) {\r
10871                     scope.setRole = 'group';\r
10872                 }             \r
10873             }\r
10874         }\r
10875     })\r
10876     .directive('b2bMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {\r
10877         return {\r
10878             restrict: "E",\r
10879             replace: true,\r
10880             scope: {\r
10881                 member: '=',\r
10882                 groupIt: '='\r
10883             },\r
10884             templateUrl: 'b2bTemplate/treeNav/treeMember.html',\r
10885             link: function (scope, element, attrs) {\r
10886                 scope.elemArr = [];\r
10887                 var removeRootTabIndex = function (elem) {\r
10888                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {\r
10889                         elem.attr('tabindex', -1);                        \r
10890                         return;\r
10891                     }\r
10892                     removeRootTabIndex(elem.parent());\r
10893                 };\r
10894                 scope.$watch('member.child', function(newVal, oldVal){                  \r
10895                     if(newVal !== oldVal){\r
10896                         scope.showChild();\r
10897                     };\r
10898                 });\r
10899                 scope.showChild = function () {\r
10900                         if (!element.hasClass('grouped')) {\r
10901                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {\r
10902                                 scope.groupIt = false;\r
10903                                 element.addClass('grouped');\r
10904                                 element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");\r
10905                                 $compile(element.contents())(scope);\r
10906                                 if(scope.member.active && scope.member.active === true){\r
10907                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
10908                                 };\r
10909                                 if(scope.member.selected && scope.member.selected === true){\r
10910                                     element.attr('aria-selected', true);\r
10911                                     element.attr('tabindex', 0);\r
10912                                     removeRootTabIndex(element);\r
10913                                 };\r
10914                                 if(scope.member.active && scope.member.active == undefined){\r
10915                                     element.find('i').eq(0).addClass('icon-primary-collapsed');\r
10916                                 };\r
10917                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {\r
10918                                 element.addClass('grouped');\r
10919                                 scope.groupIt = true;\r
10920                                 // FILTER - GROUPBY - APPROACH \r
10921                                 var j = 0;\r
10922                                 var grpName = '';\r
10923                                 if(scope.member.child[0].groupName !== undefined){\r
10924                                     grpName = scope.member.child[0].groupName;\r
10925                                 }\r
10926                                 else{\r
10927                                     var toSlice = scope.member.child[0].name.search(' ');\r
10928                                     grpName = scope.member.child[0].name.slice(0, toSlice);\r
10929                                 }\r
10930 \r
10931                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {\r
10932                                     j = 0;\r
10933                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        \r
10934                                         if (j === scope.member.child.length) {\r
10935                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
10936                                             break;\r
10937                                             \r
10938                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){\r
10939                                                 scope.member.child[j-1].activeGrp = true;\r
10940                                             };\r
10941                                             \r
10942                                         }\r
10943                                         if (i + scope.member.divide > scope.member.child.length) {\r
10944                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
10945                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
10946                                                 scope.member.child[j].activeGrp = true;\r
10947                                             };\r
10948 \r
10949                                         } else {\r
10950                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);\r
10951                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
10952                                                 scope.member.child[j].activeGrp = true;\r
10953                                             };\r
10954                                         }\r
10955                                     }\r
10956                                 }\r
10957                                 if(scope.member.divide){\r
10958                                     element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");\r
10959                                 } else {\r
10960                                     element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");\r
10961                                 }\r
10962                                 $compile(element.contents())(scope);\r
10963                                 if(scope.member.active && scope.member.active === true){\r
10964                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
10965                                 };\r
10966                                 if(scope.member.selected && scope.member.selected === true){\r
10967                                     element.attr('aria-selected', true);\r
10968                                 };\r
10969                                 if( scope.member.active && scope.member.active == undefined){\r
10970                                     element.find('i').eq(0).addClass('icon-primary-collapsed');\r
10971                                 };\r
10972                             }\r
10973                         }\r
10974                 };\r
10975                 //Below condition opens node for opening on json load.\r
10976                 if(scope.member.active && scope.member.active == true){\r
10977                     scope.showChild();\r
10978                 };\r
10979                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){\r
10980                     element.find('i').eq(0).addClass('icon-primary-collapsed');\r
10981                 }\r
10982                 else if(scope.member.child == undefined){\r
10983                     element.find('i').eq(0).addClass('icon-primary-circle');\r
10984                 };\r
10985                 element.bind('keydown', function (evt) {\r
10986                     switch (evt.keyCode) {\r
10987                         case keymap.KEY.ENTER:\r
10988                             if (element.hasClass('bg') && scope.member.onSelect !== undefined) {\r
10989                                 scope.member.onSelect(scope.member);\r
10990                             }\r
10991                             evt.stopPropagation();\r
10992                             break;\r
10993                         default: \r
10994                             break;                            \r
10995                     }\r
10996                     \r
10997                 });\r
10998                 //else getting true in every case .. so better use switch case .. that makes more sense you dumb.\r
10999                 element.bind('click', function (evt) {\r
11000                     scope.showChild();\r
11001                     var expandFunc = scope.member.onExpand;\r
11002                     \r
11003                     //onSelect\r
11004                         if (element.hasClass('bg') && scope.member.onSelect !== undefined) {\r
11005                                     scope.member.onSelect(scope.member);\r
11006                                 }\r
11007                         if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {\r
11008                            var eValue = scope.member.onExpand(scope.member);\r
11009                         }\r
11010                         if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {\r
11011                             scope.member.onCollapse(scope.member);\r
11012                         }\r
11013                 });\r
11014             }\r
11015         }\r
11016 }])\r
11017     .directive('b2bTreeLink', ['keymap', '$timeout', function (keymap, $timeout) {\r
11018         return {\r
11019             restrict: 'A',\r
11020             link: function (scope, element, attr, ctrl) {\r
11021                 var rootE, parentE, upE, downE;\r
11022                 var closeOthersUp = function (elem,isKeyPress,passiveClose) {\r
11023                     //For accordion functionality on sibling nodes\r
11024                     if (elem.find('a').eq(0).hasClass('active')) {\r
11025                         activeToggle(elem,isKeyPress,passiveClose);\r
11026                         return;\r
11027                     }\r
11028                     if (elem.hasClass('bg') && !isKeyPress) {\r
11029                         elem.removeClass('bg');\r
11030                         if (elem.attr('aria-selected')) {\r
11031                             elem.attr('aria-selected', 'false');\r
11032                         }                        \r
11033                     }\r
11034                     if (elem[0].previousElementSibling !== null) {\r
11035                         closeOthersUp(angular.element(elem[0].previousElementSibling),isKeyPress);\r
11036                     }\r
11037                 };\r
11038                 var closeOthersDown = function (elem,isKeyPress,passiveClose) {\r
11039                     //For accordion functionality on sibling nodes\r
11040                     if (elem.find('a').eq(0).hasClass('active')) {\r
11041                         activeToggle(elem,isKeyPress,passiveClose);\r
11042                         return;\r
11043                     }\r
11044                     if (elem.hasClass('bg') && !isKeyPress) {\r
11045                         elem.removeClass('bg');\r
11046                         if (elem.attr('aria-selected')) {\r
11047                             elem.attr('aria-selected', 'false');\r
11048                         }                        \r
11049                     }\r
11050                     if (elem[0].nextElementSibling !== null) {\r
11051                         closeOthersDown(angular.element(elem[0].nextElementSibling),isKeyPress);\r
11052                     }\r
11053                 };\r
11054 \r
11055                \r
11056                 var removeBackground = function(elem){\r
11057 \r
11058                     if(elem.hasClass('b2b-tree')){\r
11059                         angular.element(elem[0].getElementsByClassName('bg')).removeClass('bg');\r
11060                         return;\r
11061                     }else{\r
11062                         removeBackground(elem.parent().parent());\r
11063                     }\r
11064 \r
11065                 };\r
11066 \r
11067 /**\r
11068 * These two functions used for setting heights on parent nodes as the child node closes\r
11069 * Retaining this code for future reference\r
11070 \r
11071                 var addParentHeight = function(e, h) {\r
11072                     var parentLi = e.parent().parent();\r
11073                     var parentUl = e.parent();\r
11074                     if(!parentLi.hasClass('b2b-tree')) {\r
11075                         var addHeight = parentUl[0].offsetHeight + h;\r
11076                         parentLi.find('ul').eq(0).css({\r
11077                             height: addHeight+'px'\r
11078                         })\r
11079                         addParentHeight(parentLi, h);\r
11080                     }                    \r
11081                 };\r
11082 \r
11083                 var removeParentHeight = function(e, h) {\r
11084                     var parentLi = e.parent().parent();\r
11085                     var parentUl = e.parent();\r
11086                     if(!parentLi.hasClass('b2b-tree')) {\r
11087                         var addHeight = parentUl[0].offsetHeight - h;\r
11088                         parentLi.find('ul').eq(0).css({\r
11089                             height: addHeight+'px'\r
11090                         })\r
11091                         removeParentHeight(parentLi, h);\r
11092                     }\r
11093                 };\r
11094 */          \r
11095 \r
11096             // isKeyPress - to notify that the function is called by Right Key press\r
11097             // passiveClose -  prevents firing of oncollapse events during the action\r
11098             // of expand function(check the function definition)\r
11099 \r
11100                 var activeToggle = function (elem,isKeyPress,passiveClose) {\r
11101                     var element = elem.find('a').eq(0);\r
11102                     if (element.hasClass('active')) {\r
11103                         if(!isKeyPress){\r
11104                             elem.removeClass('bg');\r
11105                         }\r
11106                         \r
11107                         if (elem.attr('aria-selected') && !isKeyPress) {\r
11108                             elem.attr('aria-selected', 'false');\r
11109                         }\r
11110                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {\r
11111                             if(isKeyPress && scope.member){\r
11112                                 if (scope.member.onCollapse !== undefined && !passiveClose) {\r
11113                                     scope.member.onCollapse(scope.member);\r
11114                                 }\r
11115                             }\r
11116                             element.removeClass('active');\r
11117                             elem.attr('aria-expanded', 'false');\r
11118                             element.find('i').eq(0).removeClass('icon-primary-expanded');\r
11119                             element.find('i').eq(0).addClass('icon-primary-collapsed');\r
11120                             //For Animation: below commented code is used to manually set height of UL to zero \r
11121                             //retaining code for future reference\r
11122                             /*\r
11123                             var totalHeight = elem.find('ul')[0].scrollHeight;\r
11124                             removeParentHeight(elem, totalHeight);\r
11125                             elem.find('ul').eq(0).css({\r
11126                                 height: null\r
11127                             });*/\r
11128                         }\r
11129                     } else {\r
11130                         if(!isKeyPress){\r
11131                             elem.addClass('bg');\r
11132                             elem.attr('aria-selected', 'true');\r
11133                         }\r
11134                         \r
11135                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {\r
11136                             if(isKeyPress){\r
11137                                 if(typeof scope.showChild === 'function' ){\r
11138                                 scope.showChild();\r
11139                                 }\r
11140                                 if(scope.member){\r
11141                                     if (scope.member.onExpand !== undefined) {\r
11142                                         scope.member.onExpand(scope.member);\r
11143                                     }\r
11144                                 }\r
11145                             }\r
11146                             element.addClass('active');\r
11147                             elem.attr('aria-expanded', 'true');\r
11148                             element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
11149                             element.find('i').eq(0).addClass('icon-primary-expanded');\r
11150                             //For Animation: below commented code is used to manually set height of the ul generatedon the click of parent LI.\r
11151                             //retaining code for future reference\r
11152                             /*                            \r
11153                             var totalHeight = elem.find('ul')[0].scrollHeight;\r
11154                             addParentHeight(elem, totalHeight);\r
11155                             elem.find('ul').eq(0).css({\r
11156                                 height: totalHeight+'px'\r
11157                             });*/\r
11158                             \r
11159                         }\r
11160                     }\r
11161                 };\r
11162                 element.bind('click', function (evt) {\r
11163                     //first we close others and then we open the clicked element\r
11164                     if (element[0].previousElementSibling) {\r
11165                         closeOthersUp(angular.element(element[0].previousElementSibling));\r
11166                     }\r
11167                     if (element[0].nextElementSibling) {\r
11168                         closeOthersDown(angular.element(element[0].nextElementSibling));\r
11169                     }\r
11170                     removeBackground(element);\r
11171                     activeToggle(element);                    \r
11172                     \r
11173                     evt.stopPropagation();                    \r
11174                 });\r
11175                 //default root tree element tabindex set zero\r
11176                 if (element.parent().parent().hasClass('b2b-tree') && (element.parent()[0].previousElementSibling === null)) {\r
11177                     element.attr('tabindex', 0);\r
11178                 }\r
11179                 //check root via class\r
11180                 var isRoot = function (elem) {\r
11181                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {\r
11182                         return true;\r
11183                     } else {\r
11184                         return false;\r
11185                     }\r
11186                 };\r
11187                 var findRoot = function (elem) {\r
11188                     if (isRoot(elem)) {\r
11189                         rootE = elem;\r
11190                         return;\r
11191                     }\r
11192                     findRoot(elem.parent());\r
11193                 };\r
11194 \r
11195                 var findPreActive = function (elem) {\r
11196 \r
11197                     if (!(elem.hasClass("active"))) {\r
11198                         return;\r
11199                     } else {\r
11200                         var childElems = angular.element(elem[0].nextElementSibling.children);\r
11201                         lastE = angular.element(childElems[childElems.length - 1]);\r
11202                         if (lastE.find('a').eq(0).hasClass('active')) {\r
11203                             findPreActive(lastE.find('a').eq(0));\r
11204                         }\r
11205                         upE = lastE;\r
11206                     }\r
11207                 };\r
11208 \r
11209                 var findUp = function (elem) {\r
11210                     if (isRoot(elem)) {\r
11211                         upE = elem;\r
11212                         return;\r
11213                     }\r
11214                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {\r
11215                         upE = angular.element(elem[0].previousElementSibling);\r
11216                         if (upE.find('a').eq(0).hasClass('active')) {\r
11217                             findPreActive(upE.find('a').eq(0));\r
11218                         }\r
11219                     } else {\r
11220                         upE = elem.parent().parent();\r
11221                     }\r
11222                 };\r
11223 \r
11224                 var downElement = function (elem) {\r
11225                     if (elem.next().hasClass('tree-hide')) {\r
11226                         downElement(elem.next());\r
11227                     } else {\r
11228                         downE = elem.next();\r
11229                     }\r
11230                 }\r
11231                 var isBottomElem = false;\r
11232                 var downParent = function(liElem){\r
11233                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree')){\r
11234                         isBottomElem = true;\r
11235                         return;\r
11236                     }\r
11237                     if(liElem.next().length !== 0){\r
11238                         downE = liElem.next().eq(0);\r
11239                         return;\r
11240                     }\r
11241                     else {\r
11242                         downParent(liElem.parent().parent());\r
11243                     }\r
11244                 }\r
11245                 \r
11246                 var findDown = function (elem) {\r
11247                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {\r
11248                         downE = elem.parent();\r
11249                         return;\r
11250                     }\r
11251                     if (elem.hasClass('active')) {\r
11252                         downE = elem.next().find('li').eq(0);\r
11253                         if (downE.hasClass('tree-hide')) {\r
11254                             downElement(downE);\r
11255                         }\r
11256 \r
11257                     } else {\r
11258                         downParent(elem.parent());\r
11259                         if(isBottomElem === true){\r
11260                             downE = elem.parent();\r
11261                             isBottomElem = false;\r
11262                         }\r
11263                     }\r
11264                 };\r
11265 \r
11266 \r
11267                 var resetTabPosition = function(element){\r
11268                     findRoot(element);\r
11269                     angular.element(rootE.parent().parent()[0].querySelector("li[tabindex='0']")).attr('tabindex','-1');\r
11270                     var elemToFocus =  rootE.parent().parent()[0].querySelector(".bg")|| rootE;\r
11271 \r
11272                     angular.element(elemToFocus).attr('tabindex','0');\r
11273                 };\r
11274                 // Function to control the expansion of nodes when the user tabs into the tree and\r
11275                 // the slected node is not visible\r
11276                 var expand = function(elemArr){\r
11277                     var elem= elemArr.pop();\r
11278                     var element = elem.find('a').eq(0);                    \r
11279                     var selectedNode = elem.parent().parent()[0].querySelector(".bg");\r
11280                     if(selectedNode != null){\r
11281                         while(elem){\r
11282                              element = elem.find('a').eq(0);\r
11283                     if(!element.hasClass('active') ){\r
11284 \r
11285 \r
11286                     if (elem[0].previousElementSibling) {\r
11287                         closeOthersUp(angular.element(elem[0].previousElementSibling),true,true);\r
11288                         }\r
11289                         if (elem[0].nextElementSibling) {\r
11290                             closeOthersDown(angular.element(elem[0].nextElementSibling),true,true);\r
11291                         }\r
11292 \r
11293                          if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {\r
11294                             if(typeof scope.showChild === 'function' ){\r
11295                                 scope.showChild();\r
11296                             }\r
11297                             element.addClass('active');\r
11298                             elem.attr('aria-expanded', 'true');\r
11299                             element.find('i').eq(0).removeClass('icon-primary-collapsed');\r
11300                             element.find('i').eq(0).addClass('icon-primary-expanded');\r
11301                             }\r
11302                           \r
11303                           }   \r
11304                           elem = elemArr.pop();\r
11305                         }                      \r
11306                         \r
11307                     }else{\r
11308                         return;\r
11309                     }                   \r
11310                 };\r
11311 \r
11312                 element.find('a').eq(0).bind('mouseenter', function (evt) {\r
11313                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {\r
11314                         angular.element(value).removeClass('activeTooltip') \r
11315                     });\r
11316                     element.addClass('activeTooltip');\r
11317                 });\r
11318                 element.find('a').eq(0).bind('mouseleave', function (evt) {\r
11319                     element.removeClass('activeTooltip');\r
11320                 });\r
11321                 element.bind('focus', function (evt) {\r
11322                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {\r
11323                         angular.element(value).removeClass('activeTooltip') \r
11324                     });\r
11325                     element.addClass('activeTooltip');\r
11326                 });\r
11327                 element.bind('blur', function (evt) {\r
11328                     element.removeClass('activeTooltip');\r
11329                 });\r
11330                 element.bind('keydown', function (evt) {\r
11331                     switch (evt.keyCode) {\r
11332                     case keymap.KEY.HOME:\r
11333                         evt.preventDefault();\r
11334                         evt.stopPropagation();\r
11335                         element.attr('tabindex', -1);\r
11336                         findRoot(element);\r
11337                         rootE.eq(0).attr('tabindex', 0);\r
11338                         rootE[0].focus();\r
11339                         break;\r
11340                     case keymap.KEY.LEFT:\r
11341                         evt.preventDefault();\r
11342                         evt.stopPropagation(); \r
11343                       \r
11344                         if(element.find('a').eq(0).hasClass('active')){\r
11345                             if (element[0].previousElementSibling) {\r
11346                                 closeOthersUp(angular.element(element[0].previousElementSibling),true);\r
11347                             }\r
11348                             if (element[0].nextElementSibling) {\r
11349                                 closeOthersDown(angular.element(element[0].nextElementSibling),true);\r
11350                              }\r
11351                              activeToggle(element,true);\r
11352                                 return;\r
11353                         }\r
11354                             element.attr('tabindex', -1);\r
11355                             parentE = element.parent().parent();\r
11356                             parentE.attr('tabindex', 0);\r
11357                             parentE[0].focus();\r
11358                         break;\r
11359                     case keymap.KEY.UP:\r
11360                         evt.preventDefault();\r
11361                         evt.stopPropagation();\r
11362                         element.attr('tabindex', -1);\r
11363                         findUp(element);\r
11364                         upE.eq(0).attr('tabindex', 0);\r
11365                         upE[0].focus();\r
11366                         break;\r
11367                     case keymap.KEY.RIGHT:\r
11368                         evt.preventDefault();\r
11369                         evt.stopPropagation();\r
11370                         if(element.find('i').eq(0).hasClass('icon-primary-circle')){\r
11371                             break;\r
11372                         }    \r
11373                         if (!element.find('a').eq(0).hasClass('active')) {\r
11374                             if (element[0].previousElementSibling) {\r
11375                         closeOthersUp(angular.element(element[0].previousElementSibling),true);\r
11376                         }\r
11377                         if (element[0].nextElementSibling) {\r
11378                             closeOthersDown(angular.element(element[0].nextElementSibling),true);\r
11379                         }\r
11380                         activeToggle(element,true);\r
11381                     \r
11382                         }\r
11383                         else {\r
11384                             element.attr('tabindex', -1);\r
11385                             findDown(element.find('a').eq(0));\r
11386                             downE.eq(0).attr('tabindex', 0);\r
11387                             downE[0].focus();                            \r
11388                         }                        \r
11389                         break;\r
11390                     case keymap.KEY.DOWN:\r
11391                         evt.preventDefault();\r
11392                         element.attr('tabindex', -1);\r
11393                         findDown(element.find('a').eq(0));\r
11394                         downE.eq(0).attr('tabindex', 0);\r
11395                         downE[0].focus();\r
11396                         evt.stopPropagation();\r
11397                         break;\r
11398                     case keymap.KEY.ENTER:\r
11399                         var isSelectedElem = element.hasClass('bg');\r
11400                         var enterFunc = function(element){\r
11401                             if (isSelectedElem) {\r
11402                                 element.removeClass('bg');\r
11403                                 if (element.attr('aria-selected')) {\r
11404                                     element.attr('aria-selected', 'false');\r
11405                                 }                        \r
11406                             }\r
11407                             else {\r
11408                                 element.addClass('bg');\r
11409                                 element.attr('aria-selected', 'true');                                   \r
11410                             }  \r
11411                         };                            \r
11412                         if (element[0].previousElementSibling) {\r
11413                             closeOthersUp(angular.element(element[0].previousElementSibling));\r
11414                         }\r
11415                         if (element[0].nextElementSibling) {\r
11416                             closeOthersDown(angular.element(element[0].nextElementSibling));\r
11417                         }                   \r
11418                         \r
11419                         removeBackground(element);\r
11420                         enterFunc(element);\r
11421                         evt.stopPropagation();                                                      \r
11422                         break;\r
11423                     case keymap.KEY.TAB:\r
11424                         $timeout(function(){\r
11425                             resetTabPosition(element);\r
11426                         },0);\r
11427                          evt.stopPropagation(); \r
11428                         \r
11429                         break;\r
11430                     default:\r
11431                         break;\r
11432                     }\r
11433                 });\r
11434             element.bind('keyup',function(evt){\r
11435                 if(evt.keyCode === keymap.KEY.TAB){\r
11436                   \r
11437                         var tempElem = element;\r
11438                         var elemArr = [];\r
11439                         while(!tempElem.hasClass('b2b-tree')){\r
11440                             elemArr.push(tempElem);\r
11441                             tempElem = tempElem.parent().parent();\r
11442                         }\r
11443                         elemArr.push(tempElem);\r
11444                       \r
11445                         expand(elemArr);                    \r
11446                 }\r
11447                  evt.stopPropagation(); \r
11448             });\r
11449             }\r
11450         };\r
11451     }]);\r
11452 /**\r
11453  * @ngdoc directive\r
11454  * @name Navigation.att:Tree nodes with checkboxes\r
11455  *\r
11456  * @param {String} setRole - The value needs to be "tree". This is required to incorporate CATO requirements.\r
11457  * @param {boolean} groupIt - The value needs to be "false" for top-level tree rendered. \r
11458  * @param {Object} collection -  The JSON object of tree to be rendered.\r
11459  * @description\r
11460  *  <file src="src/treeNodeCheckbox/docs/readme.md" />\r
11461  *\r
11462  * @usage\r
11463  *      <div class="b2b-tree-checkbox">\r
11464  *                <b2b-tree-node-checkbox collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-node-checkbox>\r
11465  *            </div>\r
11466  * @example\r
11467  *  <section id="code">\r
11468         <example module="b2b.att">\r
11469             <file src="src/treeNodeCheckbox/docs/demo.html" />\r
11470             <file src="src/treeNodeCheckbox/docs/demo.js" />\r
11471        </example>\r
11472     </section>\r
11473  *\r
11474  */\r
11475 angular.module('b2b.att.treeNodeCheckbox', ['b2b.att.utilities'])\r
11476     .directive('b2bTreeNodeCheckbox', function () {\r
11477         return {\r
11478             restrict: "E",\r
11479             replace: true,\r
11480             scope: {\r
11481                 collection: '=',\r
11482                 groupIt: '=',\r
11483                 setRole: '@'\r
11484             },\r
11485             templateUrl: function (element, attrs) {\r
11486                 if (attrs.groupIt === 'true') {\r
11487                     return "b2bTemplate/treeNodeCheckbox/groupedTree.html";\r
11488                 } else {\r
11489                     return "b2bTemplate/treeNodeCheckbox/ungroupedTree.html";\r
11490                 }\r
11491             },\r
11492             link: function (scope) {\r
11493                 if (!(scope.setRole === 'tree')) {\r
11494                     scope.setRole = 'group';\r
11495                 }\r
11496             }\r
11497         }\r
11498     })\r
11499     .directive('b2bTreeMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {\r
11500         return {\r
11501             restrict: "E",\r
11502             replace: true,\r
11503             scope: {\r
11504                 member: '=',\r
11505                 groupIt: '='\r
11506             },\r
11507             templateUrl: 'b2bTemplate/treeNodeCheckbox/treeMember.html',\r
11508             link: function (scope, element, attrs) {\r
11509                 scope.elemArr = [];\r
11510                 var removeRootTabIndex = function (elem) {\r
11511                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {\r
11512                         elem.attr('tabindex', -1);                        \r
11513                         return;\r
11514                     }\r
11515                     removeRootTabIndex(elem.parent());\r
11516                 };\r
11517                 scope.$watch('member.child', function(newVal, oldVal){                  \r
11518                     if(newVal !== oldVal){\r
11519                         scope.showChild();\r
11520                     };\r
11521                 });\r
11522 \r
11523                 var checkedCount = 0;\r
11524                 var nonCheckedCount = 0;\r
11525                 var checkBoxesCount = 0;\r
11526 \r
11527                 if(element.find('a').eq(0).find('input')){\r
11528                     if(scope.member.indeterminate){\r
11529                         element.find('a').eq(0).find('input').prop('indeterminate', true);\r
11530                         element.attr('aria-checked',"mixed");\r
11531                     }\r
11532                     element.attr('aria-checked',scope.member.isSelected);\r
11533                 }\r
11534 \r
11535                 element.find('a').eq(0).find('input').bind('change',function(){\r
11536                     scope.member.indeterminate = false;\r
11537                     downwardModalUpdate(scope.member);\r
11538                     downwardSelection(element);\r
11539                     upwardSelection(element);\r
11540                     element.attr('aria-checked',scope.member.isSelected);\r
11541                      if (scope.member.onSelect !== undefined) {\r
11542                         scope.member.onSelect(scope.member);\r
11543                     }\r
11544                 });\r
11545 \r
11546                 element.find('a').eq(0).find('input').bind('click',function(){\r
11547                     var elem = angular.element(this);\r
11548                     if(scope.member.indeterminate){\r
11549                         scope.member.indeterminate = false;\r
11550                         scope.member.isSelected = true;\r
11551                         elem.prop('indeterminate', false);\r
11552                         elem.prop('checked', true);\r
11553                         elem.triggerHandler('change');\r
11554                     }\r
11555                 });\r
11556 \r
11557                 var groupNode = false;\r
11558                 var checkedTreeNode = false;\r
11559 \r
11560                 var isCheckboxSelected = function(elem){\r
11561                     checkedTreeNode = false;\r
11562                     checkedTreeNode = angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked;\r
11563                 }\r
11564 \r
11565                 var findCheckbox = function(elem){\r
11566                     return angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox');\r
11567                 }\r
11568 \r
11569                 var updateGrpNodeCheckboxes = function(elem, checked){\r
11570                     angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked = checked;\r
11571                 }\r
11572 \r
11573                 \r
11574                 var isGroupNode = function(elem){\r
11575                     groupNode = false;\r
11576                     if(angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.grpTreeCheckbox')){\r
11577                         groupNode = true;\r
11578                     }\r
11579                 }\r
11580 \r
11581                 var downwardModalUpdate = function(curMember){\r
11582                     angular.forEach(curMember.child, function(childMember, key) {\r
11583                         childMember.isSelected = curMember.isSelected;\r
11584                         childMember.indeterminate = false;\r
11585                         if(angular.isArray(childMember.child) && scope.member.child.length > 0){\r
11586                             downwardModalUpdate(childMember);\r
11587                         }\r
11588                     });\r
11589                 }\r
11590 \r
11591                 var downwardSelection = function(elem){\r
11592                     if(findCheckbox(elem)){\r
11593                         isCheckboxSelected(elem)\r
11594                     } \r
11595                     if(angular.element(elem).find('ul').length > 0){\r
11596                         var childNodes = angular.element(elem).find('ul').eq(0).children('li');\r
11597                         for(var i=0; i<childNodes.length; i++){\r
11598                             if(findCheckbox(childNodes[i])){\r
11599                                 isGroupNode(childNodes[i]);\r
11600                                 angular.element(findCheckbox(childNodes[i])).prop('indeterminate', false);\r
11601                                 angular.element(childNodes[i]).attr('aria-checked',checkedTreeNode);\r
11602                                 if(groupNode){\r
11603                                     updateGrpNodeCheckboxes(childNodes[i],checkedTreeNode);\r
11604                                 }else{\r
11605                                     angular.element(childNodes[i]).scope().member.isSelected = checkedTreeNode;\r
11606                                     angular.element(childNodes[i]).scope().member.indeterminate = false\r
11607                                     angular.element(childNodes[i]).scope().$apply();\r
11608                                 }\r
11609                                 downwardSelection(childNodes[i]);\r
11610                             }\r
11611                         }\r
11612 \r
11613                     }\r
11614                 }\r
11615                 var upwardSelection = function(elem){\r
11616                     var childNodes = elem.parent().parent().find('ul').eq(0).children('li');\r
11617                     checkedCount = 0;\r
11618                     nonCheckedCount = 0;\r
11619                     checkBoxesCount = 0;    \r
11620                     for(i=0; i<childNodes.length; i++){\r
11621                         if(findCheckbox(childNodes[i])){\r
11622                             isGroupNode(childNodes[i]);\r
11623                             isCheckboxSelected(childNodes[i]);\r
11624                             checkBoxesCount++;\r
11625                             if(checkedTreeNode){\r
11626                                 checkedCount++;\r
11627                             }else if(!angular.element(angular.element(angular.element(childNodes[i]).find('a').eq(0))[0].querySelector('input.treeCheckBox')).prop('indeterminate')){\r
11628                                 nonCheckedCount++;\r
11629                             }\r
11630                         }\r
11631                     }\r
11632                     var parentNodeScope;\r
11633                     parentNodeScope = angular.element(elem.parent().parent()).scope();\r
11634                     if(findCheckbox(elem.parent().parent())){\r
11635                         if(nonCheckedCount == checkBoxesCount){\r
11636                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);\r
11637                             if(parentNodeScope &&  parentNodeScope.member){\r
11638                                 parentNodeScope.member.isSelected = false;\r
11639                                 parentNodeScope.member.indeterminate = false;\r
11640                             }else{\r
11641                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);\r
11642                             }\r
11643                             angular.element(elem.parent().parent()).attr('aria-checked',false);\r
11644                         }else if(checkedCount == checkBoxesCount){\r
11645                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);\r
11646                             if(parentNodeScope &&  parentNodeScope.member){\r
11647                                 parentNodeScope.member.isSelected = true;\r
11648                                 parentNodeScope.member.indeterminate = false;\r
11649                             }else{\r
11650                                 updateGrpNodeCheckboxes(elem.parent().parent(),true);\r
11651                             }\r
11652                             angular.element(elem.parent().parent()).attr('aria-checked',true);\r
11653                         }else{\r
11654                             angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', true);\r
11655                             if(parentNodeScope &&  parentNodeScope.member){\r
11656                                 parentNodeScope.member.isSelected = false;\r
11657                                 parentNodeScope.member.indeterminate = true;\r
11658                             }else{\r
11659                                 updateGrpNodeCheckboxes(elem.parent().parent(),false);\r
11660                             }\r
11661                             angular.element(elem.parent().parent()).attr('aria-checked',"mixed");\r
11662                         }\r
11663                         if(parentNodeScope &&  parentNodeScope.member){\r
11664                             parentNodeScope.$apply();\r
11665                         }        \r
11666                     }\r
11667                     \r
11668                     \r
11669                     \r
11670                     if(elem.parent().parent().attr('role') == "treeitem"){\r
11671                         upwardSelection(elem.parent().parent());\r
11672                     }\r
11673                 }\r
11674 \r
11675                 scope.showChild = function () {\r
11676                         if (!element.hasClass('grouped')) {\r
11677                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {\r
11678                                 scope.groupIt = false;\r
11679                                 element.addClass('grouped');\r
11680                                 element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");\r
11681                                 $compile(element.contents())(scope);\r
11682                                 if(scope.member.active && scope.member.active === true){\r
11683                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');\r
11684                                 };\r
11685                                 if(scope.member.selected && scope.member.selected === true){\r
11686                                     element.attr('tabindex', 0);\r
11687                                     removeRootTabIndex(element);\r
11688                                 };\r
11689                                 if(scope.member.active && scope.member.active == undefined){\r
11690                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11691                                 };\r
11692                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {\r
11693                                 element.addClass('grouped');\r
11694                                 scope.groupIt = true;\r
11695                                 var j = 0;\r
11696                                 var grpName = '';\r
11697                                 if(scope.member.child[0].groupName !== undefined){\r
11698                                     grpName = scope.member.child[0].groupName;\r
11699                                 }\r
11700                                 else{\r
11701                                     var toSlice = scope.member.child[0].name.search(' ');\r
11702                                     grpName = scope.member.child[0].name.slice(0, toSlice);\r
11703                                 }\r
11704 \r
11705                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {\r
11706                                     j = 0;\r
11707                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        \r
11708                                         if (j === scope.member.child.length) {\r
11709                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
11710                                             break;\r
11711                                             \r
11712                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){\r
11713                                                 scope.member.child[j-1].activeGrp = true;\r
11714                                             };\r
11715                                             \r
11716                                         }\r
11717                                         if (i + scope.member.divide > scope.member.child.length) {\r
11718                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);\r
11719                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
11720                                                 scope.member.child[j].activeGrp = true;\r
11721                                             };\r
11722 \r
11723                                         } else {\r
11724                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);\r
11725                                             if(scope.member.child[j].active && scope.member.child[j].active===true){\r
11726                                                 scope.member.child[j].activeGrp = true;\r
11727                                             };\r
11728                                         }\r
11729                                     }\r
11730                                 }\r
11731                                 if(scope.member.divide){\r
11732                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");\r
11733                                 } else {\r
11734                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");\r
11735                                 }\r
11736                                 $compile(element.contents())(scope);\r
11737                                 if(scope.member.active && scope.member.active === true){\r
11738                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');\r
11739                                 };\r
11740                                 \r
11741                                 if( scope.member.active && scope.member.active == undefined){\r
11742                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11743                                 };\r
11744                             }\r
11745                         }\r
11746                         $timeout(function () {\r
11747                             if(!scope.member.indeterminate){\r
11748                                 downwardSelection(element);\r
11749                             }    \r
11750                         });  \r
11751 \r
11752                 };\r
11753                 \r
11754                 if(scope.member.active && scope.member.active == true){\r
11755                     scope.showChild();\r
11756                 };\r
11757                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){\r
11758                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11759                 }\r
11760                 else if(scope.member.child == undefined){\r
11761                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-circle');\r
11762                     if(scope.$parent.$index === 0) {\r
11763                         element.find('a').eq(0).append('<span class="first-link"></span>');\r
11764                     };\r
11765                 };\r
11766                 \r
11767                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {\r
11768                     scope.showChild();\r
11769                     var expandFunc = scope.member.onExpand;\r
11770                     if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {\r
11771                        var eValue = scope.member.onExpand(scope.member);\r
11772                     }\r
11773                     if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {\r
11774                         scope.member.onCollapse(scope.member);\r
11775                     }\r
11776                 });\r
11777 \r
11778                 angular.element(element[0].querySelectorAll('.treeNodeName')).eq(0).bind('click', function (evt) {\r
11779 \r
11780                 });\r
11781                 \r
11782             }\r
11783         }\r
11784 }])\r
11785     .directive('b2bTreeNodeLink', ['keymap', '$timeout', function (keymap, $timeout) {\r
11786         return {\r
11787             restrict: 'A',\r
11788             link: function (scope, element, attr, ctrl) {\r
11789                 var rootE, parentE, upE, downE;\r
11790                 var closeOthersUp = function (elem) {\r
11791                     \r
11792                     if (elem.find('a').eq(0).hasClass('active')) {\r
11793                         activeToggle(elem);\r
11794                         return;\r
11795                     }\r
11796                     if (elem.hasClass('bg')) {\r
11797                         elem.removeClass('bg');\r
11798                     }\r
11799                     if (elem[0].previousElementSibling !== null) {\r
11800                         closeOthersUp(angular.element(elem[0].previousElementSibling));\r
11801                     }\r
11802                 };\r
11803                 var closeOthersDown = function (elem) {\r
11804                     \r
11805                     if (elem.find('a').eq(0).hasClass('active')) {\r
11806                         activeToggle(elem);\r
11807                         return;\r
11808                     }\r
11809                     if (elem.hasClass('bg')) {\r
11810                         elem.removeClass('bg');\r
11811                     }\r
11812                     if (elem[0].nextElementSibling !== null) {\r
11813                         closeOthersDown(angular.element(elem[0].nextElementSibling));\r
11814                     }\r
11815                 };\r
11816 \r
11817                 var removeBackgroundUp = function (elem) {\r
11818                     \r
11819                     if (elem.hasClass('b2b-tree-checkbox')) {\r
11820                         return;\r
11821                     } else {\r
11822                         elem.parent().parent().removeClass('bg');\r
11823                         removeBackgroundUp(elem.parent().parent());\r
11824                     }\r
11825                 };\r
11826 \r
11827                 var removeBackgroundDown = function (elem) {\r
11828                     \r
11829                     angular.element(elem[0].querySelector('.bg')).removeClass('bg');\r
11830                 };\r
11831 \r
11832 \r
11833 \r
11834                 var activeToggle = function (elem) {\r
11835                     var element = elem.find('a').eq(0);\r
11836                     if (element.hasClass('active')) {\r
11837                         elem.removeClass('bg');\r
11838                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {\r
11839                             element.removeClass('active');\r
11840                             elem.attr('aria-expanded', 'false');\r
11841                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-expanded');\r
11842                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');\r
11843                         }\r
11844                     } else {\r
11845                         elem.addClass('bg');\r
11846                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {\r
11847                             element.addClass('active');\r
11848                             elem.attr('aria-expanded', 'true');\r
11849                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');\r
11850                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-expanded');\r
11851                         }\r
11852                     }\r
11853                 };\r
11854                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {\r
11855                     \r
11856                         if (element[0].previousElementSibling) {\r
11857                             closeOthersUp(angular.element(element[0].previousElementSibling));\r
11858                         }\r
11859                         if (element[0].nextElementSibling) {\r
11860                             closeOthersDown(angular.element(element[0].nextElementSibling));\r
11861                         }\r
11862 \r
11863                         activeToggle(element);\r
11864 \r
11865                     removeBackgroundDown(element);\r
11866                     removeBackgroundUp(element);\r
11867                     evt.stopPropagation();                    \r
11868                 });\r
11869                 \r
11870                 if (element.parent().parent().hasClass('b2b-tree-checkbox') && (element.parent()[0].previousElementSibling === null)) {\r
11871                     element.attr('tabindex', 0);\r
11872                 }\r
11873                 \r
11874                 var isRoot = function (elem) {\r
11875                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {\r
11876                         return true;\r
11877                     } else {\r
11878                         return false;\r
11879                     }\r
11880                 };\r
11881                 var findRoot = function (elem) {\r
11882                     if (isRoot(elem)) {\r
11883                         rootE = elem;\r
11884                         return;\r
11885                     }\r
11886                     findRoot(elem.parent());\r
11887                 };\r
11888 \r
11889                 var findPreActive = function (elem) {\r
11890 \r
11891                     if (!(elem.hasClass("active"))) {\r
11892                         return;\r
11893                     } else {\r
11894                         var childElems = angular.element(elem[0].nextElementSibling.children);\r
11895                         lastE = angular.element(childElems[childElems.length - 1]);\r
11896                         if (lastE.find('a').eq(0).hasClass('active')) {\r
11897                             findPreActive(lastE.find('a').eq(0));\r
11898                         }\r
11899                         upE = lastE;\r
11900                     }\r
11901                 };\r
11902 \r
11903                 var findUp = function (elem) {\r
11904                     if (isRoot(elem)) {\r
11905                         upE = elem;\r
11906                         return;\r
11907                     }\r
11908                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {\r
11909                         upE = angular.element(elem[0].previousElementSibling);\r
11910                         if (upE.find('a').eq(0).hasClass('active')) {\r
11911                             findPreActive(upE.find('a').eq(0));\r
11912                         }\r
11913                     } else {\r
11914                         upE = elem.parent().parent();\r
11915                     }\r
11916                 };\r
11917 \r
11918                 var downElement = function (elem) {\r
11919                     if (elem.next().hasClass('tree-hide')) {\r
11920                         downElement(elem.next());\r
11921                     } else {\r
11922                         downE = elem.next();\r
11923                     }\r
11924                 }\r
11925                 var isBottomElem = false;\r
11926                 var downParent = function(liElem){\r
11927                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree-checkbox')){\r
11928                         isBottomElem = true;\r
11929                         return;\r
11930                     }\r
11931                     if(liElem.next().length !== 0){\r
11932                         downE = liElem.next().eq(0);\r
11933                         return;\r
11934                     }\r
11935                     else {\r
11936                         downParent(liElem.parent().parent());\r
11937                     }\r
11938                 }\r
11939                 \r
11940                 var findDown = function (elem) {\r
11941                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {\r
11942                         downE = elem.parent();\r
11943                         return;\r
11944                     }\r
11945                     if (elem.hasClass('active')) {\r
11946                         downE = elem.next().find('li').eq(0);\r
11947                         if (downE.hasClass('tree-hide')) {\r
11948                             downElement(downE);\r
11949                         }\r
11950 \r
11951                     } else {\r
11952                         downParent(elem.parent());\r
11953                         if(isBottomElem === true){\r
11954                             downE = elem.parent();\r
11955                             isBottomElem = false;\r
11956                         }\r
11957                     }\r
11958                 };\r
11959                 element.bind('keydown', function (evt) {\r
11960                     switch (evt.keyCode) {\r
11961                     case keymap.KEY.HOME:\r
11962                         evt.preventDefault();\r
11963                         evt.stopPropagation();\r
11964                         element.attr('tabindex', -1);\r
11965                         findRoot(element);\r
11966                         rootE.eq(0).attr('tabindex', 0);\r
11967                         rootE[0].focus();\r
11968                         break;\r
11969                     case keymap.KEY.LEFT:\r
11970                         evt.preventDefault();\r
11971                         evt.stopPropagation();\r
11972                         if (!isRoot(element)) {\r
11973                             if(element.find('a').eq(0).hasClass('active')){\r
11974                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');\r
11975                                 return;\r
11976                             }\r
11977                             element.attr('tabindex', -1);\r
11978                             parentE = element.parent().parent();\r
11979                             parentE.attr('tabindex', 0);\r
11980                             parentE[0].focus();\r
11981                         } else {\r
11982                             if (element.find('a').eq(0).hasClass('active')) {\r
11983                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');\r
11984                             }\r
11985                         };\r
11986                         break;\r
11987                     case keymap.KEY.UP:\r
11988                         evt.preventDefault();\r
11989                         evt.stopPropagation();\r
11990                         element.attr('tabindex', -1);\r
11991                         findUp(element);\r
11992                         upE.eq(0).attr('tabindex', 0);\r
11993                         upE[0].focus();\r
11994                         break;\r
11995                     case keymap.KEY.RIGHT:\r
11996                         evt.preventDefault();\r
11997                         evt.stopPropagation();\r
11998                         if(angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')){\r
11999                             break;\r
12000                         }    \r
12001                         if (!element.find('a').eq(0).hasClass('active')) {\r
12002                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');\r
12003                         }\r
12004                         else {\r
12005                             element.attr('tabindex', -1);\r
12006                             findDown(element.find('a').eq(0));\r
12007                             downE.eq(0).attr('tabindex', 0);\r
12008                             downE[0].focus();                            \r
12009                         }                        \r
12010                         break;\r
12011                     case keymap.KEY.DOWN:\r
12012                         evt.preventDefault();\r
12013                         element.attr('tabindex', -1);\r
12014                         findDown(element.find('a').eq(0));\r
12015                         downE.eq(0).attr('tabindex', 0);\r
12016                         downE[0].focus();\r
12017                         evt.stopPropagation();\r
12018                         break;\r
12019                     case keymap.KEY.SPACE:\r
12020                     case keymap.KEY.ENTER:\r
12021                         evt.preventDefault();\r
12022                         evt.stopPropagation();\r
12023                         if(angular.isDefined(element.scope().member.isSelected)){\r
12024                             element.scope().member.isSelected = !element.scope().member.isSelected;\r
12025                             element.scope().member.indeterminate = false;\r
12026                             element.scope().$apply();\r
12027                             element.find('a').eq(0).find('input').prop('indeterminate', false);\r
12028                             element.find('a').eq(0).find('input').triggerHandler('change');\r
12029                         }\r
12030                         break;    \r
12031                     default:\r
12032                         break;\r
12033                     }\r
12034                 });\r
12035             }\r
12036         };\r
12037     }]);\r
12038 /*!\r
12039  * VERSION: 1.7.3\r
12040  * DATE: 2014-01-14\r
12041  * UPDATES AND DOCS AT: http://www.greensock.com\r
12042  *\r
12043  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r
12044  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r
12045  * Club GreenSock members, the software agreement that was issued with your membership.\r
12046  * \r
12047  * @author: Jack Doyle, jack@greensock.com\r
12048  **/\r
12049 (window._gsQueue || (window._gsQueue = [])).push( function() {\r
12050 \r
12051     "use strict";\r
12052 \r
12053     var _doc = document.documentElement,\r
12054         _window = window,\r
12055         _max = function(element, axis) {\r
12056             var dim = (axis === "x") ? "Width" : "Height",\r
12057                 scroll = "scroll" + dim,\r
12058                 client = "client" + dim,\r
12059                 body = document.body;\r
12060             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
12061         },\r
12062 \r
12063         ScrollToPlugin = window._gsDefine.plugin({\r
12064             propName: "scrollTo",\r
12065             API: 2,\r
12066             version:"1.7.3",\r
12067 \r
12068             //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
12069             init: function(target, value, tween) {\r
12070                 this._wdw = (target === _window);\r
12071                 this._target = target;\r
12072                 this._tween = tween;\r
12073                 if (typeof(value) !== "object") {\r
12074                     value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".\r
12075                 }\r
12076                 this._autoKill = (value.autoKill !== false);\r
12077                 this.x = this.xPrev = this.getX();\r
12078                 this.y = this.yPrev = this.getY();\r
12079                 if (value.x != null) {\r
12080                     this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);\r
12081                     this._overwriteProps.push("scrollTo_x");\r
12082                 } else {\r
12083                     this.skipX = true;\r
12084                 }\r
12085                 if (value.y != null) {\r
12086                     this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);\r
12087                     this._overwriteProps.push("scrollTo_y");\r
12088                 } else {\r
12089                     this.skipY = true;\r
12090                 }\r
12091                 return true;\r
12092             },\r
12093 \r
12094             //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
12095             set: function(v) {\r
12096                 this._super.setRatio.call(this, v);\r
12097 \r
12098                 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,\r
12099                     y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,\r
12100                     yDif = y - this.yPrev,\r
12101                     xDif = x - this.xPrev;\r
12102 \r
12103                 if (this._autoKill) {\r
12104                     //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
12105                     if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {\r
12106                         this.skipX = true; //if the user scrolls separately, we should stop tweening!\r
12107                     }\r
12108                     if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {\r
12109                         this.skipY = true; //if the user scrolls separately, we should stop tweening!\r
12110                     }\r
12111                     if (this.skipX && this.skipY) {\r
12112                         this._tween.kill();\r
12113                     }\r
12114                 }\r
12115                 if (this._wdw) {\r
12116                     _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);\r
12117                 } else {\r
12118                     if (!this.skipY) {\r
12119                         this._target.scrollTop = this.y;\r
12120                     }\r
12121                     if (!this.skipX) {\r
12122                         this._target.scrollLeft = this.x;\r
12123                     }\r
12124                 }\r
12125                 this.xPrev = this.x;\r
12126                 this.yPrev = this.y;\r
12127             }\r
12128 \r
12129         }),\r
12130         p = ScrollToPlugin.prototype;\r
12131 \r
12132     ScrollToPlugin.max = _max;\r
12133 \r
12134     p.getX = function() {\r
12135         return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;\r
12136     };\r
12137 \r
12138     p.getY = function() {\r
12139         return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;\r
12140     };\r
12141 \r
12142     p._kill = function(lookup) {\r
12143         if (lookup.scrollTo_x) {\r
12144             this.skipX = true;\r
12145         }\r
12146         if (lookup.scrollTo_y) {\r
12147             this.skipY = true;\r
12148         }\r
12149         return this._super._kill.call(this, lookup);\r
12150     };\r
12151 \r
12152 }); if (window._gsDefine) { window._gsQueue.pop()(); }\r
12153 /*!\r
12154  * VERSION: 1.12.1\r
12155  * DATE: 2014-06-26\r
12156  * UPDATES AND DOCS AT: http://www.greensock.com\r
12157  * \r
12158  * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin\r
12159  *\r
12160  * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r
12161  * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r
12162  * Club GreenSock members, the software agreement that was issued with your membership.\r
12163  * \r
12164  * @author: Jack Doyle, jack@greensock.com\r
12165  **/\r
12166 \r
12167 (window._gsQueue || (window._gsQueue = [])).push( function() {\r
12168 \r
12169     "use strict";\r
12170 \r
12171     window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {\r
12172 \r
12173         var _slice = [].slice,\r
12174             TweenMax = function(target, duration, vars) {\r
12175                 TweenLite.call(this, target, duration, vars);\r
12176                 this._cycle = 0;\r
12177                 this._yoyo = (this.vars.yoyo === true);\r
12178                 this._repeat = this.vars.repeat || 0;\r
12179                 this._repeatDelay = this.vars.repeatDelay || 0;\r
12180                 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.\r
12181                 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)\r
12182             },\r
12183             _tinyNum = 0.0000000001,\r
12184             TweenLiteInternals = TweenLite._internals,\r
12185             _isSelector = TweenLiteInternals.isSelector,\r
12186             _isArray = TweenLiteInternals.isArray,\r
12187             p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),\r
12188             _blankArray = [];\r
12189 \r
12190         TweenMax.version = "1.12.1";\r
12191         p.constructor = TweenMax;\r
12192         p.kill()._gc = false;\r
12193         TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;\r
12194         TweenMax.getTweensOf = TweenLite.getTweensOf;\r
12195         TweenMax.lagSmoothing = TweenLite.lagSmoothing;\r
12196         TweenMax.ticker = TweenLite.ticker;\r
12197         TweenMax.render = TweenLite.render;\r
12198 \r
12199         p.invalidate = function() {\r
12200             this._yoyo = (this.vars.yoyo === true);\r
12201             this._repeat = this.vars.repeat || 0;\r
12202             this._repeatDelay = this.vars.repeatDelay || 0;\r
12203             this._uncache(true);\r
12204             return TweenLite.prototype.invalidate.call(this);\r
12205         };\r
12206         \r
12207         p.updateTo = function(vars, resetDuration) {\r
12208             var curRatio = this.ratio, p;\r
12209             if (resetDuration && this._startTime < this._timeline._time) {\r
12210                 this._startTime = this._timeline._time;\r
12211                 this._uncache(false);\r
12212                 if (this._gc) {\r
12213                     this._enabled(true, false);\r
12214                 } else {\r
12215                     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
12216                 }\r
12217             }\r
12218             for (p in vars) {\r
12219                 this.vars[p] = vars[p];\r
12220             }\r
12221             if (this._initted) {\r
12222                 if (resetDuration) {\r
12223                     this._initted = false;\r
12224                 } else {\r
12225                     if (this._gc) {\r
12226                         this._enabled(true, false);\r
12227                     }\r
12228                     if (this._notifyPluginsOfEnabled && this._firstPT) {\r
12229                         TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks\r
12230                     }\r
12231                     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
12232                         var prevTime = this._time;\r
12233                         this.render(0, true, false);\r
12234                         this._initted = false;\r
12235                         this.render(prevTime, true, false);\r
12236                     } else if (this._time > 0) {\r
12237                         this._initted = false;\r
12238                         this._init();\r
12239                         var inv = 1 / (1 - curRatio),\r
12240                             pt = this._firstPT, endValue;\r
12241                         while (pt) {\r
12242                             endValue = pt.s + pt.c; \r
12243                             pt.c *= inv;\r
12244                             pt.s = endValue - pt.c;\r
12245                             pt = pt._next;\r
12246                         }\r
12247                     }\r
12248                 }\r
12249             }\r
12250             return this;\r
12251         };\r
12252                 \r
12253         p.render = function(time, suppressEvents, force) {\r
12254             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
12255                 this.invalidate();\r
12256             }\r
12257             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),\r
12258                 prevTime = this._time,\r
12259                 prevTotalTime = this._totalTime, \r
12260                 prevCycle = this._cycle,\r
12261                 duration = this._duration,\r
12262                 prevRawPrevTime = this._rawPrevTime,\r
12263                 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;\r
12264             if (time >= totalDur) {\r
12265                 this._totalTime = totalDur;\r
12266                 this._cycle = this._repeat;\r
12267                 if (this._yoyo && (this._cycle & 1) !== 0) {\r
12268                     this._time = 0;\r
12269                     this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;\r
12270                 } else {\r
12271                     this._time = duration;\r
12272                     this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;\r
12273                 }\r
12274                 if (!this._reversed) {\r
12275                     isComplete = true;\r
12276                     callback = "onComplete";\r
12277                 }\r
12278                 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
12279                     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
12280                         time = 0;\r
12281                     }\r
12282                     if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {\r
12283                         force = true;\r
12284                         if (prevRawPrevTime > _tinyNum) {\r
12285                             callback = "onReverseComplete";\r
12286                         }\r
12287                     }\r
12288                     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
12289                 }\r
12290                 \r
12291             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
12292                 this._totalTime = this._time = this._cycle = 0;\r
12293                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;\r
12294                 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {\r
12295                     callback = "onReverseComplete";\r
12296                     isComplete = this._reversed;\r
12297                 }\r
12298                 if (time < 0) {\r
12299                     this._active = false;\r
12300                     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
12301                         if (prevRawPrevTime >= 0) {\r
12302                             force = true;\r
12303                         }\r
12304                         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
12305                     }\r
12306                 } 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
12307                     force = true;\r
12308                 }\r
12309             } else {\r
12310                 this._totalTime = this._time = time;\r
12311                 \r
12312                 if (this._repeat !== 0) {\r
12313                     cycleDuration = duration + this._repeatDelay;\r
12314                     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
12315                     if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {\r
12316                         this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)\r
12317                     }\r
12318                     this._time = this._totalTime - (this._cycle * cycleDuration);\r
12319                     if (this._yoyo) if ((this._cycle & 1) !== 0) {\r
12320                         this._time = duration - this._time;\r
12321                     }\r
12322                     if (this._time > duration) {\r
12323                         this._time = duration;\r
12324                     } else if (this._time < 0) {\r
12325                         this._time = 0;\r
12326                     }\r
12327                 }\r
12328 \r
12329                 if (this._easeType) {\r
12330                     r = this._time / duration;\r
12331                     type = this._easeType;\r
12332                     pow = this._easePower;\r
12333                     if (type === 1 || (type === 3 && r >= 0.5)) {\r
12334                         r = 1 - r;\r
12335                     }\r
12336                     if (type === 3) {\r
12337                         r *= 2;\r
12338                     }\r
12339                     if (pow === 1) {\r
12340                         r *= r;\r
12341                     } else if (pow === 2) {\r
12342                         r *= r * r;\r
12343                     } else if (pow === 3) {\r
12344                         r *= r * r * r;\r
12345                     } else if (pow === 4) {\r
12346                         r *= r * r * r * r;\r
12347                     }\r
12348 \r
12349                     if (type === 1) {\r
12350                         this.ratio = 1 - r;\r
12351                     } else if (type === 2) {\r
12352                         this.ratio = r;\r
12353                     } else if (this._time / duration < 0.5) {\r
12354                         this.ratio = r / 2;\r
12355                     } else {\r
12356                         this.ratio = 1 - (r / 2);\r
12357                     }\r
12358 \r
12359                 } else {\r
12360                     this.ratio = this._ease.getRatio(this._time / duration);\r
12361                 }\r
12362                 \r
12363             }\r
12364                 \r
12365             if (prevTime === this._time && !force && prevCycle === this._cycle) {\r
12366                 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
12367                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
12368                 }\r
12369                 return;\r
12370             } else if (!this._initted) {\r
12371                 this._init();\r
12372                 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
12373                     return;\r
12374                 } 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
12375                     this._time = prevTime;\r
12376                     this._totalTime = prevTotalTime;\r
12377                     this._rawPrevTime = prevRawPrevTime;\r
12378                     this._cycle = prevCycle;\r
12379                     TweenLiteInternals.lazyTweens.push(this);\r
12380                     this._lazy = time;\r
12381                     return;\r
12382                 }\r
12383                 //_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
12384                 if (this._time && !isComplete) {\r
12385                     this.ratio = this._ease.getRatio(this._time / duration);\r
12386                 } else if (isComplete && this._ease._calcEnd) {\r
12387                     this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);\r
12388                 }\r
12389             }\r
12390             if (this._lazy !== false) {\r
12391                 this._lazy = false;\r
12392             }\r
12393 \r
12394             if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {\r
12395                 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
12396             }\r
12397             if (prevTotalTime === 0) {\r
12398                 if (this._initted === 2 && time > 0) {\r
12399                     //this.invalidate();\r
12400                     this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true\r
12401                 }\r
12402                 if (this._startAt) {\r
12403                     if (time >= 0) {\r
12404                         this._startAt.render(time, suppressEvents, force);\r
12405                     } else if (!callback) {\r
12406                         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
12407                     }\r
12408                 }\r
12409                 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {\r
12410                     this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
12411                 }\r
12412             }\r
12413             \r
12414             pt = this._firstPT;\r
12415             while (pt) {\r
12416                 if (pt.f) {\r
12417                     pt.t[pt.p](pt.c * this.ratio + pt.s);\r
12418                 } else {\r
12419                     pt.t[pt.p] = pt.c * this.ratio + pt.s;\r
12420                 }\r
12421                 pt = pt._next;\r
12422             }\r
12423             \r
12424             if (this._onUpdate) {\r
12425                 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
12426                     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
12427                 }\r
12428                 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {\r
12429                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
12430                 }\r
12431             }\r
12432             if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {\r
12433                 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);\r
12434             }\r
12435             if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate\r
12436                 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
12437                     this._startAt.render(time, suppressEvents, force);\r
12438                 }\r
12439                 if (isComplete) {\r
12440                     if (this._timeline.autoRemoveChildren) {\r
12441                         this._enabled(false, false);\r
12442                     }\r
12443                     this._active = false;\r
12444                 }\r
12445                 if (!suppressEvents && this.vars[callback]) {\r
12446                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
12447                 }\r
12448                 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
12449                     this._rawPrevTime = 0;\r
12450                 }\r
12451             }\r
12452         };\r
12453         \r
12454 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------\r
12455         \r
12456         TweenMax.to = function(target, duration, vars) {\r
12457             return new TweenMax(target, duration, vars);\r
12458         };\r
12459         \r
12460         TweenMax.from = function(target, duration, vars) {\r
12461             vars.runBackwards = true;\r
12462             vars.immediateRender = (vars.immediateRender != false);\r
12463             return new TweenMax(target, duration, vars);\r
12464         };\r
12465         \r
12466         TweenMax.fromTo = function(target, duration, fromVars, toVars) {\r
12467             toVars.startAt = fromVars;\r
12468             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
12469             return new TweenMax(target, duration, toVars);\r
12470         };\r
12471         \r
12472         TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12473             stagger = stagger || 0;\r
12474             var delay = vars.delay || 0,\r
12475                 a = [],\r
12476                 finalComplete = function() {\r
12477                     if (vars.onComplete) {\r
12478                         vars.onComplete.apply(vars.onCompleteScope || this, arguments);\r
12479                     }\r
12480                     onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);\r
12481                 },\r
12482                 l, copy, i, p;\r
12483             if (!_isArray(targets)) {\r
12484                 if (typeof(targets) === "string") {\r
12485                     targets = TweenLite.selector(targets) || targets;\r
12486                 }\r
12487                 if (_isSelector(targets)) {\r
12488                     targets = _slice.call(targets, 0);\r
12489                 }\r
12490             }\r
12491             l = targets.length;\r
12492             for (i = 0; i < l; i++) {\r
12493                 copy = {};\r
12494                 for (p in vars) {\r
12495                     copy[p] = vars[p];\r
12496                 }\r
12497                 copy.delay = delay;\r
12498                 if (i === l - 1 && onCompleteAll) {\r
12499                     copy.onComplete = finalComplete;\r
12500                 }\r
12501                 a[i] = new TweenMax(targets[i], duration, copy);\r
12502                 delay += stagger;\r
12503             }\r
12504             return a;\r
12505         };\r
12506         \r
12507         TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12508             vars.runBackwards = true;\r
12509             vars.immediateRender = (vars.immediateRender != false);\r
12510             return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12511         };\r
12512         \r
12513         TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12514             toVars.startAt = fromVars;\r
12515             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
12516             return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12517         };\r
12518                 \r
12519         TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {\r
12520             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
12521         };\r
12522         \r
12523         TweenMax.set = function(target, vars) {\r
12524             return new TweenMax(target, 0, vars);\r
12525         };\r
12526         \r
12527         TweenMax.isTweening = function(target) {\r
12528             return (TweenLite.getTweensOf(target, true).length > 0);\r
12529         };\r
12530         \r
12531         var _getChildrenOf = function(timeline, includeTimelines) {\r
12532                 var a = [],\r
12533                     cnt = 0,\r
12534                     tween = timeline._first;\r
12535                 while (tween) {\r
12536                     if (tween instanceof TweenLite) {\r
12537                         a[cnt++] = tween;\r
12538                     } else {\r
12539                         if (includeTimelines) {\r
12540                             a[cnt++] = tween;\r
12541                         }\r
12542                         a = a.concat(_getChildrenOf(tween, includeTimelines));\r
12543                         cnt = a.length;\r
12544                     }\r
12545                     tween = tween._next;\r
12546                 }\r
12547                 return a;\r
12548             }, \r
12549             getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {\r
12550                 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );\r
12551             };\r
12552         \r
12553         TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {\r
12554             if (tweens == null) {\r
12555                 tweens = true;\r
12556             }\r
12557             if (delayedCalls == null) {\r
12558                 delayedCalls = true;\r
12559             }\r
12560             var a = getAllTweens((timelines != false)),\r
12561                 l = a.length,\r
12562                 allTrue = (tweens && delayedCalls && timelines),\r
12563                 isDC, tween, i;\r
12564             for (i = 0; i < l; i++) {\r
12565                 tween = a[i];\r
12566                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {\r
12567                     if (complete) {\r
12568                         tween.totalTime(tween._reversed ? 0 : tween.totalDuration());\r
12569                     } else {\r
12570                         tween._enabled(false, false);\r
12571                     }\r
12572                 }\r
12573             }\r
12574         };\r
12575         \r
12576         TweenMax.killChildTweensOf = function(parent, complete) {\r
12577             if (parent == null) {\r
12578                 return;\r
12579             }\r
12580             var tl = TweenLiteInternals.tweenLookup,\r
12581                 a, curParent, p, i, l;\r
12582             if (typeof(parent) === "string") {\r
12583                 parent = TweenLite.selector(parent) || parent;\r
12584             }\r
12585             if (_isSelector(parent)) {\r
12586                 parent = _slice.call(parent, 0);\r
12587             }\r
12588             if (_isArray(parent)) {\r
12589                 i = parent.length;\r
12590                 while (--i > -1) {\r
12591                     TweenMax.killChildTweensOf(parent[i], complete);\r
12592                 }\r
12593                 return;\r
12594             }\r
12595             a = [];\r
12596             for (p in tl) {\r
12597                 curParent = tl[p].target.parentNode;\r
12598                 while (curParent) {\r
12599                     if (curParent === parent) {\r
12600                         a = a.concat(tl[p].tweens);\r
12601                     }\r
12602                     curParent = curParent.parentNode;\r
12603                 }\r
12604             }\r
12605             l = a.length;\r
12606             for (i = 0; i < l; i++) {\r
12607                 if (complete) {\r
12608                     a[i].totalTime(a[i].totalDuration());\r
12609                 }\r
12610                 a[i]._enabled(false, false);\r
12611             }\r
12612         };\r
12613 \r
12614         var _changePause = function(pause, tweens, delayedCalls, timelines) {\r
12615             tweens = (tweens !== false);\r
12616             delayedCalls = (delayedCalls !== false);\r
12617             timelines = (timelines !== false);\r
12618             var a = getAllTweens(timelines),\r
12619                 allTrue = (tweens && delayedCalls && timelines),\r
12620                 i = a.length,\r
12621                 isDC, tween;\r
12622             while (--i > -1) {\r
12623                 tween = a[i];\r
12624                 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {\r
12625                     tween.paused(pause);\r
12626                 }\r
12627             }\r
12628         };\r
12629         \r
12630         TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {\r
12631             _changePause(true, tweens, delayedCalls, timelines);\r
12632         };\r
12633         \r
12634         TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {\r
12635             _changePause(false, tweens, delayedCalls, timelines);\r
12636         };\r
12637 \r
12638         TweenMax.globalTimeScale = function(value) {\r
12639             var tl = Animation._rootTimeline,\r
12640                 t = TweenLite.ticker.time;\r
12641             if (!arguments.length) {\r
12642                 return tl._timeScale;\r
12643             }\r
12644             value = value || _tinyNum; //can't allow zero because it'll throw the math off\r
12645             tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);\r
12646             tl = Animation._rootFramesTimeline;\r
12647             t = TweenLite.ticker.frame;\r
12648             tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);\r
12649             tl._timeScale = Animation._rootTimeline._timeScale = value;\r
12650             return value;\r
12651         };\r
12652         \r
12653     \r
12654 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------\r
12655         \r
12656         p.progress = function(value) {\r
12657             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
12658         };\r
12659         \r
12660         p.totalProgress = function(value) {\r
12661             return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);\r
12662         };\r
12663         \r
12664         p.time = function(value, suppressEvents) {\r
12665             if (!arguments.length) {\r
12666                 return this._time;\r
12667             }\r
12668             if (this._dirty) {\r
12669                 this.totalDuration();\r
12670             }\r
12671             if (value > this._duration) {\r
12672                 value = this._duration;\r
12673             }\r
12674             if (this._yoyo && (this._cycle & 1) !== 0) {\r
12675                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));\r
12676             } else if (this._repeat !== 0) {\r
12677                 value += this._cycle * (this._duration + this._repeatDelay);\r
12678             }\r
12679             return this.totalTime(value, suppressEvents);\r
12680         };\r
12681 \r
12682         p.duration = function(value) {\r
12683             if (!arguments.length) {\r
12684                 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
12685             }\r
12686             return Animation.prototype.duration.call(this, value);\r
12687         };\r
12688 \r
12689         p.totalDuration = function(value) {\r
12690             if (!arguments.length) {\r
12691                 if (this._dirty) {\r
12692                     //instead of Infinity, we use 999999999999 so that we can accommodate reverses\r
12693                     this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);\r
12694                     this._dirty = false;\r
12695                 }\r
12696                 return this._totalDuration;\r
12697             }\r
12698             return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );\r
12699         };\r
12700         \r
12701         p.repeat = function(value) {\r
12702             if (!arguments.length) {\r
12703                 return this._repeat;\r
12704             }\r
12705             this._repeat = value;\r
12706             return this._uncache(true);\r
12707         };\r
12708         \r
12709         p.repeatDelay = function(value) {\r
12710             if (!arguments.length) {\r
12711                 return this._repeatDelay;\r
12712             }\r
12713             this._repeatDelay = value;\r
12714             return this._uncache(true);\r
12715         };\r
12716         \r
12717         p.yoyo = function(value) {\r
12718             if (!arguments.length) {\r
12719                 return this._yoyo;\r
12720             }\r
12721             this._yoyo = value;\r
12722             return this;\r
12723         };\r
12724         \r
12725         \r
12726         return TweenMax;\r
12727         \r
12728     }, true);\r
12729 \r
12730 \r
12731 \r
12732 \r
12733 \r
12734 \r
12735 \r
12736 \r
12737 /*\r
12738  * ----------------------------------------------------------------\r
12739  * TimelineLite\r
12740  * ----------------------------------------------------------------\r
12741  */\r
12742     window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {\r
12743 \r
12744         var TimelineLite = function(vars) {\r
12745                 SimpleTimeline.call(this, vars);\r
12746                 this._labels = {};\r
12747                 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);\r
12748                 this.smoothChildTiming = (this.vars.smoothChildTiming === true);\r
12749                 this._sortChildren = true;\r
12750                 this._onUpdate = this.vars.onUpdate;\r
12751                 var v = this.vars,\r
12752                     val, p;\r
12753                 for (p in v) {\r
12754                     val = v[p];\r
12755                     if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {\r
12756                         v[p] = this._swapSelfInParams(val);\r
12757                     }\r
12758                 }\r
12759                 if (_isArray(v.tweens)) {\r
12760                     this.add(v.tweens, 0, v.align, v.stagger);\r
12761                 }\r
12762             },\r
12763             _tinyNum = 0.0000000001,\r
12764             _isSelector = TweenLite._internals.isSelector,\r
12765             _isArray = TweenLite._internals.isArray,\r
12766             _blankArray = [],\r
12767             _globals = window._gsDefine.globals,\r
12768             _copy = function(vars) {\r
12769                 var copy = {}, p;\r
12770                 for (p in vars) {\r
12771                     copy[p] = vars[p];\r
12772                 }\r
12773                 return copy;\r
12774             },\r
12775             _pauseCallback = function(tween, callback, params, scope) {\r
12776                 tween._timeline.pause(tween._startTime);\r
12777                 if (callback) {\r
12778                     callback.apply(scope || tween._timeline, params || _blankArray);\r
12779                 }\r
12780             },\r
12781             _slice = _blankArray.slice,\r
12782             p = TimelineLite.prototype = new SimpleTimeline();\r
12783 \r
12784         TimelineLite.version = "1.12.1";\r
12785         p.constructor = TimelineLite;\r
12786         p.kill()._gc = false;\r
12787 \r
12788         p.to = function(target, duration, vars, position) {\r
12789             var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;\r
12790             return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);\r
12791         };\r
12792 \r
12793         p.from = function(target, duration, vars, position) {\r
12794             return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);\r
12795         };\r
12796 \r
12797         p.fromTo = function(target, duration, fromVars, toVars, position) {\r
12798             var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;\r
12799             return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);\r
12800         };\r
12801 \r
12802         p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12803             var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),\r
12804                 i;\r
12805             if (typeof(targets) === "string") {\r
12806                 targets = TweenLite.selector(targets) || targets;\r
12807             }\r
12808             if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.\r
12809                 targets = _slice.call(targets, 0);\r
12810             }\r
12811             stagger = stagger || 0;\r
12812             for (i = 0; i < targets.length; i++) {\r
12813                 if (vars.startAt) {\r
12814                     vars.startAt = _copy(vars.startAt);\r
12815                 }\r
12816                 tl.to(targets[i], duration, _copy(vars), i * stagger);\r
12817             }\r
12818             return this.add(tl, position);\r
12819         };\r
12820 \r
12821         p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12822             vars.immediateRender = (vars.immediateRender != false);\r
12823             vars.runBackwards = true;\r
12824             return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12825         };\r
12826 \r
12827         p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {\r
12828             toVars.startAt = fromVars;\r
12829             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
12830             return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);\r
12831         };\r
12832 \r
12833         p.call = function(callback, params, scope, position) {\r
12834             return this.add( TweenLite.delayedCall(0, callback, params, scope), position);\r
12835         };\r
12836 \r
12837         p.set = function(target, vars, position) {\r
12838             position = this._parseTimeOrLabel(position, 0, true);\r
12839             if (vars.immediateRender == null) {\r
12840                 vars.immediateRender = (position === this._time && !this._paused);\r
12841             }\r
12842             return this.add( new TweenLite(target, 0, vars), position);\r
12843         };\r
12844 \r
12845         TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {\r
12846             vars = vars || {};\r
12847             if (vars.smoothChildTiming == null) {\r
12848                 vars.smoothChildTiming = true;\r
12849             }\r
12850             var tl = new TimelineLite(vars),\r
12851                 root = tl._timeline,\r
12852                 tween, next;\r
12853             if (ignoreDelayedCalls == null) {\r
12854                 ignoreDelayedCalls = true;\r
12855             }\r
12856             root._remove(tl, true);\r
12857             tl._startTime = 0;\r
12858             tl._rawPrevTime = tl._time = tl._totalTime = root._time;\r
12859             tween = root._first;\r
12860             while (tween) {\r
12861                 next = tween._next;\r
12862                 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {\r
12863                     tl.add(tween, tween._startTime - tween._delay);\r
12864                 }\r
12865                 tween = next;\r
12866             }\r
12867             root.add(tl, 0);\r
12868             return tl;\r
12869         };\r
12870 \r
12871         p.add = function(value, position, align, stagger) {\r
12872             var curTime, l, i, child, tl, beforeRawTime;\r
12873             if (typeof(position) !== "number") {\r
12874                 position = this._parseTimeOrLabel(position, 0, true, value);\r
12875             }\r
12876             if (!(value instanceof Animation)) {\r
12877                 if ((value instanceof Array) || (value && value.push && _isArray(value))) {\r
12878                     align = align || "normal";\r
12879                     stagger = stagger || 0;\r
12880                     curTime = position;\r
12881                     l = value.length;\r
12882                     for (i = 0; i < l; i++) {\r
12883                         if (_isArray(child = value[i])) {\r
12884                             child = new TimelineLite({tweens:child});\r
12885                         }\r
12886                         this.add(child, curTime);\r
12887                         if (typeof(child) !== "string" && typeof(child) !== "function") {\r
12888                             if (align === "sequence") {\r
12889                                 curTime = child._startTime + (child.totalDuration() / child._timeScale);\r
12890                             } else if (align === "start") {\r
12891                                 child._startTime -= child.delay();\r
12892                             }\r
12893                         }\r
12894                         curTime += stagger;\r
12895                     }\r
12896                     return this._uncache(true);\r
12897                 } else if (typeof(value) === "string") {\r
12898                     return this.addLabel(value, position);\r
12899                 } else if (typeof(value) === "function") {\r
12900                     value = TweenLite.delayedCall(0, value);\r
12901                 } else {\r
12902                     throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");\r
12903                 }\r
12904             }\r
12905 \r
12906             SimpleTimeline.prototype.add.call(this, value, position);\r
12907 \r
12908             //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
12909             if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {\r
12910                 //in case any of the ancestors had completed but should now be enabled...\r
12911                 tl = this;\r
12912                 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
12913                 while (tl._timeline) {\r
12914                     if (beforeRawTime && tl._timeline.smoothChildTiming) {\r
12915                         tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.\r
12916                     } else if (tl._gc) {\r
12917                         tl._enabled(true, false);\r
12918                     }\r
12919                     tl = tl._timeline;\r
12920                 }\r
12921             }\r
12922 \r
12923             return this;\r
12924         };\r
12925 \r
12926         p.remove = function(value) {\r
12927             if (value instanceof Animation) {\r
12928                 return this._remove(value, false);\r
12929             } else if (value instanceof Array || (value && value.push && _isArray(value))) {\r
12930                 var i = value.length;\r
12931                 while (--i > -1) {\r
12932                     this.remove(value[i]);\r
12933                 }\r
12934                 return this;\r
12935             } else if (typeof(value) === "string") {\r
12936                 return this.removeLabel(value);\r
12937             }\r
12938             return this.kill(null, value);\r
12939         };\r
12940 \r
12941         p._remove = function(tween, skipDisable) {\r
12942             SimpleTimeline.prototype._remove.call(this, tween, skipDisable);\r
12943             var last = this._last;\r
12944             if (!last) {\r
12945                 this._time = this._totalTime = this._duration = this._totalDuration = 0;\r
12946             } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {\r
12947                 this._time = this.duration();\r
12948                 this._totalTime = this._totalDuration;\r
12949             }\r
12950             return this;\r
12951         };\r
12952 \r
12953         p.append = function(value, offsetOrLabel) {\r
12954             return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));\r
12955         };\r
12956 \r
12957         p.insert = p.insertMultiple = function(value, position, align, stagger) {\r
12958             return this.add(value, position || 0, align, stagger);\r
12959         };\r
12960 \r
12961         p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {\r
12962             return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);\r
12963         };\r
12964 \r
12965         p.addLabel = function(label, position) {\r
12966             this._labels[label] = this._parseTimeOrLabel(position);\r
12967             return this;\r
12968         };\r
12969 \r
12970         p.addPause = function(position, callback, params, scope) {\r
12971             return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);\r
12972         };\r
12973 \r
12974         p.removeLabel = function(label) {\r
12975             delete this._labels[label];\r
12976             return this;\r
12977         };\r
12978 \r
12979         p.getLabelTime = function(label) {\r
12980             return (this._labels[label] != null) ? this._labels[label] : -1;\r
12981         };\r
12982 \r
12983         p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {\r
12984             var i;\r
12985             //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
12986             if (ignore instanceof Animation && ignore.timeline === this) {\r
12987                 this.remove(ignore);\r
12988             } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {\r
12989                 i = ignore.length;\r
12990                 while (--i > -1) {\r
12991                     if (ignore[i] instanceof Animation && ignore[i].timeline === this) {\r
12992                         this.remove(ignore[i]);\r
12993                     }\r
12994                 }\r
12995             }\r
12996             if (typeof(offsetOrLabel) === "string") {\r
12997                 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);\r
12998             }\r
12999             offsetOrLabel = offsetOrLabel || 0;\r
13000             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
13001                 i = timeOrLabel.indexOf("=");\r
13002                 if (i === -1) {\r
13003                     if (this._labels[timeOrLabel] == null) {\r
13004                         return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;\r
13005                     }\r
13006                     return this._labels[timeOrLabel] + offsetOrLabel;\r
13007                 }\r
13008                 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));\r
13009                 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();\r
13010             } else if (timeOrLabel == null) {\r
13011                 timeOrLabel = this.duration();\r
13012             }\r
13013             return Number(timeOrLabel) + offsetOrLabel;\r
13014         };\r
13015 \r
13016         p.seek = function(position, suppressEvents) {\r
13017             return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));\r
13018         };\r
13019 \r
13020         p.stop = function() {\r
13021             return this.paused(true);\r
13022         };\r
13023 \r
13024         p.gotoAndPlay = function(position, suppressEvents) {\r
13025             return this.play(position, suppressEvents);\r
13026         };\r
13027 \r
13028         p.gotoAndStop = function(position, suppressEvents) {\r
13029             return this.pause(position, suppressEvents);\r
13030         };\r
13031 \r
13032         p.render = function(time, suppressEvents, force) {\r
13033             if (this._gc) {\r
13034                 this._enabled(true, false);\r
13035             }\r
13036             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),\r
13037                 prevTime = this._time,\r
13038                 prevStart = this._startTime,\r
13039                 prevTimeScale = this._timeScale,\r
13040                 prevPaused = this._paused,\r
13041                 tween, isComplete, next, callback, internalForce;\r
13042             if (time >= totalDur) {\r
13043                 this._totalTime = this._time = totalDur;\r
13044                 if (!this._reversed) if (!this._hasPausedChild()) {\r
13045                     isComplete = true;\r
13046                     callback = "onComplete";\r
13047                     if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {\r
13048                         internalForce = true;\r
13049                         if (this._rawPrevTime > _tinyNum) {\r
13050                             callback = "onReverseComplete";\r
13051                         }\r
13052                     }\r
13053                 }\r
13054                 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
13055                 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
13056 \r
13057             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
13058                 this._totalTime = this._time = 0;\r
13059                 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {\r
13060                     callback = "onReverseComplete";\r
13061                     isComplete = this._reversed;\r
13062                 }\r
13063                 if (time < 0) {\r
13064                     this._active = false;\r
13065                     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
13066                         internalForce = true;\r
13067                     }\r
13068                     this._rawPrevTime = time;\r
13069                 } else {\r
13070                     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
13071 \r
13072                     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
13073                     if (!this._initted) {\r
13074                         internalForce = true;\r
13075                     }\r
13076                 }\r
13077 \r
13078             } else {\r
13079                 this._totalTime = this._time = this._rawPrevTime = time;\r
13080             }\r
13081             if ((this._time === prevTime || !this._first) && !force && !internalForce) {\r
13082                 return;\r
13083             } else if (!this._initted) {\r
13084                 this._initted = true;\r
13085             }\r
13086 \r
13087             if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {\r
13088                 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
13089             }\r
13090 \r
13091             if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {\r
13092                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
13093             }\r
13094 \r
13095             if (this._time >= prevTime) {\r
13096                 tween = this._first;\r
13097                 while (tween) {\r
13098                     next = tween._next; //record it here because the value could change after rendering...\r
13099                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13100                         break;\r
13101                     } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {\r
13102                         if (!tween._reversed) {\r
13103                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13104                         } else {\r
13105                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13106                         }\r
13107                     }\r
13108                     tween = next;\r
13109                 }\r
13110             } else {\r
13111                 tween = this._last;\r
13112                 while (tween) {\r
13113                     next = tween._prev; //record it here because the value could change after rendering...\r
13114                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13115                         break;\r
13116                     } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {\r
13117                         if (!tween._reversed) {\r
13118                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13119                         } else {\r
13120                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13121                         }\r
13122                     }\r
13123                     tween = next;\r
13124                 }\r
13125             }\r
13126 \r
13127             if (this._onUpdate) if (!suppressEvents) {\r
13128                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
13129             }\r
13130 \r
13131             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
13132                 if (isComplete) {\r
13133                     if (this._timeline.autoRemoveChildren) {\r
13134                         this._enabled(false, false);\r
13135                     }\r
13136                     this._active = false;\r
13137                 }\r
13138                 if (!suppressEvents && this.vars[callback]) {\r
13139                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
13140                 }\r
13141             }\r
13142         };\r
13143 \r
13144         p._hasPausedChild = function() {\r
13145             var tween = this._first;\r
13146             while (tween) {\r
13147                 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {\r
13148                     return true;\r
13149                 }\r
13150                 tween = tween._next;\r
13151             }\r
13152             return false;\r
13153         };\r
13154 \r
13155         p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {\r
13156             ignoreBeforeTime = ignoreBeforeTime || -9999999999;\r
13157             var a = [],\r
13158                 tween = this._first,\r
13159                 cnt = 0;\r
13160             while (tween) {\r
13161                 if (tween._startTime < ignoreBeforeTime) {\r
13162                     //do nothing\r
13163                 } else if (tween instanceof TweenLite) {\r
13164                     if (tweens !== false) {\r
13165                         a[cnt++] = tween;\r
13166                     }\r
13167                 } else {\r
13168                     if (timelines !== false) {\r
13169                         a[cnt++] = tween;\r
13170                     }\r
13171                     if (nested !== false) {\r
13172                         a = a.concat(tween.getChildren(true, tweens, timelines));\r
13173                         cnt = a.length;\r
13174                     }\r
13175                 }\r
13176                 tween = tween._next;\r
13177             }\r
13178             return a;\r
13179         };\r
13180 \r
13181         p.getTweensOf = function(target, nested) {\r
13182             var disabled = this._gc,\r
13183                 a = [],\r
13184                 cnt = 0,\r
13185                 tweens, i;\r
13186             if (disabled) {\r
13187                 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
13188             }\r
13189             tweens = TweenLite.getTweensOf(target);\r
13190             i = tweens.length;\r
13191             while (--i > -1) {\r
13192                 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {\r
13193                     a[cnt++] = tweens[i];\r
13194                 }\r
13195             }\r
13196             if (disabled) {\r
13197                 this._enabled(false, true);\r
13198             }\r
13199             return a;\r
13200         };\r
13201 \r
13202         p._contains = function(tween) {\r
13203             var tl = tween.timeline;\r
13204             while (tl) {\r
13205                 if (tl === this) {\r
13206                     return true;\r
13207                 }\r
13208                 tl = tl.timeline;\r
13209             }\r
13210             return false;\r
13211         };\r
13212 \r
13213         p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {\r
13214             ignoreBeforeTime = ignoreBeforeTime || 0;\r
13215             var tween = this._first,\r
13216                 labels = this._labels,\r
13217                 p;\r
13218             while (tween) {\r
13219                 if (tween._startTime >= ignoreBeforeTime) {\r
13220                     tween._startTime += amount;\r
13221                 }\r
13222                 tween = tween._next;\r
13223             }\r
13224             if (adjustLabels) {\r
13225                 for (p in labels) {\r
13226                     if (labels[p] >= ignoreBeforeTime) {\r
13227                         labels[p] += amount;\r
13228                     }\r
13229                 }\r
13230             }\r
13231             return this._uncache(true);\r
13232         };\r
13233 \r
13234         p._kill = function(vars, target) {\r
13235             if (!vars && !target) {\r
13236                 return this._enabled(false, false);\r
13237             }\r
13238             var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),\r
13239                 i = tweens.length,\r
13240                 changed = false;\r
13241             while (--i > -1) {\r
13242                 if (tweens[i]._kill(vars, target)) {\r
13243                     changed = true;\r
13244                 }\r
13245             }\r
13246             return changed;\r
13247         };\r
13248 \r
13249         p.clear = function(labels) {\r
13250             var tweens = this.getChildren(false, true, true),\r
13251                 i = tweens.length;\r
13252             this._time = this._totalTime = 0;\r
13253             while (--i > -1) {\r
13254                 tweens[i]._enabled(false, false);\r
13255             }\r
13256             if (labels !== false) {\r
13257                 this._labels = {};\r
13258             }\r
13259             return this._uncache(true);\r
13260         };\r
13261 \r
13262         p.invalidate = function() {\r
13263             var tween = this._first;\r
13264             while (tween) {\r
13265                 tween.invalidate();\r
13266                 tween = tween._next;\r
13267             }\r
13268             return this;\r
13269         };\r
13270 \r
13271         p._enabled = function(enabled, ignoreTimeline) {\r
13272             if (enabled === this._gc) {\r
13273                 var tween = this._first;\r
13274                 while (tween) {\r
13275                     tween._enabled(enabled, true);\r
13276                     tween = tween._next;\r
13277                 }\r
13278             }\r
13279             return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);\r
13280         };\r
13281 \r
13282         p.duration = function(value) {\r
13283             if (!arguments.length) {\r
13284                 if (this._dirty) {\r
13285                     this.totalDuration(); //just triggers recalculation\r
13286                 }\r
13287                 return this._duration;\r
13288             }\r
13289             if (this.duration() !== 0 && value !== 0) {\r
13290                 this.timeScale(this._duration / value);\r
13291             }\r
13292             return this;\r
13293         };\r
13294 \r
13295         p.totalDuration = function(value) {\r
13296             if (!arguments.length) {\r
13297                 if (this._dirty) {\r
13298                     var max = 0,\r
13299                         tween = this._last,\r
13300                         prevStart = 999999999999,\r
13301                         prev, end;\r
13302                     while (tween) {\r
13303                         prev = tween._prev; //record it here in case the tween changes position in the sequence...\r
13304                         if (tween._dirty) {\r
13305                             tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.\r
13306                         }\r
13307                         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
13308                             this.add(tween, tween._startTime - tween._delay);\r
13309                         } else {\r
13310                             prevStart = tween._startTime;\r
13311                         }\r
13312                         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
13313                             max -= tween._startTime;\r
13314                             if (this._timeline.smoothChildTiming) {\r
13315                                 this._startTime += tween._startTime / this._timeScale;\r
13316                             }\r
13317                             this.shiftChildren(-tween._startTime, false, -9999999999);\r
13318                             prevStart = 0;\r
13319                         }\r
13320                         end = tween._startTime + (tween._totalDuration / tween._timeScale);\r
13321                         if (end > max) {\r
13322                             max = end;\r
13323                         }\r
13324                         tween = prev;\r
13325                     }\r
13326                     this._duration = this._totalDuration = max;\r
13327                     this._dirty = false;\r
13328                 }\r
13329                 return this._totalDuration;\r
13330             }\r
13331             if (this.totalDuration() !== 0) if (value !== 0) {\r
13332                 this.timeScale(this._totalDuration / value);\r
13333             }\r
13334             return this;\r
13335         };\r
13336 \r
13337         p.usesFrames = function() {\r
13338             var tl = this._timeline;\r
13339             while (tl._timeline) {\r
13340                 tl = tl._timeline;\r
13341             }\r
13342             return (tl === Animation._rootFramesTimeline);\r
13343         };\r
13344 \r
13345         p.rawTime = function() {\r
13346             return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;\r
13347         };\r
13348 \r
13349         return TimelineLite;\r
13350 \r
13351     }, true);\r
13352     \r
13353 \r
13354 \r
13355 \r
13356 \r
13357 \r
13358 \r
13359 \r
13360     \r
13361     \r
13362     \r
13363     \r
13364     \r
13365 /*\r
13366  * ----------------------------------------------------------------\r
13367  * TimelineMax\r
13368  * ----------------------------------------------------------------\r
13369  */\r
13370     window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {\r
13371 \r
13372         var TimelineMax = function(vars) {\r
13373                 TimelineLite.call(this, vars);\r
13374                 this._repeat = this.vars.repeat || 0;\r
13375                 this._repeatDelay = this.vars.repeatDelay || 0;\r
13376                 this._cycle = 0;\r
13377                 this._yoyo = (this.vars.yoyo === true);\r
13378                 this._dirty = true;\r
13379             },\r
13380             _tinyNum = 0.0000000001,\r
13381             _blankArray = [],\r
13382             _easeNone = new Ease(null, null, 1, 0),\r
13383             p = TimelineMax.prototype = new TimelineLite();\r
13384 \r
13385         p.constructor = TimelineMax;\r
13386         p.kill()._gc = false;\r
13387         TimelineMax.version = "1.12.1";\r
13388 \r
13389         p.invalidate = function() {\r
13390             this._yoyo = (this.vars.yoyo === true);\r
13391             this._repeat = this.vars.repeat || 0;\r
13392             this._repeatDelay = this.vars.repeatDelay || 0;\r
13393             this._uncache(true);\r
13394             return TimelineLite.prototype.invalidate.call(this);\r
13395         };\r
13396 \r
13397         p.addCallback = function(callback, position, params, scope) {\r
13398             return this.add( TweenLite.delayedCall(0, callback, params, scope), position);\r
13399         };\r
13400 \r
13401         p.removeCallback = function(callback, position) {\r
13402             if (callback) {\r
13403                 if (position == null) {\r
13404                     this._kill(null, callback);\r
13405                 } else {\r
13406                     var a = this.getTweensOf(callback, false),\r
13407                         i = a.length,\r
13408                         time = this._parseTimeOrLabel(position);\r
13409                     while (--i > -1) {\r
13410                         if (a[i]._startTime === time) {\r
13411                             a[i]._enabled(false, false);\r
13412                         }\r
13413                     }\r
13414                 }\r
13415             }\r
13416             return this;\r
13417         };\r
13418 \r
13419         p.tweenTo = function(position, vars) {\r
13420             vars = vars || {};\r
13421             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
13422                 duration, p, t;\r
13423             for (p in vars) {\r
13424                 copy[p] = vars[p];\r
13425             }\r
13426             copy.time = this._parseTimeOrLabel(position);\r
13427             duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;\r
13428             t = new TweenLite(this, duration, copy);\r
13429             copy.onStart = function() {\r
13430                 t.target.paused(true);\r
13431                 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
13432                     t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );\r
13433                 }\r
13434                 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.\r
13435                     vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);\r
13436                 }\r
13437             };\r
13438             return t;\r
13439         };\r
13440 \r
13441         p.tweenFromTo = function(fromPosition, toPosition, vars) {\r
13442             vars = vars || {};\r
13443             fromPosition = this._parseTimeOrLabel(fromPosition);\r
13444             vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};\r
13445             vars.immediateRender = (vars.immediateRender !== false);\r
13446             var t = this.tweenTo(toPosition, vars);\r
13447             return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);\r
13448         };\r
13449 \r
13450         p.render = function(time, suppressEvents, force) {\r
13451             if (this._gc) {\r
13452                 this._enabled(true, false);\r
13453             }\r
13454             var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),\r
13455                 dur = this._duration,\r
13456                 prevTime = this._time,\r
13457                 prevTotalTime = this._totalTime,\r
13458                 prevStart = this._startTime,\r
13459                 prevTimeScale = this._timeScale,\r
13460                 prevRawPrevTime = this._rawPrevTime,\r
13461                 prevPaused = this._paused,\r
13462                 prevCycle = this._cycle,\r
13463                 tween, isComplete, next, callback, internalForce, cycleDuration;\r
13464             if (time >= totalDur) {\r
13465                 if (!this._locked) {\r
13466                     this._totalTime = totalDur;\r
13467                     this._cycle = this._repeat;\r
13468                 }\r
13469                 if (!this._reversed) if (!this._hasPausedChild()) {\r
13470                     isComplete = true;\r
13471                     callback = "onComplete";\r
13472                     if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {\r
13473                         internalForce = true;\r
13474                         if (prevRawPrevTime > _tinyNum) {\r
13475                             callback = "onReverseComplete";\r
13476                         }\r
13477                     }\r
13478                 }\r
13479                 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
13480                 if (this._yoyo && (this._cycle & 1) !== 0) {\r
13481                     this._time = time = 0;\r
13482                 } else {\r
13483                     this._time = dur;\r
13484                     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
13485                 }\r
13486 \r
13487             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
13488                 if (!this._locked) {\r
13489                     this._totalTime = this._cycle = 0;\r
13490                 }\r
13491                 this._time = 0;\r
13492                 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
13493                     callback = "onReverseComplete";\r
13494                     isComplete = this._reversed;\r
13495                 }\r
13496                 if (time < 0) {\r
13497                     this._active = false;\r
13498                     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
13499                         internalForce = true;\r
13500                     }\r
13501                     this._rawPrevTime = time;\r
13502                 } else {\r
13503                     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
13504                     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
13505                     if (!this._initted) {\r
13506                         internalForce = true;\r
13507                     }\r
13508                 }\r
13509 \r
13510             } else {\r
13511                 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
13512                     internalForce = true;\r
13513                 }\r
13514                 this._time = this._rawPrevTime = time;\r
13515                 if (!this._locked) {\r
13516                     this._totalTime = time;\r
13517                     if (this._repeat !== 0) {\r
13518                         cycleDuration = dur + this._repeatDelay;\r
13519                         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
13520                         if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {\r
13521                             this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)\r
13522                         }\r
13523                         this._time = this._totalTime - (this._cycle * cycleDuration);\r
13524                         if (this._yoyo) if ((this._cycle & 1) !== 0) {\r
13525                             this._time = dur - this._time;\r
13526                         }\r
13527                         if (this._time > dur) {\r
13528                             this._time = dur;\r
13529                             time = dur + 0.0001; //to avoid occasional floating point rounding error\r
13530                         } else if (this._time < 0) {\r
13531                             this._time = time = 0;\r
13532                         } else {\r
13533                             time = this._time;\r
13534                         }\r
13535                     }\r
13536                 }\r
13537             }\r
13538 \r
13539             if (this._cycle !== prevCycle) if (!this._locked) {\r
13540                 /*\r
13541                 make sure children at the end/beginning of the timeline are rendered properly. If, for example,\r
13542                 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which\r
13543                 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there\r
13544                 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So\r
13545                 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must\r
13546                 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.\r
13547                 */\r
13548                 var backwards = (this._yoyo && (prevCycle & 1) !== 0),\r
13549                     wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),\r
13550                     recTotalTime = this._totalTime,\r
13551                     recCycle = this._cycle,\r
13552                     recRawPrevTime = this._rawPrevTime,\r
13553                     recTime = this._time;\r
13554 \r
13555                 this._totalTime = prevCycle * dur;\r
13556                 if (this._cycle < prevCycle) {\r
13557                     backwards = !backwards;\r
13558                 } else {\r
13559                     this._totalTime += dur;\r
13560                 }\r
13561                 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
13562 \r
13563                 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;\r
13564                 this._cycle = prevCycle;\r
13565                 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()\r
13566                 prevTime = (backwards) ? 0 : dur;\r
13567                 this.render(prevTime, suppressEvents, (dur === 0));\r
13568                 if (!suppressEvents) if (!this._gc) {\r
13569                     if (this.vars.onRepeat) {\r
13570                         this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);\r
13571                     }\r
13572                 }\r
13573                 if (wrap) {\r
13574                     prevTime = (backwards) ? dur + 0.0001 : -0.0001;\r
13575                     this.render(prevTime, true, false);\r
13576                 }\r
13577                 this._locked = false;\r
13578                 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)\r
13579                     return;\r
13580                 }\r
13581                 this._time = recTime;\r
13582                 this._totalTime = recTotalTime;\r
13583                 this._cycle = recCycle;\r
13584                 this._rawPrevTime = recRawPrevTime;\r
13585             }\r
13586 \r
13587             if ((this._time === prevTime || !this._first) && !force && !internalForce) {\r
13588                 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
13589                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
13590                 }\r
13591                 return;\r
13592             } else if (!this._initted) {\r
13593                 this._initted = true;\r
13594             }\r
13595 \r
13596             if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {\r
13597                 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
13598             }\r
13599 \r
13600             if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {\r
13601                 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
13602             }\r
13603 \r
13604             if (this._time >= prevTime) {\r
13605                 tween = this._first;\r
13606                 while (tween) {\r
13607                     next = tween._next; //record it here because the value could change after rendering...\r
13608                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13609                         break;\r
13610                     } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {\r
13611                         if (!tween._reversed) {\r
13612                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13613                         } else {\r
13614                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13615                         }\r
13616 \r
13617                     }\r
13618                     tween = next;\r
13619                 }\r
13620             } else {\r
13621                 tween = this._last;\r
13622                 while (tween) {\r
13623                     next = tween._prev; //record it here because the value could change after rendering...\r
13624                     if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering\r
13625                         break;\r
13626                     } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {\r
13627                         if (!tween._reversed) {\r
13628                             tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
13629                         } else {\r
13630                             tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
13631                         }\r
13632                     }\r
13633                     tween = next;\r
13634                 }\r
13635             }\r
13636 \r
13637             if (this._onUpdate) if (!suppressEvents) {\r
13638                 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
13639             }\r
13640             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
13641                 if (isComplete) {\r
13642                     if (this._timeline.autoRemoveChildren) {\r
13643                         this._enabled(false, false);\r
13644                     }\r
13645                     this._active = false;\r
13646                 }\r
13647                 if (!suppressEvents && this.vars[callback]) {\r
13648                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
13649                 }\r
13650             }\r
13651         };\r
13652 \r
13653         p.getActive = function(nested, tweens, timelines) {\r
13654             if (nested == null) {\r
13655                 nested = true;\r
13656             }\r
13657             if (tweens == null) {\r
13658                 tweens = true;\r
13659             }\r
13660             if (timelines == null) {\r
13661                 timelines = false;\r
13662             }\r
13663             var a = [],\r
13664                 all = this.getChildren(nested, tweens, timelines),\r
13665                 cnt = 0,\r
13666                 l = all.length,\r
13667                 i, tween;\r
13668             for (i = 0; i < l; i++) {\r
13669                 tween = all[i];\r
13670                 if (tween.isActive()) {\r
13671                     a[cnt++] = tween;\r
13672                 }\r
13673             }\r
13674             return a;\r
13675         };\r
13676 \r
13677 \r
13678         p.getLabelAfter = function(time) {\r
13679             if (!time) if (time !== 0) { //faster than isNan()\r
13680                 time = this._time;\r
13681             }\r
13682             var labels = this.getLabelsArray(),\r
13683                 l = labels.length,\r
13684                 i;\r
13685             for (i = 0; i < l; i++) {\r
13686                 if (labels[i].time > time) {\r
13687                     return labels[i].name;\r
13688                 }\r
13689             }\r
13690             return null;\r
13691         };\r
13692 \r
13693         p.getLabelBefore = function(time) {\r
13694             if (time == null) {\r
13695                 time = this._time;\r
13696             }\r
13697             var labels = this.getLabelsArray(),\r
13698                 i = labels.length;\r
13699             while (--i > -1) {\r
13700                 if (labels[i].time < time) {\r
13701                     return labels[i].name;\r
13702                 }\r
13703             }\r
13704             return null;\r
13705         };\r
13706 \r
13707         p.getLabelsArray = function() {\r
13708             var a = [],\r
13709                 cnt = 0,\r
13710                 p;\r
13711             for (p in this._labels) {\r
13712                 a[cnt++] = {time:this._labels[p], name:p};\r
13713             }\r
13714             a.sort(function(a,b) {\r
13715                 return a.time - b.time;\r
13716             });\r
13717             return a;\r
13718         };\r
13719 \r
13720 \r
13721 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------\r
13722 \r
13723         p.progress = function(value) {\r
13724             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
13725         };\r
13726 \r
13727         p.totalProgress = function(value) {\r
13728             return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);\r
13729         };\r
13730 \r
13731         p.totalDuration = function(value) {\r
13732             if (!arguments.length) {\r
13733                 if (this._dirty) {\r
13734                     TimelineLite.prototype.totalDuration.call(this); //just forces refresh\r
13735                     //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.\r
13736                     this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);\r
13737                 }\r
13738                 return this._totalDuration;\r
13739             }\r
13740             return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );\r
13741         };\r
13742 \r
13743         p.time = function(value, suppressEvents) {\r
13744             if (!arguments.length) {\r
13745                 return this._time;\r
13746             }\r
13747             if (this._dirty) {\r
13748                 this.totalDuration();\r
13749             }\r
13750             if (value > this._duration) {\r
13751                 value = this._duration;\r
13752             }\r
13753             if (this._yoyo && (this._cycle & 1) !== 0) {\r
13754                 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));\r
13755             } else if (this._repeat !== 0) {\r
13756                 value += this._cycle * (this._duration + this._repeatDelay);\r
13757             }\r
13758             return this.totalTime(value, suppressEvents);\r
13759         };\r
13760 \r
13761         p.repeat = function(value) {\r
13762             if (!arguments.length) {\r
13763                 return this._repeat;\r
13764             }\r
13765             this._repeat = value;\r
13766             return this._uncache(true);\r
13767         };\r
13768 \r
13769         p.repeatDelay = function(value) {\r
13770             if (!arguments.length) {\r
13771                 return this._repeatDelay;\r
13772             }\r
13773             this._repeatDelay = value;\r
13774             return this._uncache(true);\r
13775         };\r
13776 \r
13777         p.yoyo = function(value) {\r
13778             if (!arguments.length) {\r
13779                 return this._yoyo;\r
13780             }\r
13781             this._yoyo = value;\r
13782             return this;\r
13783         };\r
13784 \r
13785         p.currentLabel = function(value) {\r
13786             if (!arguments.length) {\r
13787                 return this.getLabelBefore(this._time + 0.00000001);\r
13788             }\r
13789             return this.seek(value, true);\r
13790         };\r
13791 \r
13792         return TimelineMax;\r
13793 \r
13794     }, true);\r
13795     \r
13796 \r
13797 \r
13798 \r
13799 \r
13800     \r
13801     \r
13802     \r
13803     \r
13804     \r
13805     \r
13806     \r
13807 /*\r
13808  * ----------------------------------------------------------------\r
13809  * BezierPlugin\r
13810  * ----------------------------------------------------------------\r
13811  */\r
13812     (function() {\r
13813 \r
13814         var _RAD2DEG = 180 / Math.PI,\r
13815             _r1 = [],\r
13816             _r2 = [],\r
13817             _r3 = [],\r
13818             _corProps = {},\r
13819             Segment = function(a, b, c, d) {\r
13820                 this.a = a;\r
13821                 this.b = b;\r
13822                 this.c = c;\r
13823                 this.d = d;\r
13824                 this.da = d - a;\r
13825                 this.ca = c - a;\r
13826                 this.ba = b - a;\r
13827             },\r
13828             _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",\r
13829             cubicToQuadratic = function(a, b, c, d) {\r
13830                 var q1 = {a:a},\r
13831                     q2 = {},\r
13832                     q3 = {},\r
13833                     q4 = {c:d},\r
13834                     mab = (a + b) / 2,\r
13835                     mbc = (b + c) / 2,\r
13836                     mcd = (c + d) / 2,\r
13837                     mabc = (mab + mbc) / 2,\r
13838                     mbcd = (mbc + mcd) / 2,\r
13839                     m8 = (mbcd - mabc) / 8;\r
13840                 q1.b = mab + (a - mab) / 4;\r
13841                 q2.b = mabc + m8;\r
13842                 q1.c = q2.a = (q1.b + q2.b) / 2;\r
13843                 q2.c = q3.a = (mabc + mbcd) / 2;\r
13844                 q3.b = mbcd - m8;\r
13845                 q4.b = mcd + (d - mcd) / 4;\r
13846                 q3.c = q4.a = (q3.b + q4.b) / 2;\r
13847                 return [q1, q2, q3, q4];\r
13848             },\r
13849             _calculateControlPoints = function(a, curviness, quad, basic, correlate) {\r
13850                 var l = a.length - 1,\r
13851                     ii = 0,\r
13852                     cp1 = a[0].a,\r
13853                     i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;\r
13854                 for (i = 0; i < l; i++) {\r
13855                     seg = a[ii];\r
13856                     p1 = seg.a;\r
13857                     p2 = seg.d;\r
13858                     p3 = a[ii+1].d;\r
13859 \r
13860                     if (correlate) {\r
13861                         r1 = _r1[i];\r
13862                         r2 = _r2[i];\r
13863                         tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);\r
13864                         m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));\r
13865                         m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));\r
13866                         mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));\r
13867                     } else {\r
13868                         m1 = p2 - (p2 - p1) * curviness * 0.5;\r
13869                         m2 = p2 + (p3 - p2) * curviness * 0.5;\r
13870                         mm = p2 - (m1 + m2) / 2;\r
13871                     }\r
13872                     m1 += mm;\r
13873                     m2 += mm;\r
13874 \r
13875                     seg.c = cp2 = m1;\r
13876                     if (i !== 0) {\r
13877                         seg.b = cp1;\r
13878                     } else {\r
13879                         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
13880                     }\r
13881 \r
13882                     seg.da = p2 - p1;\r
13883                     seg.ca = cp2 - p1;\r
13884                     seg.ba = cp1 - p1;\r
13885 \r
13886                     if (quad) {\r
13887                         qb = cubicToQuadratic(p1, cp1, cp2, p2);\r
13888                         a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);\r
13889                         ii += 4;\r
13890                     } else {\r
13891                         ii++;\r
13892                     }\r
13893 \r
13894                     cp1 = m2;\r
13895                 }\r
13896                 seg = a[ii];\r
13897                 seg.b = cp1;\r
13898                 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
13899                 seg.da = seg.d - seg.a;\r
13900                 seg.ca = seg.c - seg.a;\r
13901                 seg.ba = cp1 - seg.a;\r
13902                 if (quad) {\r
13903                     qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);\r
13904                     a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);\r
13905                 }\r
13906             },\r
13907             _parseAnchors = function(values, p, correlate, prepend) {\r
13908                 var a = [],\r
13909                     l, i, p1, p2, p3, tmp;\r
13910                 if (prepend) {\r
13911                     values = [prepend].concat(values);\r
13912                     i = values.length;\r
13913                     while (--i > -1) {\r
13914                         if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {\r
13915                             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
13916                         }\r
13917                     }\r
13918                 }\r
13919                 l = values.length - 2;\r
13920                 if (l < 0) {\r
13921                     a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);\r
13922                     return a;\r
13923                 }\r
13924                 for (i = 0; i < l; i++) {\r
13925                     p1 = values[i][p];\r
13926                     p2 = values[i+1][p];\r
13927                     a[i] = new Segment(p1, 0, 0, p2);\r
13928                     if (correlate) {\r
13929                         p3 = values[i+2][p];\r
13930                         _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);\r
13931                         _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);\r
13932                     }\r
13933                 }\r
13934                 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);\r
13935                 return a;\r
13936             },\r
13937             bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {\r
13938                 var obj = {},\r
13939                     props = [],\r
13940                     first = prepend || values[0],\r
13941                     i, p, a, j, r, l, seamless, last;\r
13942                 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;\r
13943                 if (curviness == null) {\r
13944                     curviness = 1;\r
13945                 }\r
13946                 for (p in values[0]) {\r
13947                     props.push(p);\r
13948                 }\r
13949                 //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
13950                 if (values.length > 1) {\r
13951                     last = values[values.length - 1];\r
13952                     seamless = true;\r
13953                     i = props.length;\r
13954                     while (--i > -1) {\r
13955                         p = props[i];\r
13956                         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
13957                             seamless = false;\r
13958                             break;\r
13959                         }\r
13960                     }\r
13961                     if (seamless) {\r
13962                         values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens\r
13963                         if (prepend) {\r
13964                             values.unshift(prepend);\r
13965                         }\r
13966                         values.push(values[1]);\r
13967                         prepend = values[values.length - 3];\r
13968                     }\r
13969                 }\r
13970                 _r1.length = _r2.length = _r3.length = 0;\r
13971                 i = props.length;\r
13972                 while (--i > -1) {\r
13973                     p = props[i];\r
13974                     _corProps[p] = (correlate.indexOf(","+p+",") !== -1);\r
13975                     obj[p] = _parseAnchors(values, p, _corProps[p], prepend);\r
13976                 }\r
13977                 i = _r1.length;\r
13978                 while (--i > -1) {\r
13979                     _r1[i] = Math.sqrt(_r1[i]);\r
13980                     _r2[i] = Math.sqrt(_r2[i]);\r
13981                 }\r
13982                 if (!basic) {\r
13983                     i = props.length;\r
13984                     while (--i > -1) {\r
13985                         if (_corProps[p]) {\r
13986                             a = obj[props[i]];\r
13987                             l = a.length - 1;\r
13988                             for (j = 0; j < l; j++) {\r
13989                                 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];\r
13990                                 _r3[j] = (_r3[j] || 0) + r * r;\r
13991                             }\r
13992                         }\r
13993                     }\r
13994                     i = _r3.length;\r
13995                     while (--i > -1) {\r
13996                         _r3[i] = Math.sqrt(_r3[i]);\r
13997                     }\r
13998                 }\r
13999                 i = props.length;\r
14000                 j = quadratic ? 4 : 1;\r
14001                 while (--i > -1) {\r
14002                     p = props[i];\r
14003                     a = obj[p];\r
14004                     _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
14005                     if (seamless) {\r
14006                         a.splice(0, j);\r
14007                         a.splice(a.length - j, j);\r
14008                     }\r
14009                 }\r
14010                 return obj;\r
14011             },\r
14012             _parseBezierData = function(values, type, prepend) {\r
14013                 type = type || "soft";\r
14014                 var obj = {},\r
14015                     inc = (type === "cubic") ? 3 : 2,\r
14016                     soft = (type === "soft"),\r
14017                     props = [],\r
14018                     a, b, c, d, cur, i, j, l, p, cnt, tmp;\r
14019                 if (soft && prepend) {\r
14020                     values = [prepend].concat(values);\r
14021                 }\r
14022                 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }\r
14023                 for (p in values[0]) {\r
14024                     props.push(p);\r
14025                 }\r
14026                 i = props.length;\r
14027                 while (--i > -1) {\r
14028                     p = props[i];\r
14029                     obj[p] = cur = [];\r
14030                     cnt = 0;\r
14031                     l = values.length;\r
14032                     for (j = 0; j < l; j++) {\r
14033                         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
14034                         if (soft) if (j > 1) if (j < l - 1) {\r
14035                             cur[cnt++] = (a + cur[cnt-2]) / 2;\r
14036                         }\r
14037                         cur[cnt++] = a;\r
14038                     }\r
14039                     l = cnt - inc + 1;\r
14040                     cnt = 0;\r
14041                     for (j = 0; j < l; j += inc) {\r
14042                         a = cur[j];\r
14043                         b = cur[j+1];\r
14044                         c = cur[j+2];\r
14045                         d = (inc === 2) ? 0 : cur[j+3];\r
14046                         cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);\r
14047                     }\r
14048                     cur.length = cnt;\r
14049                 }\r
14050                 return obj;\r
14051             },\r
14052             _addCubicLengths = function(a, steps, resolution) {\r
14053                 var inc = 1 / resolution,\r
14054                     j = a.length,\r
14055                     d, d1, s, da, ca, ba, p, i, inv, bez, index;\r
14056                 while (--j > -1) {\r
14057                     bez = a[j];\r
14058                     s = bez.a;\r
14059                     da = bez.d - s;\r
14060                     ca = bez.c - s;\r
14061                     ba = bez.b - s;\r
14062                     d = d1 = 0;\r
14063                     for (i = 1; i <= resolution; i++) {\r
14064                         p = inc * i;\r
14065                         inv = 1 - p;\r
14066                         d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);\r
14067                         index = j * resolution + i - 1;\r
14068                         steps[index] = (steps[index] || 0) + d * d;\r
14069                     }\r
14070                 }\r
14071             },\r
14072             _parseLengthData = function(obj, resolution) {\r
14073                 resolution = resolution >> 0 || 6;\r
14074                 var a = [],\r
14075                     lengths = [],\r
14076                     d = 0,\r
14077                     total = 0,\r
14078                     threshold = resolution - 1,\r
14079                     segments = [],\r
14080                     curLS = [], //current length segments array\r
14081                     p, i, l, index;\r
14082                 for (p in obj) {\r
14083                     _addCubicLengths(obj[p], a, resolution);\r
14084                 }\r
14085                 l = a.length;\r
14086                 for (i = 0; i < l; i++) {\r
14087                     d += Math.sqrt(a[i]);\r
14088                     index = i % resolution;\r
14089                     curLS[index] = d;\r
14090                     if (index === threshold) {\r
14091                         total += d;\r
14092                         index = (i / resolution) >> 0;\r
14093                         segments[index] = curLS;\r
14094                         lengths[index] = total;\r
14095                         d = 0;\r
14096                         curLS = [];\r
14097                     }\r
14098                 }\r
14099                 return {length:total, lengths:lengths, segments:segments};\r
14100             },\r
14101 \r
14102 \r
14103 \r
14104             BezierPlugin = window._gsDefine.plugin({\r
14105                     propName: "bezier",\r
14106                     priority: -1,\r
14107                     version: "1.3.2",\r
14108                     API: 2,\r
14109                     global:true,\r
14110 \r
14111                     //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
14112                     init: function(target, vars, tween) {\r
14113                         this._target = target;\r
14114                         if (vars instanceof Array) {\r
14115                             vars = {values:vars};\r
14116                         }\r
14117                         this._func = {};\r
14118                         this._round = {};\r
14119                         this._props = [];\r
14120                         this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);\r
14121                         var values = vars.values || [],\r
14122                             first = {},\r
14123                             second = values[0],\r
14124                             autoRotate = vars.autoRotate || tween.vars.orientToBezier,\r
14125                             p, isFunc, i, j, prepend;\r
14126 \r
14127                         this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;\r
14128                         for (p in second) {\r
14129                             this._props.push(p);\r
14130                         }\r
14131 \r
14132                         i = this._props.length;\r
14133                         while (--i > -1) {\r
14134                             p = this._props[i];\r
14135 \r
14136                             this._overwriteProps.push(p);\r
14137                             isFunc = this._func[p] = (typeof(target[p]) === "function");\r
14138                             first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();\r
14139                             if (!prepend) if (first[p] !== values[0][p]) {\r
14140                                 prepend = first;\r
14141                             }\r
14142                         }\r
14143                         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
14144                         this._segCount = this._beziers[p].length;\r
14145 \r
14146                         if (this._timeRes) {\r
14147                             var ld = _parseLengthData(this._beziers, this._timeRes);\r
14148                             this._length = ld.length;\r
14149                             this._lengths = ld.lengths;\r
14150                             this._segments = ld.segments;\r
14151                             this._l1 = this._li = this._s1 = this._si = 0;\r
14152                             this._l2 = this._lengths[0];\r
14153                             this._curSeg = this._segments[0];\r
14154                             this._s2 = this._curSeg[0];\r
14155                             this._prec = 1 / this._curSeg.length;\r
14156                         }\r
14157 \r
14158                         if ((autoRotate = this._autoRotate)) {\r
14159                             this._initialRotations = [];\r
14160                             if (!(autoRotate[0] instanceof Array)) {\r
14161                                 this._autoRotate = autoRotate = [autoRotate];\r
14162                             }\r
14163                             i = autoRotate.length;\r
14164                             while (--i > -1) {\r
14165                                 for (j = 0; j < 3; j++) {\r
14166                                     p = autoRotate[i][j];\r
14167                                     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
14168                                 }\r
14169                                 p = autoRotate[i][2];\r
14170                                 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];\r
14171                             }\r
14172                         }\r
14173                         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
14174                         return true;\r
14175                     },\r
14176 \r
14177                     //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
14178                     set: function(v) {\r
14179                         var segments = this._segCount,\r
14180                             func = this._func,\r
14181                             target = this._target,\r
14182                             notStart = (v !== this._startRatio),\r
14183                             curIndex, inv, i, p, b, t, val, l, lengths, curSeg;\r
14184                         if (!this._timeRes) {\r
14185                             curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;\r
14186                             t = (v - (curIndex * (1 / segments))) * segments;\r
14187                         } else {\r
14188                             lengths = this._lengths;\r
14189                             curSeg = this._curSeg;\r
14190                             v *= this._length;\r
14191                             i = this._li;\r
14192                             //find the appropriate segment (if the currently cached one isn't correct)\r
14193                             if (v > this._l2 && i < segments - 1) {\r
14194                                 l = segments - 1;\r
14195                                 while (i < l && (this._l2 = lengths[++i]) <= v) {   }\r
14196                                 this._l1 = lengths[i-1];\r
14197                                 this._li = i;\r
14198                                 this._curSeg = curSeg = this._segments[i];\r
14199                                 this._s2 = curSeg[(this._s1 = this._si = 0)];\r
14200                             } else if (v < this._l1 && i > 0) {\r
14201                                 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }\r
14202                                 if (i === 0 && v < this._l1) {\r
14203                                     this._l1 = 0;\r
14204                                 } else {\r
14205                                     i++;\r
14206                                 }\r
14207                                 this._l2 = lengths[i];\r
14208                                 this._li = i;\r
14209                                 this._curSeg = curSeg = this._segments[i];\r
14210                                 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;\r
14211                                 this._s2 = curSeg[this._si];\r
14212                             }\r
14213                             curIndex = i;\r
14214                             //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)\r
14215                             v -= this._l1;\r
14216                             i = this._si;\r
14217                             if (v > this._s2 && i < curSeg.length - 1) {\r
14218                                 l = curSeg.length - 1;\r
14219                                 while (i < l && (this._s2 = curSeg[++i]) <= v) {    }\r
14220                                 this._s1 = curSeg[i-1];\r
14221                                 this._si = i;\r
14222                             } else if (v < this._s1 && i > 0) {\r
14223                                 while (i > 0 && (this._s1 = curSeg[--i]) >= v) {    }\r
14224                                 if (i === 0 && v < this._s1) {\r
14225                                     this._s1 = 0;\r
14226                                 } else {\r
14227                                     i++;\r
14228                                 }\r
14229                                 this._s2 = curSeg[i];\r
14230                                 this._si = i;\r
14231                             }\r
14232                             t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;\r
14233                         }\r
14234                         inv = 1 - t;\r
14235 \r
14236                         i = this._props.length;\r
14237                         while (--i > -1) {\r
14238                             p = this._props[i];\r
14239                             b = this._beziers[p][curIndex];\r
14240                             val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;\r
14241                             if (this._round[p]) {\r
14242                                 val = Math.round(val);\r
14243                             }\r
14244                             if (func[p]) {\r
14245                                 target[p](val);\r
14246                             } else {\r
14247                                 target[p] = val;\r
14248                             }\r
14249                         }\r
14250 \r
14251                         if (this._autoRotate) {\r
14252                             var ar = this._autoRotate,\r
14253                                 b2, x1, y1, x2, y2, add, conv;\r
14254                             i = ar.length;\r
14255                             while (--i > -1) {\r
14256                                 p = ar[i][2];\r
14257                                 add = ar[i][3] || 0;\r
14258                                 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;\r
14259                                 b = this._beziers[ar[i][0]];\r
14260                                 b2 = this._beziers[ar[i][1]];\r
14261 \r
14262                                 if (b && b2) { //in case one of the properties got overwritten.\r
14263                                     b = b[curIndex];\r
14264                                     b2 = b2[curIndex];\r
14265 \r
14266                                     x1 = b.a + (b.b - b.a) * t;\r
14267                                     x2 = b.b + (b.c - b.b) * t;\r
14268                                     x1 += (x2 - x1) * t;\r
14269                                     x2 += ((b.c + (b.d - b.c) * t) - x2) * t;\r
14270 \r
14271                                     y1 = b2.a + (b2.b - b2.a) * t;\r
14272                                     y2 = b2.b + (b2.c - b2.b) * t;\r
14273                                     y1 += (y2 - y1) * t;\r
14274                                     y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;\r
14275 \r
14276                                     val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];\r
14277 \r
14278                                     if (func[p]) {\r
14279                                         target[p](val);\r
14280                                     } else {\r
14281                                         target[p] = val;\r
14282                                     }\r
14283                                 }\r
14284                             }\r
14285                         }\r
14286                     }\r
14287             }),\r
14288             p = BezierPlugin.prototype;\r
14289 \r
14290 \r
14291         BezierPlugin.bezierThrough = bezierThrough;\r
14292         BezierPlugin.cubicToQuadratic = cubicToQuadratic;\r
14293         BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite\r
14294         BezierPlugin.quadraticToCubic = function(a, b, c) {\r
14295             return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);\r
14296         };\r
14297 \r
14298         BezierPlugin._cssRegister = function() {\r
14299             var CSSPlugin = window._gsDefine.globals.CSSPlugin;\r
14300             if (!CSSPlugin) {\r
14301                 return;\r
14302             }\r
14303             var _internals = CSSPlugin._internals,\r
14304                 _parseToProxy = _internals._parseToProxy,\r
14305                 _setPluginRatio = _internals._setPluginRatio,\r
14306                 CSSPropTween = _internals.CSSPropTween;\r
14307             _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {\r
14308                 if (e instanceof Array) {\r
14309                     e = {values:e};\r
14310                 }\r
14311                 plugin = new BezierPlugin();\r
14312                 var values = e.values,\r
14313                     l = values.length - 1,\r
14314                     pluginValues = [],\r
14315                     v = {},\r
14316                     i, p, data;\r
14317                 if (l < 0) {\r
14318                     return pt;\r
14319                 }\r
14320                 for (i = 0; i <= l; i++) {\r
14321                     data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));\r
14322                     pluginValues[i] = data.end;\r
14323                 }\r
14324                 for (p in e) {\r
14325                     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
14326                 }\r
14327                 v.values = pluginValues;\r
14328                 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);\r
14329                 pt.data = data;\r
14330                 pt.plugin = plugin;\r
14331                 pt.setRatio = _setPluginRatio;\r
14332                 if (v.autoRotate === 0) {\r
14333                     v.autoRotate = true;\r
14334                 }\r
14335                 if (v.autoRotate && !(v.autoRotate instanceof Array)) {\r
14336                     i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);\r
14337                     v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;\r
14338                 }\r
14339                 if (v.autoRotate) {\r
14340                     if (!cssp._transform) {\r
14341                         cssp._enableTransforms(false);\r
14342                     }\r
14343                     data.autoRotate = cssp._target._gsTransform;\r
14344                 }\r
14345                 plugin._onInitTween(data.proxy, v, cssp._tween);\r
14346                 return pt;\r
14347             }});\r
14348         };\r
14349 \r
14350         p._roundProps = function(lookup, value) {\r
14351             var op = this._overwriteProps,\r
14352                 i = op.length;\r
14353             while (--i > -1) {\r
14354                 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {\r
14355                     this._round[op[i]] = value;\r
14356                 }\r
14357             }\r
14358         };\r
14359 \r
14360         p._kill = function(lookup) {\r
14361             var a = this._props,\r
14362                 p, i;\r
14363             for (p in this._beziers) {\r
14364                 if (p in lookup) {\r
14365                     delete this._beziers[p];\r
14366                     delete this._func[p];\r
14367                     i = a.length;\r
14368                     while (--i > -1) {\r
14369                         if (a[i] === p) {\r
14370                             a.splice(i, 1);\r
14371                         }\r
14372                     }\r
14373                 }\r
14374             }\r
14375             return this._super._kill.call(this, lookup);\r
14376         };\r
14377 \r
14378     }());\r
14379 \r
14380 \r
14381 \r
14382 \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  * CSSPlugin\r
14396  * ----------------------------------------------------------------\r
14397  */\r
14398     window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {\r
14399 \r
14400         /** @constructor **/\r
14401         var CSSPlugin = function() {\r
14402                 TweenPlugin.call(this, "css");\r
14403                 this._overwriteProps.length = 0;\r
14404                 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)\r
14405             },\r
14406             _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
14407             _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
14408             _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter\r
14409             _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
14410             _specialProps = {},\r
14411             p = CSSPlugin.prototype = new TweenPlugin("css");\r
14412 \r
14413         p.constructor = CSSPlugin;\r
14414         CSSPlugin.version = "1.12.1";\r
14415         CSSPlugin.API = 2;\r
14416         CSSPlugin.defaultTransformPerspective = 0;\r
14417         CSSPlugin.defaultSkewType = "compensated";\r
14418         p = "px"; //we'll reuse the "p" variable to keep file size down\r
14419         CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};\r
14420 \r
14421 \r
14422         var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,\r
14423             _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,\r
14424             _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
14425             _NaNExp = /[^\d\-\.]/g,\r
14426             _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,\r
14427             _opacityExp = /opacity *= *([^)]*)/i,\r
14428             _opacityValExp = /opacity:([^;]*)/i,\r
14429             _alphaFilterExp = /alpha\(opacity *=.+?\)/i,\r
14430             _rgbhslExp = /^(rgb|hsl)/,\r
14431             _capsExp = /([A-Z])/g,\r
14432             _camelExp = /-([a-z])/gi,\r
14433             _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
14434             _camelFunc = function(s, g) { return g.toUpperCase(); },\r
14435             _horizExp = /(?:Left|Right|Width)/i,\r
14436             _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,\r
14437             _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,\r
14438             _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis\r
14439             _DEG2RAD = Math.PI / 180,\r
14440             _RAD2DEG = 180 / Math.PI,\r
14441             _forcePT = {},\r
14442             _doc = document,\r
14443             _tempDiv = _doc.createElement("div"),\r
14444             _tempImg = _doc.createElement("img"),\r
14445             _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins\r
14446             _agent = navigator.userAgent,\r
14447             _autoRound,\r
14448             _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
14449 \r
14450             _isSafari,\r
14451             _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
14452             _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
14453             _ieVers,\r
14454             _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
14455                 var i = _agent.indexOf("Android"),\r
14456                     d = _doc.createElement("div"), a;\r
14457 \r
14458                 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));\r
14459                 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));\r
14460                 _isFirefox = (_agent.indexOf("Firefox") !== -1);\r
14461 \r
14462                 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {\r
14463                     _ieVers = parseFloat( RegExp.$1 );\r
14464                 }\r
14465 \r
14466                 d.innerHTML = "<a title='' style='top:1px;opacity:.55;'>a</a>";\r
14467                 a = d.getElementsByTagName("a")[0];\r
14468                 return a ? /^0.55/.test(a.style.opacity) : false;\r
14469             }()),\r
14470             _getIEOpacity = function(v) {\r
14471                 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);\r
14472             },\r
14473             _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.\r
14474                 if (window.console) {\r
14475                     //console.log(s);\r
14476                 }\r
14477             },\r
14478             _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"\r
14479             _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".\r
14480 \r
14481             // @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
14482             _checkPropPrefix = function(p, e) {\r
14483                 e = e || _tempDiv;\r
14484                 var s = e.style,\r
14485                     a, i;\r
14486                 if (s[p] !== undefined) {\r
14487                     return p;\r
14488                 }\r
14489                 p = p.charAt(0).toUpperCase() + p.substr(1);\r
14490                 a = ["O","Moz","ms","Ms","Webkit"];\r
14491                 i = 5;\r
14492                 while (--i > -1 && s[a[i]+p] === undefined) { }\r
14493                 if (i >= 0) {\r
14494                     _prefix = (i === 3) ? "ms" : a[i];\r
14495                     _prefixCSS = "-" + _prefix.toLowerCase() + "-";\r
14496                     return _prefix + p;\r
14497                 }\r
14498                 return null;\r
14499             },\r
14500 \r
14501             _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},\r
14502 \r
14503             /**\r
14504              * @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
14505              * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");\r
14506              *\r
14507              * @param {!Object} t Target element whose style property you want to query\r
14508              * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)\r
14509              * @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
14510              * @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
14511              * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".\r
14512              * @return {?string} The current property value\r
14513              */\r
14514             _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {\r
14515                 var rv;\r
14516                 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
14517                     return _getIEOpacity(t);\r
14518                 }\r
14519                 if (!calc && t.style[p]) {\r
14520                     rv = t.style[p];\r
14521                 } else if ((cs = cs || _getComputedStyle(t))) {\r
14522                     rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());\r
14523                 } else if (t.currentStyle) {\r
14524                     rv = t.currentStyle[p];\r
14525                 }\r
14526                 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;\r
14527             },\r
14528 \r
14529             /**\r
14530              * @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
14531              * @param {!Object} t Target element\r
14532              * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)\r
14533              * @param {!number} v Value\r
14534              * @param {string=} sfx Suffix (like "px" or "%" or "em")\r
14535              * @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
14536              * @return {number} value in pixels\r
14537              */\r
14538             _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {\r
14539                 if (sfx === "px" || !sfx) { return v; }\r
14540                 if (sfx === "auto" || !v) { return 0; }\r
14541                 var horiz = _horizExp.test(p),\r
14542                     node = t,\r
14543                     style = _tempDiv.style,\r
14544                     neg = (v < 0),\r
14545                     pix, cache, time;\r
14546                 if (neg) {\r
14547                     v = -v;\r
14548                 }\r
14549                 if (sfx === "%" && p.indexOf("border") !== -1) {\r
14550                     pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);\r
14551                 } else {\r
14552                     style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";\r
14553                     if (sfx === "%" || !node.appendChild) {\r
14554                         node = t.parentNode || _doc.body;\r
14555                         cache = node._gsCache;\r
14556                         time = TweenLite.ticker.frame;\r
14557                         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
14558                             return cache.width * v / 100;\r
14559                         }\r
14560                         style[(horiz ? "width" : "height")] = v + sfx;\r
14561                     } else {\r
14562                         style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;\r
14563                     }\r
14564                     node.appendChild(_tempDiv);\r
14565                     pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);\r
14566                     node.removeChild(_tempDiv);\r
14567                     if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {\r
14568                         cache = node._gsCache = node._gsCache || {};\r
14569                         cache.time = time;\r
14570                         cache.width = pix / v * 100;\r
14571                     }\r
14572                     if (pix === 0 && !recurse) {\r
14573                         pix = _convertToPixels(t, p, v, sfx, true);\r
14574                     }\r
14575                 }\r
14576                 return neg ? -pix : pix;\r
14577             },\r
14578             _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
14579                 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }\r
14580                 var dim = ((p === "left") ? "Left" : "Top"),\r
14581                     v = _getStyle(t, "margin" + dim, cs);\r
14582                 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);\r
14583             },\r
14584 \r
14585             // @private returns at object containing ALL of the style properties in camelCase and their associated values.\r
14586             _getAllStyles = function(t, cs) {\r
14587                 var s = {},\r
14588                     i, tr;\r
14589                 if ((cs = cs || _getComputedStyle(t, null))) {\r
14590                     if ((i = cs.length)) {\r
14591                         while (--i > -1) {\r
14592                             s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);\r
14593                         }\r
14594                     } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.\r
14595                         for (i in cs) {\r
14596                             s[i] = cs[i];\r
14597                         }\r
14598                     }\r
14599                 } else if ((cs = t.currentStyle || t.style)) {\r
14600                     for (i in cs) {\r
14601                         if (typeof(i) === "string" && s[i] === undefined) {\r
14602                             s[i.replace(_camelExp, _camelFunc)] = cs[i];\r
14603                         }\r
14604                     }\r
14605                 }\r
14606                 if (!_supportsOpacity) {\r
14607                     s.opacity = _getIEOpacity(t);\r
14608                 }\r
14609                 tr = _getTransform(t, cs, false);\r
14610                 s.rotation = tr.rotation;\r
14611                 s.skewX = tr.skewX;\r
14612                 s.scaleX = tr.scaleX;\r
14613                 s.scaleY = tr.scaleY;\r
14614                 s.x = tr.x;\r
14615                 s.y = tr.y;\r
14616                 if (_supports3D) {\r
14617                     s.z = tr.z;\r
14618                     s.rotationX = tr.rotationX;\r
14619                     s.rotationY = tr.rotationY;\r
14620                     s.scaleZ = tr.scaleZ;\r
14621                 }\r
14622                 if (s.filters) {\r
14623                     delete s.filters;\r
14624                 }\r
14625                 return s;\r
14626             },\r
14627 \r
14628             // @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
14629             _cssDif = function(t, s1, s2, vars, forceLookup) {\r
14630                 var difs = {},\r
14631                     style = t.style,\r
14632                     val, p, mpt;\r
14633                 for (p in s2) {\r
14634                     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
14635                         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
14636                         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
14637                             mpt = new MiniPropTween(style, p, style[p], mpt);\r
14638                         }\r
14639                     }\r
14640                 }\r
14641                 if (vars) {\r
14642                     for (p in vars) { //copy properties (except className)\r
14643                         if (p !== "className") {\r
14644                             difs[p] = vars[p];\r
14645                         }\r
14646                     }\r
14647                 }\r
14648                 return {difs:difs, firstMPT:mpt};\r
14649             },\r
14650             _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},\r
14651             _margins = ["marginLeft","marginRight","marginTop","marginBottom"],\r
14652 \r
14653             /**\r
14654              * @private Gets the width or height of an element\r
14655              * @param {!Object} t Target element\r
14656              * @param {!string} p Property name ("width" or "height")\r
14657              * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.\r
14658              * @return {number} Dimension (in pixels)\r
14659              */\r
14660             _getDimension = function(t, p, cs) {\r
14661                 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),\r
14662                     a = _dimensions[p],\r
14663                     i = a.length;\r
14664                 cs = cs || _getComputedStyle(t, null);\r
14665                 while (--i > -1) {\r
14666                     v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;\r
14667                     v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;\r
14668                 }\r
14669                 return v;\r
14670             },\r
14671 \r
14672             // @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
14673             _parsePosition = function(v, recObj) {\r
14674                 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".\r
14675                     v = "0 0";\r
14676                 }\r
14677                 var a = v.split(" "),\r
14678                     x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],\r
14679                     y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];\r
14680                 if (y == null) {\r
14681                     y = "0";\r
14682                 } else if (y === "center") {\r
14683                     y = "50%";\r
14684                 }\r
14685                 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
14686                     x = "50%";\r
14687                 }\r
14688                 if (recObj) {\r
14689                     recObj.oxp = (x.indexOf("%") !== -1);\r
14690                     recObj.oyp = (y.indexOf("%") !== -1);\r
14691                     recObj.oxr = (x.charAt(1) === "=");\r
14692                     recObj.oyr = (y.charAt(1) === "=");\r
14693                     recObj.ox = parseFloat(x.replace(_NaNExp, ""));\r
14694                     recObj.oy = parseFloat(y.replace(_NaNExp, ""));\r
14695                 }\r
14696                 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");\r
14697             },\r
14698 \r
14699             /**\r
14700              * @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
14701              * @param {(number|string)} e End value which is typically a string, but could be a number\r
14702              * @param {(number|string)} b Beginning value which is typically a string but could be a number\r
14703              * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)\r
14704              */\r
14705             _parseChange = function(e, b) {\r
14706                 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);\r
14707             },\r
14708 \r
14709             /**\r
14710              * @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
14711              * @param {Object} v Value to be parsed\r
14712              * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)\r
14713              * @return {number} Parsed value\r
14714              */\r
14715             _parseVal = function(v, d) {\r
14716                 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);\r
14717             },\r
14718 \r
14719             /**\r
14720              * @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
14721              * @param {Object} v Value to be parsed\r
14722              * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)\r
14723              * @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
14724              * @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
14725              * @return {number} parsed angle in radians\r
14726              */\r
14727             _parseAngle = function(v, d, p, directionalEnd) {\r
14728                 var min = 0.000001,\r
14729                     cap, split, dif, result;\r
14730                 if (v == null) {\r
14731                     result = d;\r
14732                 } else if (typeof(v) === "number") {\r
14733                     result = v;\r
14734                 } else {\r
14735                     cap = 360;\r
14736                     split = v.split("_");\r
14737                     dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);\r
14738                     if (split.length) {\r
14739                         if (directionalEnd) {\r
14740                             directionalEnd[p] = d + dif;\r
14741                         }\r
14742                         if (v.indexOf("short") !== -1) {\r
14743                             dif = dif % cap;\r
14744                             if (dif !== dif % (cap / 2)) {\r
14745                                 dif = (dif < 0) ? dif + cap : dif - cap;\r
14746                             }\r
14747                         }\r
14748                         if (v.indexOf("_cw") !== -1 && dif < 0) {\r
14749                             dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
14750                         } else if (v.indexOf("ccw") !== -1 && dif > 0) {\r
14751                             dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
14752                         }\r
14753                     }\r
14754                     result = d + dif;\r
14755                 }\r
14756                 if (result < min && result > -min) {\r
14757                     result = 0;\r
14758                 }\r
14759                 return result;\r
14760             },\r
14761 \r
14762             _colorLookup = {aqua:[0,255,255],\r
14763                 lime:[0,255,0],\r
14764                 silver:[192,192,192],\r
14765                 black:[0,0,0],\r
14766                 maroon:[128,0,0],\r
14767                 teal:[0,128,128],\r
14768                 blue:[0,0,255],\r
14769                 navy:[0,0,128],\r
14770                 white:[255,255,255],\r
14771                 fuchsia:[255,0,255],\r
14772                 olive:[128,128,0],\r
14773                 yellow:[255,255,0],\r
14774                 orange:[255,165,0],\r
14775                 gray:[128,128,128],\r
14776                 purple:[128,0,128],\r
14777                 green:[0,128,0],\r
14778                 red:[255,0,0],\r
14779                 pink:[255,192,203],\r
14780                 cyan:[0,255,255],\r
14781                 transparent:[255,255,255,0]},\r
14782 \r
14783             _hue = function(h, m1, m2) {\r
14784                 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;\r
14785                 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
14786             },\r
14787 \r
14788             /**\r
14789              * @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
14790              * @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
14791              * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.\r
14792              */\r
14793             _parseColor = function(v) {\r
14794                 var c1, c2, c3, h, s, l;\r
14795                 if (!v || v === "") {\r
14796                     return _colorLookup.black;\r
14797                 }\r
14798                 if (typeof(v) === "number") {\r
14799                     return [v >> 16, (v >> 8) & 255, v & 255];\r
14800                 }\r
14801                 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
14802                     v = v.substr(0, v.length - 1);\r
14803                 }\r
14804                 if (_colorLookup[v]) {\r
14805                     return _colorLookup[v];\r
14806                 }\r
14807                 if (v.charAt(0) === "#") {\r
14808                     if (v.length === 4) { //for shorthand like #9F0\r
14809                         c1 = v.charAt(1),\r
14810                         c2 = v.charAt(2),\r
14811                         c3 = v.charAt(3);\r
14812                         v = "#" + c1 + c1 + c2 + c2 + c3 + c3;\r
14813                     }\r
14814                     v = parseInt(v.substr(1), 16);\r
14815                     return [v >> 16, (v >> 8) & 255, v & 255];\r
14816                 }\r
14817                 if (v.substr(0, 3) === "hsl") {\r
14818                     v = v.match(_numExp);\r
14819                     h = (Number(v[0]) % 360) / 360;\r
14820                     s = Number(v[1]) / 100;\r
14821                     l = Number(v[2]) / 100;\r
14822                     c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;\r
14823                     c1 = l * 2 - c2;\r
14824                     if (v.length > 3) {\r
14825                         v[3] = Number(v[3]);\r
14826                     }\r
14827                     v[0] = _hue(h + 1 / 3, c1, c2);\r
14828                     v[1] = _hue(h, c1, c2);\r
14829                     v[2] = _hue(h - 1 / 3, c1, c2);\r
14830                     return v;\r
14831                 }\r
14832                 v = v.match(_numExp) || _colorLookup.transparent;\r
14833                 v[0] = Number(v[0]);\r
14834                 v[1] = Number(v[1]);\r
14835                 v[2] = Number(v[2]);\r
14836                 if (v.length > 3) {\r
14837                     v[3] = Number(v[3]);\r
14838                 }\r
14839                 return v;\r
14840             },\r
14841             _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
14842 \r
14843         for (p in _colorLookup) {\r
14844             _colorExp += "|" + p + "\\b";\r
14845         }\r
14846         _colorExp = new RegExp(_colorExp+")", "gi");\r
14847 \r
14848         /**\r
14849          * @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
14850          * @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
14851          * @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
14852          * @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
14853          * @return {Function} formatter function\r
14854          */\r
14855         var _getFormatter = function(dflt, clr, collapsible, multi) {\r
14856                 if (dflt == null) {\r
14857                     return function(v) {return v;};\r
14858                 }\r
14859                 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",\r
14860                     dVals = dflt.split(dColor).join("").match(_valuesExp) || [],\r
14861                     pfx = dflt.substr(0, dflt.indexOf(dVals[0])),\r
14862                     sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",\r
14863                     delim = (dflt.indexOf(" ") !== -1) ? " " : ",",\r
14864                     numVals = dVals.length,\r
14865                     dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",\r
14866                     formatter;\r
14867                 if (!numVals) {\r
14868                     return function(v) {return v;};\r
14869                 }\r
14870                 if (clr) {\r
14871                     formatter = function(v) {\r
14872                         var color, vals, i, a;\r
14873                         if (typeof(v) === "number") {\r
14874                             v += dSfx;\r
14875                         } else if (multi && _commasOutsideParenExp.test(v)) {\r
14876                             a = v.replace(_commasOutsideParenExp, "|").split("|");\r
14877                             for (i = 0; i < a.length; i++) {\r
14878                                 a[i] = formatter(a[i]);\r
14879                             }\r
14880                             return a.join(",");\r
14881                         }\r
14882                         color = (v.match(_colorExp) || [dColor])[0];\r
14883                         vals = v.split(color).join("").match(_valuesExp) || [];\r
14884                         i = vals.length;\r
14885                         if (numVals > i--) {\r
14886                             while (++i < numVals) {\r
14887                                 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];\r
14888                             }\r
14889                         }\r
14890                         return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");\r
14891                     };\r
14892                     return formatter;\r
14893 \r
14894                 }\r
14895                 formatter = function(v) {\r
14896                     var vals, a, i;\r
14897                     if (typeof(v) === "number") {\r
14898                         v += dSfx;\r
14899                     } else if (multi && _commasOutsideParenExp.test(v)) {\r
14900                         a = v.replace(_commasOutsideParenExp, "|").split("|");\r
14901                         for (i = 0; i < a.length; i++) {\r
14902                             a[i] = formatter(a[i]);\r
14903                         }\r
14904                         return a.join(",");\r
14905                     }\r
14906                     vals = v.match(_valuesExp) || [];\r
14907                     i = vals.length;\r
14908                     if (numVals > i--) {\r
14909                         while (++i < numVals) {\r
14910                             vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];\r
14911                         }\r
14912                     }\r
14913                     return pfx + vals.join(delim) + sfx;\r
14914                 };\r
14915                 return formatter;\r
14916             },\r
14917 \r
14918             /**\r
14919              * @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
14920              * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"\r
14921              * @return {Function} a formatter function\r
14922              */\r
14923             _getEdgeParser = function(props) {\r
14924                 props = props.split(",");\r
14925                 return function(t, e, p, cssp, pt, plugin, vars) {\r
14926                     var a = (e + "").split(" "),\r
14927                         i;\r
14928                     vars = {};\r
14929                     for (i = 0; i < 4; i++) {\r
14930                         vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];\r
14931                     }\r
14932                     return cssp.parse(t, vars, pt, plugin);\r
14933                 };\r
14934             },\r
14935 \r
14936             // @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
14937             _setPluginRatio = _internals._setPluginRatio = function(v) {\r
14938                 this.plugin.setRatio(v);\r
14939                 var d = this.data,\r
14940                     proxy = d.proxy,\r
14941                     mpt = d.firstMPT,\r
14942                     min = 0.000001,\r
14943                     val, pt, i, str;\r
14944                 while (mpt) {\r
14945                     val = proxy[mpt.v];\r
14946                     if (mpt.r) {\r
14947                         val = Math.round(val);\r
14948                     } else if (val < min && val > -min) {\r
14949                         val = 0;\r
14950                     }\r
14951                     mpt.t[mpt.p] = val;\r
14952                     mpt = mpt._next;\r
14953                 }\r
14954                 if (d.autoRotate) {\r
14955                     d.autoRotate.rotation = proxy.rotation;\r
14956                 }\r
14957                 //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
14958                 if (v === 1) {\r
14959                     mpt = d.firstMPT;\r
14960                     while (mpt) {\r
14961                         pt = mpt.t;\r
14962                         if (!pt.type) {\r
14963                             pt.e = pt.s + pt.xs0;\r
14964                         } else if (pt.type === 1) {\r
14965                             str = pt.xs0 + pt.s + pt.xs1;\r
14966                             for (i = 1; i < pt.l; i++) {\r
14967                                 str += pt["xn"+i] + pt["xs"+(i+1)];\r
14968                             }\r
14969                             pt.e = str;\r
14970                         }\r
14971                         mpt = mpt._next;\r
14972                     }\r
14973                 }\r
14974             },\r
14975 \r
14976             /**\r
14977              * @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
14978              * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)\r
14979              * @param {!string} p property name\r
14980              * @param {(number|string|object)} v value\r
14981              * @param {MiniPropTween=} next next MiniPropTween in the linked list\r
14982              * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer\r
14983              */\r
14984             MiniPropTween = function(t, p, v, next, r) {\r
14985                 this.t = t;\r
14986                 this.p = p;\r
14987                 this.v = v;\r
14988                 this.r = r;\r
14989                 if (next) {\r
14990                     next._prev = this;\r
14991                     this._next = next;\r
14992                 }\r
14993             },\r
14994 \r
14995             /**\r
14996              * @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
14997              * This method returns an object that has the following properties:\r
14998              *  - 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
14999              *  - 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
15000              *  - firstMPT: the first MiniPropTween in the linked list\r
15001              *  - 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
15002              * @param {!Object} t target object to be tweened\r
15003              * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed\r
15004              * @param {!CSSPlugin} cssp The CSSPlugin instance\r
15005              * @param {CSSPropTween=} pt the next CSSPropTween in the linked list\r
15006              * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values\r
15007              * @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
15008              * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)\r
15009              */\r
15010             _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {\r
15011                 var bpt = pt,\r
15012                     start = {},\r
15013                     end = {},\r
15014                     transform = cssp._transform,\r
15015                     oldForce = _forcePT,\r
15016                     i, p, xp, mpt, firstPT;\r
15017                 cssp._transform = null;\r
15018                 _forcePT = vars;\r
15019                 pt = firstPT = cssp.parse(t, vars, pt, plugin);\r
15020                 _forcePT = oldForce;\r
15021                 //break off from the linked list so the new ones are isolated.\r
15022                 if (shallow) {\r
15023                     cssp._transform = transform;\r
15024                     if (bpt) {\r
15025                         bpt._prev = null;\r
15026                         if (bpt._prev) {\r
15027                             bpt._prev._next = null;\r
15028                         }\r
15029                     }\r
15030                 }\r
15031                 while (pt && pt !== bpt) {\r
15032                     if (pt.type <= 1) {\r
15033                         p = pt.p;\r
15034                         end[p] = pt.s + pt.c;\r
15035                         start[p] = pt.s;\r
15036                         if (!shallow) {\r
15037                             mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);\r
15038                             pt.c = 0;\r
15039                         }\r
15040                         if (pt.type === 1) {\r
15041                             i = pt.l;\r
15042                             while (--i > 0) {\r
15043                                 xp = "xn" + i;\r
15044                                 p = pt.p + "_" + xp;\r
15045                                 end[p] = pt.data[xp];\r
15046                                 start[p] = pt[xp];\r
15047                                 if (!shallow) {\r
15048                                     mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);\r
15049                                 }\r
15050                             }\r
15051                         }\r
15052                     }\r
15053                     pt = pt._next;\r
15054                 }\r
15055                 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};\r
15056             },\r
15057 \r
15058 \r
15059 \r
15060             /**\r
15061              * @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
15062              * CSSPropTweens have the following optional properties as well (not defined through the constructor):\r
15063              *  - 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
15064              *  - 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
15065              *  - 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
15066              *  - 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
15067              *  - 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
15068              * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.\r
15069              * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".\r
15070              * @param {number} s Starting numeric value\r
15071              * @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
15072              * @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
15073              * @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
15074              * @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
15075              * @param {boolean=} r If true, the value(s) should be rounded\r
15076              * @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
15077              * @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
15078              * @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
15079              */\r
15080             CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {\r
15081                 this.t = t; //target\r
15082                 this.p = p; //property\r
15083                 this.s = s; //starting value\r
15084                 this.c = c; //change value\r
15085                 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
15086                 if (!(t instanceof CSSPropTween)) {\r
15087                     _overwriteProps.push(this.n);\r
15088                 }\r
15089                 this.r = r; //round (boolean)\r
15090                 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
15091                 if (pr) {\r
15092                     this.pr = pr;\r
15093                     _hasPriority = true;\r
15094                 }\r
15095                 this.b = (b === undefined) ? s : b;\r
15096                 this.e = (e === undefined) ? s + c : e;\r
15097                 if (next) {\r
15098                     this._next = next;\r
15099                     next._prev = this;\r
15100                 }\r
15101             },\r
15102 \r
15103             /**\r
15104              * 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
15105              * 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
15106              * 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
15107              * 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
15108              *\r
15109              * @param {!Object} t Target whose property will be tweened\r
15110              * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")\r
15111              * @param {string} b Beginning value\r
15112              * @param {string} e Ending value\r
15113              * @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
15114              * @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
15115              * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).\r
15116              * @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
15117              * @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
15118              * @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
15119              * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.\r
15120              */\r
15121             _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {\r
15122                 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);\r
15123                 b = b || dflt || "";\r
15124                 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);\r
15125                 e += ""; //ensures it's a string\r
15126                 var ba = b.split(", ").join(",").split(" "), //beginning array\r
15127                     ea = e.split(", ").join(",").split(" "), //ending array\r
15128                     l = ba.length,\r
15129                     autoRound = (_autoRound !== false),\r
15130                     i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;\r
15131                 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {\r
15132                     ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");\r
15133                     ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");\r
15134                     l = ba.length;\r
15135                 }\r
15136                 if (l !== ea.length) {\r
15137                     //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");\r
15138                     ba = (dflt || "").split(" ");\r
15139                     l = ba.length;\r
15140                 }\r
15141                 pt.plugin = plugin;\r
15142                 pt.setRatio = setRatio;\r
15143                 for (i = 0; i < l; i++) {\r
15144                     bv = ba[i];\r
15145                     ev = ea[i];\r
15146                     bn = parseFloat(bv);\r
15147 \r
15148                     //if the value begins with a number (most common). It's fine if it has a suffix like px\r
15149                     if (bn || bn === 0) {\r
15150                         pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);\r
15151 \r
15152                     //if the value is a color\r
15153                     } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {\r
15154                         str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.\r
15155                         bv = _parseColor(bv);\r
15156                         ev = _parseColor(ev);\r
15157                         rgba = (bv.length + ev.length > 6);\r
15158                         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
15159                             pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";\r
15160                             pt.e = pt.e.split(ea[i]).join("transparent");\r
15161                         } else {\r
15162                             if (!_supportsOpacity) { //old versions of IE don't support rgba().\r
15163                                 rgba = false;\r
15164                             }\r
15165                             pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)\r
15166                                 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)\r
15167                                 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);\r
15168                             if (rgba) {\r
15169                                 bv = (bv.length < 4) ? 1 : bv[3];\r
15170                                 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);\r
15171                             }\r
15172                         }\r
15173 \r
15174                     } else {\r
15175                         bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array\r
15176 \r
15177                         //if no number is found, treat it as a non-tweening value and just append the string to the current xs.\r
15178                         if (!bnums) {\r
15179                             pt["xs" + pt.l] += pt.l ? " " + bv : bv;\r
15180 \r
15181                         //loop through all the numbers that are found and construct the extra values on the pt.\r
15182                         } else {\r
15183                             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
15184                             if (!enums || enums.length !== bnums.length) {\r
15185                                 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");\r
15186                                 return pt;\r
15187                             }\r
15188                             ni = 0;\r
15189                             for (xi = 0; xi < bnums.length; xi++) {\r
15190                                 cv = bnums[xi];\r
15191                                 temp = bv.indexOf(cv, ni);\r
15192                                 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));\r
15193                                 ni = temp + cv.length;\r
15194                             }\r
15195                             pt["xs" + pt.l] += bv.substr(ni);\r
15196                         }\r
15197                     }\r
15198                 }\r
15199                 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.\r
15200                 if (e.indexOf("=") !== -1) if (pt.data) {\r
15201                     str = pt.xs0 + pt.data.s;\r
15202                     for (i = 1; i < pt.l; i++) {\r
15203                         str += pt["xs" + i] + pt.data["xn" + i];\r
15204                     }\r
15205                     pt.e = str + pt["xs" + i];\r
15206                 }\r
15207                 if (!pt.l) {\r
15208                     pt.type = -1;\r
15209                     pt.xs0 = pt.e;\r
15210                 }\r
15211                 return pt.xfirst || pt;\r
15212             },\r
15213             i = 9;\r
15214 \r
15215 \r
15216         p = CSSPropTween.prototype;\r
15217         p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.\r
15218         while (--i > 0) {\r
15219             p["xn" + i] = 0;\r
15220             p["xs" + i] = "";\r
15221         }\r
15222         p.xs0 = "";\r
15223         p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;\r
15224 \r
15225 \r
15226         /**\r
15227          * 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
15228          * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"\r
15229          * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).\r
15230          * @param {string=} pfx Prefix (if any)\r
15231          * @param {!number} s Starting value\r
15232          * @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
15233          * @param {string=} sfx Suffix (if any)\r
15234          * @param {boolean=} r Round (if true).\r
15235          * @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
15236          * @return {CSSPropTween} returns itself so that multiple methods can be chained together.\r
15237          */\r
15238         p.appendXtra = function(pfx, s, c, sfx, r, pad) {\r
15239             var pt = this,\r
15240                 l = pt.l;\r
15241             pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";\r
15242             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
15243                 pt["xs" + l] += s + (sfx || "");\r
15244                 return pt;\r
15245             }\r
15246             pt.l++;\r
15247             pt.type = pt.setRatio ? 2 : 1;\r
15248             pt["xs" + pt.l] = sfx || "";\r
15249             if (l > 0) {\r
15250                 pt.data["xn" + l] = s + c;\r
15251                 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)\r
15252                 pt["xn" + l] = s;\r
15253                 if (!pt.plugin) {\r
15254                     pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);\r
15255                     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
15256                 }\r
15257                 return pt;\r
15258             }\r
15259             pt.data = {s:s + c};\r
15260             pt.rxp = {};\r
15261             pt.s = s;\r
15262             pt.c = c;\r
15263             pt.r = r;\r
15264             return pt;\r
15265         };\r
15266 \r
15267         /**\r
15268          * @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
15269          * @param {!string} p Property name (like "boxShadow" or "throwProps")\r
15270          * @param {Object=} options An object containing any of the following configuration options:\r
15271          *                      - defaultValue: the default value\r
15272          *                      - 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
15273          *                      - 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
15274          *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)\r
15275          *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.\r
15276          *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.\r
15277          *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.\r
15278          *                      - 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
15279          *                      - 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
15280          */\r
15281         var SpecialProp = function(p, options) {\r
15282                 options = options || {};\r
15283                 this.p = options.prefix ? _checkPropPrefix(p) || p : p;\r
15284                 _specialProps[p] = _specialProps[this.p] = this;\r
15285                 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);\r
15286                 if (options.parser) {\r
15287                     this.parse = options.parser;\r
15288                 }\r
15289                 this.clrs = options.color;\r
15290                 this.multi = options.multi;\r
15291                 this.keyword = options.keyword;\r
15292                 this.dflt = options.defaultValue;\r
15293                 this.pr = options.priority || 0;\r
15294             },\r
15295 \r
15296             //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
15297             _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {\r
15298                 if (typeof(options) !== "object") {\r
15299                     options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin\r
15300                 }\r
15301                 var a = p.split(","),\r
15302                     d = options.defaultValue,\r
15303                     i, temp;\r
15304                 defaults = defaults || [d];\r
15305                 for (i = 0; i < a.length; i++) {\r
15306                     options.prefix = (i === 0 && options.prefix);\r
15307                     options.defaultValue = defaults[i] || d;\r
15308                     temp = new SpecialProp(a[i], options);\r
15309                 }\r
15310             },\r
15311 \r
15312             //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
15313             _registerPluginProp = function(p) {\r
15314                 if (!_specialProps[p]) {\r
15315                     var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";\r
15316                     _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {\r
15317                         var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];\r
15318                         if (!pluginClass) {\r
15319                             _log("Error: " + pluginName + " js file not loaded.");\r
15320                             return pt;\r
15321                         }\r
15322                         pluginClass._cssRegister();\r
15323                         return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);\r
15324                     }});\r
15325                 }\r
15326             };\r
15327 \r
15328 \r
15329         p = SpecialProp.prototype;\r
15330 \r
15331         /**\r
15332          * 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
15333          * @param {!Object} t target element\r
15334          * @param {(string|number|object)} b beginning value\r
15335          * @param {(string|number|object)} e ending (destination) value\r
15336          * @param {CSSPropTween=} pt next CSSPropTween in the linked list\r
15337          * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.\r
15338          * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.\r
15339          * @return {CSSPropTween=} First CSSPropTween in the linked list\r
15340          */\r
15341         p.parseComplex = function(t, b, e, pt, plugin, setRatio) {\r
15342             var kwd = this.keyword,\r
15343                 i, ba, ea, l, bi, ei;\r
15344             //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
15345             if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {\r
15346                 ba = b.replace(_commasOutsideParenExp, "|").split("|");\r
15347                 ea = e.replace(_commasOutsideParenExp, "|").split("|");\r
15348             } else if (kwd) {\r
15349                 ba = [b];\r
15350                 ea = [e];\r
15351             }\r
15352             if (ea) {\r
15353                 l = (ea.length > ba.length) ? ea.length : ba.length;\r
15354                 for (i = 0; i < l; i++) {\r
15355                     b = ba[i] = ba[i] || this.dflt;\r
15356                     e = ea[i] = ea[i] || this.dflt;\r
15357                     if (kwd) {\r
15358                         bi = b.indexOf(kwd);\r
15359                         ei = e.indexOf(kwd);\r
15360                         if (bi !== ei) {\r
15361                             e = (ei === -1) ? ea : ba;\r
15362                             e[i] += " " + kwd;\r
15363                         }\r
15364                     }\r
15365                 }\r
15366                 b = ba.join(", ");\r
15367                 e = ea.join(", ");\r
15368             }\r
15369             return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);\r
15370         };\r
15371 \r
15372         /**\r
15373          * 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
15374          * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);\r
15375          * 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
15376          * @param {!Object} t Target object whose property is being tweened\r
15377          * @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
15378          * @param {!string} p Property name\r
15379          * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.\r
15380          * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)\r
15381          * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.\r
15382          * @param {Object=} vars Original vars object that contains the data for parsing.\r
15383          * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.\r
15384          */\r
15385         p.parse = function(t, e, p, cssp, pt, plugin, vars) {\r
15386             return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);\r
15387         };\r
15388 \r
15389         /**\r
15390          * 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
15391          *  1) Target object whose property should be tweened (typically a DOM element)\r
15392          *  2) The end/destination value (could be a string, number, object, or whatever you want)\r
15393          *  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
15394          *\r
15395          * 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
15396          *\r
15397          * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {\r
15398          *      var start = target.style.width;\r
15399          *      return function(ratio) {\r
15400          *              target.style.width = (start + value * ratio) + "px";\r
15401          *              console.log("set width to " + target.style.width);\r
15402          *          }\r
15403          * }, 0);\r
15404          *\r
15405          * Then, when I do this tween, it will trigger my special property:\r
15406          *\r
15407          * TweenLite.to(element, 1, {css:{myCustomProp:100}});\r
15408          *\r
15409          * In the example, of course, we're just changing the width, but you can do anything you want.\r
15410          *\r
15411          * @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
15412          * @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
15413          * @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
15414          */\r
15415         CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {\r
15416             _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {\r
15417                 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);\r
15418                 rv.plugin = plugin;\r
15419                 rv.setRatio = onInitTween(t, e, cssp._tween, p);\r
15420                 return rv;\r
15421             }, priority:priority});\r
15422         };\r
15423 \r
15424 \r
15425 \r
15426 \r
15427 \r
15428 \r
15429 \r
15430 \r
15431         //transform-related methods and properties\r
15432         var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),\r
15433             _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.\r
15434             _transformPropCSS = _prefixCSS + "transform",\r
15435             _transformOriginProp = _checkPropPrefix("transformOrigin"),\r
15436             _supports3D = (_checkPropPrefix("perspective") !== null),\r
15437             Transform = _internals.Transform = function() {\r
15438                 this.skewY = 0;\r
15439             },\r
15440 \r
15441             /**\r
15442              * 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
15443              * @param {!Object} t target element\r
15444              * @param {Object=} cs computed style object (optional)\r
15445              * @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
15446              * @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
15447              * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}\r
15448              */\r
15449             _getTransform = _internals.getTransform = function(t, cs, rec, parse) {\r
15450                 if (t._gsTransform && rec && !parse) {\r
15451                     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
15452                 }\r
15453                 var tm = rec ? t._gsTransform || new Transform() : new Transform(),\r
15454                     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
15455                     min = 0.00002,\r
15456                     rnd = 100000,\r
15457                     minAngle = 179.99,\r
15458                     minPI = minAngle * _DEG2RAD,\r
15459                     zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,\r
15460                     s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;\r
15461                 if (_transformProp) {\r
15462                     s = _getStyle(t, _transformPropCSS, cs, true);\r
15463                 } else if (t.currentStyle) {\r
15464                     //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
15465                     s = t.currentStyle.filter.match(_ieGetMatrixExp);\r
15466                     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
15467                 }\r
15468                 //split the matrix values out into an array (m for matrix)\r
15469                 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];\r
15470                 i = m.length;\r
15471                 while (--i > -1) {\r
15472                     n = Number(m[i]);\r
15473                     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
15474                 }\r
15475                 if (m.length === 16) {\r
15476 \r
15477                     //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
15478                     var a13 = m[8], a23 = m[9], a33 = m[10],\r
15479                         a14 = m[12], a24 = m[13], a34 = m[14];\r
15480 \r
15481                     //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari\r
15482                     if (tm.zOrigin) {\r
15483                         a34 = -tm.zOrigin;\r
15484                         a14 = a13*a34-m[12];\r
15485                         a24 = a23*a34-m[13];\r
15486                         a34 = a33*a34+tm.zOrigin-m[14];\r
15487                     }\r
15488 \r
15489                     //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
15490                     if (!rec || parse || tm.rotationX == null) {\r
15491                         var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],\r
15492                             a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],\r
15493                             a43 = m[11],\r
15494                             angle = Math.atan2(a32, a33),\r
15495                             xFlip = (angle < -minPI || angle > minPI),\r
15496                             t1, t2, t3, cos, sin, yFlip, zFlip;\r
15497                         tm.rotationX = angle * _RAD2DEG;\r
15498                         //rotationX\r
15499                         if (angle) {\r
15500                             cos = Math.cos(-angle);\r
15501                             sin = Math.sin(-angle);\r
15502                             t1 = a12*cos+a13*sin;\r
15503                             t2 = a22*cos+a23*sin;\r
15504                             t3 = a32*cos+a33*sin;\r
15505                             a13 = a12*-sin+a13*cos;\r
15506                             a23 = a22*-sin+a23*cos;\r
15507                             a33 = a32*-sin+a33*cos;\r
15508                             a43 = a42*-sin+a43*cos;\r
15509                             a12 = t1;\r
15510                             a22 = t2;\r
15511                             a32 = t3;\r
15512                         }\r
15513                         //rotationY\r
15514                         angle = Math.atan2(a13, a11);\r
15515                         tm.rotationY = angle * _RAD2DEG;\r
15516                         if (angle) {\r
15517                             yFlip = (angle < -minPI || angle > minPI);\r
15518                             cos = Math.cos(-angle);\r
15519                             sin = Math.sin(-angle);\r
15520                             t1 = a11*cos-a13*sin;\r
15521                             t2 = a21*cos-a23*sin;\r
15522                             t3 = a31*cos-a33*sin;\r
15523                             a23 = a21*sin+a23*cos;\r
15524                             a33 = a31*sin+a33*cos;\r
15525                             a43 = a41*sin+a43*cos;\r
15526                             a11 = t1;\r
15527                             a21 = t2;\r
15528                             a31 = t3;\r
15529                         }\r
15530                         //rotationZ\r
15531                         angle = Math.atan2(a21, a22);\r
15532                         tm.rotation = angle * _RAD2DEG;\r
15533                         if (angle) {\r
15534                             zFlip = (angle < -minPI || angle > minPI);\r
15535                             cos = Math.cos(-angle);\r
15536                             sin = Math.sin(-angle);\r
15537                             a11 = a11*cos+a12*sin;\r
15538                             t2 = a21*cos+a22*sin;\r
15539                             a22 = a21*-sin+a22*cos;\r
15540                             a32 = a31*-sin+a32*cos;\r
15541                             a21 = t2;\r
15542                         }\r
15543 \r
15544                         if (zFlip && xFlip) {\r
15545                             tm.rotation = tm.rotationX = 0;\r
15546                         } else if (zFlip && yFlip) {\r
15547                             tm.rotation = tm.rotationY = 0;\r
15548                         } else if (yFlip && xFlip) {\r
15549                             tm.rotationY = tm.rotationX = 0;\r
15550                         }\r
15551 \r
15552                         tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;\r
15553                         tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;\r
15554                         tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;\r
15555                         tm.skewX = 0;\r
15556                         tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;\r
15557                         tm.x = a14;\r
15558                         tm.y = a24;\r
15559                         tm.z = a34;\r
15560                     }\r
15561 \r
15562                 } 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
15563                     var k = (m.length >= 6),\r
15564                         a = k ? m[0] : 1,\r
15565                         b = m[1] || 0,\r
15566                         c = m[2] || 0,\r
15567                         d = k ? m[3] : 1;\r
15568                     tm.x = m[4] || 0;\r
15569                     tm.y = m[5] || 0;\r
15570                     scaleX = Math.sqrt(a * a + b * b);\r
15571                     scaleY = Math.sqrt(d * d + c * c);\r
15572                     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
15573                     skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;\r
15574                     difX = scaleX - Math.abs(tm.scaleX || 0);\r
15575                     difY = scaleY - Math.abs(tm.scaleY || 0);\r
15576                     if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {\r
15577                         if (invX) {\r
15578                             scaleX *= -1;\r
15579                             skewX += (rotation <= 0) ? 180 : -180;\r
15580                             rotation += (rotation <= 0) ? 180 : -180;\r
15581                         } else {\r
15582                             scaleY *= -1;\r
15583                             skewX += (skewX <= 0) ? 180 : -180;\r
15584                         }\r
15585                     }\r
15586                     difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.\r
15587                     difS = (skewX - tm.skewX) % 180;\r
15588                     //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
15589                     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
15590                         tm.scaleX = scaleX;\r
15591                         tm.scaleY = scaleY;\r
15592                         tm.rotation = rotation;\r
15593                         tm.skewX = skewX;\r
15594                     }\r
15595                     if (_supports3D) {\r
15596                         tm.rotationX = tm.rotationY = tm.z = 0;\r
15597                         tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;\r
15598                         tm.scaleZ = 1;\r
15599                     }\r
15600                 }\r
15601                 tm.zOrigin = zOrigin;\r
15602 \r
15603                 //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
15604                 for (i in tm) {\r
15605                     if (tm[i] < min) if (tm[i] > -min) {\r
15606                         tm[i] = 0;\r
15607                     }\r
15608                 }\r
15609                 //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
15610                 if (rec) {\r
15611                     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
15612                 }\r
15613                 return tm;\r
15614             },\r
15615 \r
15616             //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)\r
15617             _setIETransformRatio = function(v) {\r
15618                 var t = this.data, //refers to the element's _gsTransform object\r
15619                     ang = -t.rotation * _DEG2RAD,\r
15620                     skew = ang + t.skewX * _DEG2RAD,\r
15621                     rnd = 100000,\r
15622                     a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,\r
15623                     b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,\r
15624                     c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,\r
15625                     d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,\r
15626                     style = this.t.style,\r
15627                     cs = this.t.currentStyle,\r
15628                     filters, val;\r
15629                 if (!cs) {\r
15630                     return;\r
15631                 }\r
15632                 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
15633                 b = -c;\r
15634                 c = -val;\r
15635                 filters = cs.filter;\r
15636                 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight\r
15637                 var w = this.t.offsetWidth,\r
15638                     h = this.t.offsetHeight,\r
15639                     clip = (cs.position !== "absolute"),\r
15640                     m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,\r
15641                     ox = t.x,\r
15642                     oy = t.y,\r
15643                     dx, dy;\r
15644 \r
15645                 //if transformOrigin is being used, adjust the offset x and y\r
15646                 if (t.ox != null) {\r
15647                     dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;\r
15648                     dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;\r
15649                     ox += dx - (dx * a + dy * b);\r
15650                     oy += dy - (dx * c + dy * d);\r
15651                 }\r
15652 \r
15653                 if (!clip) {\r
15654                     m += ", sizingMethod='auto expand')";\r
15655                 } else {\r
15656                     dx = (w / 2);\r
15657                     dy = (h / 2);\r
15658                     //translate to ensure that transformations occur around the correct origin (default is center).\r
15659                     m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";\r
15660                 }\r
15661                 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {\r
15662                     style.filter = filters.replace(_ieSetMatrixExp, m);\r
15663                 } else {\r
15664                     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
15665                 }\r
15666 \r
15667                 //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
15668                 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
15669                     style.removeAttribute("filter");\r
15670                 }\r
15671 \r
15672                 //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
15673                 if (!clip) {\r
15674                     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
15675                         marg, prop, dif;\r
15676                     dx = t.ieOffsetX || 0;\r
15677                     dy = t.ieOffsetY || 0;\r
15678                     t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);\r
15679                     t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);\r
15680                     for (i = 0; i < 4; i++) {\r
15681                         prop = _margins[i];\r
15682                         marg = cs[prop];\r
15683                         //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)\r
15684                         val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;\r
15685                         if (val !== t[prop]) {\r
15686                             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
15687                         } else {\r
15688                             dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;\r
15689                         }\r
15690                         style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";\r
15691                     }\r
15692                 }\r
15693             },\r
15694 \r
15695             _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {\r
15696                 var t = this.data, //refers to the element's _gsTransform object\r
15697                     style = this.t.style,\r
15698                     angle = t.rotation * _DEG2RAD,\r
15699                     sx = t.scaleX,\r
15700                     sy = t.scaleY,\r
15701                     sz = t.scaleZ,\r
15702                     perspective = t.perspective,\r
15703                     a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,\r
15704                     zOrigin, rnd, cos, sin, t1, t2, t3, t4;\r
15705                 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
15706                     _set2DTransformRatio.call(this, v);\r
15707                     return;\r
15708                 }\r
15709                 if (_isFirefox) {\r
15710                     var n = 0.0001;\r
15711                     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
15712                         sx = sz = 0.00002;\r
15713                     }\r
15714                     if (sy < n && sy > -n) {\r
15715                         sy = sz = 0.00002;\r
15716                     }\r
15717                     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
15718                         perspective = 0;\r
15719                     }\r
15720                 }\r
15721                 if (angle || t.skewX) {\r
15722                     cos = Math.cos(angle);\r
15723                     sin = Math.sin(angle);\r
15724                     a11 = cos;\r
15725                     a21 = sin;\r
15726                     if (t.skewX) {\r
15727                         angle -= t.skewX * _DEG2RAD;\r
15728                         cos = Math.cos(angle);\r
15729                         sin = Math.sin(angle);\r
15730                         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
15731                             t1 = Math.tan(t.skewX * _DEG2RAD);\r
15732                             t1 = Math.sqrt(1 + t1 * t1);\r
15733                             cos *= t1;\r
15734                             sin *= t1;\r
15735                         }\r
15736                     }\r
15737                     a12 = -sin;\r
15738                     a22 = cos;\r
15739 \r
15740                 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...\r
15741                     style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");\r
15742                     return;\r
15743                 } else {\r
15744                     a11 = a22 = 1;\r
15745                     a12 = a21 = 0;\r
15746                 }\r
15747                 a33 = 1;\r
15748                 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;\r
15749                 a43 = (perspective) ? -1 / perspective : 0;\r
15750                 zOrigin = t.zOrigin;\r
15751                 rnd = 100000;\r
15752                 angle = t.rotationY * _DEG2RAD;\r
15753                 if (angle) {\r
15754                     cos = Math.cos(angle);\r
15755                     sin = Math.sin(angle);\r
15756                     a31 = a33*-sin;\r
15757                     a41 = a43*-sin;\r
15758                     a13 = a11*sin;\r
15759                     a23 = a21*sin;\r
15760                     a33 *= cos;\r
15761                     a43 *= cos;\r
15762                     a11 *= cos;\r
15763                     a21 *= cos;\r
15764                 }\r
15765                 angle = t.rotationX * _DEG2RAD;\r
15766                 if (angle) {\r
15767                     cos = Math.cos(angle);\r
15768                     sin = Math.sin(angle);\r
15769                     t1 = a12*cos+a13*sin;\r
15770                     t2 = a22*cos+a23*sin;\r
15771                     t3 = a32*cos+a33*sin;\r
15772                     t4 = a42*cos+a43*sin;\r
15773                     a13 = a12*-sin+a13*cos;\r
15774                     a23 = a22*-sin+a23*cos;\r
15775                     a33 = a32*-sin+a33*cos;\r
15776                     a43 = a42*-sin+a43*cos;\r
15777                     a12 = t1;\r
15778                     a22 = t2;\r
15779                     a32 = t3;\r
15780                     a42 = t4;\r
15781                 }\r
15782                 if (sz !== 1) {\r
15783                     a13*=sz;\r
15784                     a23*=sz;\r
15785                     a33*=sz;\r
15786                     a43*=sz;\r
15787                 }\r
15788                 if (sy !== 1) {\r
15789                     a12*=sy;\r
15790                     a22*=sy;\r
15791                     a32*=sy;\r
15792                     a42*=sy;\r
15793                 }\r
15794                 if (sx !== 1) {\r
15795                     a11*=sx;\r
15796                     a21*=sx;\r
15797                     a31*=sx;\r
15798                     a41*=sx;\r
15799                 }\r
15800                 if (zOrigin) {\r
15801                     a34 -= zOrigin;\r
15802                     a14 = a13*a34;\r
15803                     a24 = a23*a34;\r
15804                     a34 = a33*a34+zOrigin;\r
15805                 }\r
15806                 //we round the x, y, and z slightly differently to allow even larger values.\r
15807                 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;\r
15808                 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;\r
15809                 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;\r
15810                 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
15811             },\r
15812 \r
15813             _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {\r
15814                 var t = this.data, //refers to the element's _gsTransform object\r
15815                     targ = this.t,\r
15816                     style = targ.style,\r
15817                     ang, skew, rnd, sx, sy;\r
15818                 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
15819                     this.setRatio = _set3DTransformRatio;\r
15820                     _set3DTransformRatio.call(this, v);\r
15821                     return;\r
15822                 }\r
15823                 if (!t.rotation && !t.skewX) {\r
15824                     style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";\r
15825                 } else {\r
15826                     ang = t.rotation * _DEG2RAD;\r
15827                     skew = ang - t.skewX * _DEG2RAD;\r
15828                     rnd = 100000;\r
15829                     sx = t.scaleX * rnd;\r
15830                     sy = t.scaleY * rnd;\r
15831                     //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
15832                     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
15833                 }\r
15834             };\r
15835 \r
15836         _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
15837             if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.\r
15838             var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),\r
15839                 style = t.style,\r
15840                 min = 0.000001,\r
15841                 i = _transformProps.length,\r
15842                 v = vars,\r
15843                 endRotations = {},\r
15844                 m2, skewY, copy, orig, has3D, hasChange, dr;\r
15845             if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"\r
15846                 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
15847                 copy[_transformProp] = v.transform;\r
15848                 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.\r
15849                 copy.position = "absolute";\r
15850                 _doc.body.appendChild(_tempDiv);\r
15851                 m2 = _getTransform(_tempDiv, null, false);\r
15852                 _doc.body.removeChild(_tempDiv);\r
15853             } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)\r
15854                 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),\r
15855                     scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),\r
15856                     scaleZ:_parseVal(v.scaleZ, m1.scaleZ),\r
15857                     x:_parseVal(v.x, m1.x),\r
15858                     y:_parseVal(v.y, m1.y),\r
15859                     z:_parseVal(v.z, m1.z),\r
15860                     perspective:_parseVal(v.transformPerspective, m1.perspective)};\r
15861                 dr = v.directionalRotation;\r
15862                 if (dr != null) {\r
15863                     if (typeof(dr) === "object") {\r
15864                         for (copy in dr) {\r
15865                             v[copy] = dr[copy];\r
15866                         }\r
15867                     } else {\r
15868                         v.rotation = dr;\r
15869                     }\r
15870                 }\r
15871                 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
15872                 if (_supports3D) {\r
15873                     m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);\r
15874                     m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);\r
15875                 }\r
15876                 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);\r
15877 \r
15878                 //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
15879                 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);\r
15880                 if ((skewY = m2.skewY - m1.skewY)) {\r
15881                     m2.skewX += skewY;\r
15882                     m2.rotation += skewY;\r
15883                 }\r
15884             }\r
15885 \r
15886             if (_supports3D && v.force3D != null) {\r
15887                 m1.force3D = v.force3D;\r
15888                 hasChange = true;\r
15889             }\r
15890 \r
15891             m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;\r
15892 \r
15893             has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);\r
15894             if (!has3D && v.scale != null) {\r
15895                 m2.scaleZ = 1; //no need to tween scaleZ.\r
15896             }\r
15897 \r
15898             while (--i > -1) {\r
15899                 p = _transformProps[i];\r
15900                 orig = m2[p] - m1[p];\r
15901                 if (orig > min || orig < -min || _forcePT[p] != null) {\r
15902                     hasChange = true;\r
15903                     pt = new CSSPropTween(m1, p, m1[p], orig, pt);\r
15904                     if (p in endRotations) {\r
15905                         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
15906                     }\r
15907                     pt.xs0 = 0; //ensures the value stays numeric in setRatio()\r
15908                     pt.plugin = plugin;\r
15909                     cssp._overwriteProps.push(pt.n);\r
15910                 }\r
15911             }\r
15912 \r
15913             orig = v.transformOrigin;\r
15914             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
15915                 if (_transformProp) {\r
15916                     hasChange = true;\r
15917                     p = _transformOriginProp;\r
15918                     orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors\r
15919                     pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");\r
15920                     pt.b = style[p];\r
15921                     pt.plugin = plugin;\r
15922                     if (_supports3D) {\r
15923                         copy = m1.zOrigin;\r
15924                         orig = orig.split(" ");\r
15925                         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
15926                         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
15927                         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
15928                         pt.b = copy;\r
15929                         pt.xs0 = pt.e = m1.zOrigin;\r
15930                     } else {\r
15931                         pt.xs0 = pt.e = orig;\r
15932                     }\r
15933 \r
15934                 //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
15935                 } else {\r
15936                     _parsePosition(orig + "", m1);\r
15937                 }\r
15938             }\r
15939 \r
15940             if (hasChange) {\r
15941                 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();\r
15942             }\r
15943             return pt;\r
15944         }, prefix:true});\r
15945 \r
15946         _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});\r
15947 \r
15948         _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {\r
15949             e = this.format(e);\r
15950             var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],\r
15951                 style = t.style,\r
15952                 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;\r
15953             w = parseFloat(t.offsetWidth);\r
15954             h = parseFloat(t.offsetHeight);\r
15955             ea1 = e.split(" ");\r
15956             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
15957                 if (this.p.indexOf("border")) { //older browsers used a prefix\r
15958                     props[i] = _checkPropPrefix(props[i]);\r
15959                 }\r
15960                 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");\r
15961                 if (bs.indexOf(" ") !== -1) {\r
15962                     bs2 = bs.split(" ");\r
15963                     bs = bs2[0];\r
15964                     bs2 = bs2[1];\r
15965                 }\r
15966                 es = es2 = ea1[i];\r
15967                 bn = parseFloat(bs);\r
15968                 bsfx = bs.substr((bn + "").length);\r
15969                 rel = (es.charAt(1) === "=");\r
15970                 if (rel) {\r
15971                     en = parseInt(es.charAt(0)+"1", 10);\r
15972                     es = es.substr(2);\r
15973                     en *= parseFloat(es);\r
15974                     esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";\r
15975                 } else {\r
15976                     en = parseFloat(es);\r
15977                     esfx = es.substr((en + "").length);\r
15978                 }\r
15979                 if (esfx === "") {\r
15980                     esfx = _suffixMap[p] || bsfx;\r
15981                 }\r
15982                 if (esfx !== bsfx) {\r
15983                     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
15984                     vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number\r
15985                     if (esfx === "%") {\r
15986                         bs = (hn / w * 100) + "%";\r
15987                         bs2 = (vn / h * 100) + "%";\r
15988                     } else if (esfx === "em") {\r
15989                         em = _convertToPixels(t, "borderLeft", 1, "em");\r
15990                         bs = (hn / em) + "em";\r
15991                         bs2 = (vn / em) + "em";\r
15992                     } else {\r
15993                         bs = hn + "px";\r
15994                         bs2 = vn + "px";\r
15995                     }\r
15996                     if (rel) {\r
15997                         es = (parseFloat(bs) + en) + esfx;\r
15998                         es2 = (parseFloat(bs2) + en) + esfx;\r
15999                     }\r
16000                 }\r
16001                 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);\r
16002             }\r
16003             return pt;\r
16004         }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});\r
16005         _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {\r
16006             var bp = "background-position",\r
16007                 cs = (_cs || _getComputedStyle(t, null)),\r
16008                 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
16009                 es = this.format(e),\r
16010                 ba, ea, i, pct, overlap, src;\r
16011             if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {\r
16012                 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");\r
16013                 if (src && src !== "none") {\r
16014                     ba = bs.split(" ");\r
16015                     ea = es.split(" ");\r
16016                     _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height\r
16017                     i = 2;\r
16018                     while (--i > -1) {\r
16019                         bs = ba[i];\r
16020                         pct = (bs.indexOf("%") !== -1);\r
16021                         if (pct !== (ea[i].indexOf("%") !== -1)) {\r
16022                             overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;\r
16023                             ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";\r
16024                         }\r
16025                     }\r
16026                     bs = ba.join(" ");\r
16027                 }\r
16028             }\r
16029             return this.parseComplex(t.style, bs, es, pt, plugin);\r
16030         }, formatter:_parsePosition});\r
16031         _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});\r
16032         _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});\r
16033         _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});\r
16034         _registerComplexSpecialProp("transformStyle", {prefix:true});\r
16035         _registerComplexSpecialProp("backfaceVisibility", {prefix:true});\r
16036         _registerComplexSpecialProp("userSelect", {prefix:true});\r
16037         _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});\r
16038         _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});\r
16039         _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){\r
16040             var b, cs, delim;\r
16041             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
16042                 cs = t.currentStyle;\r
16043                 delim = _ieVers < 8 ? " " : ",";\r
16044                 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";\r
16045                 e = this.format(e).split(",").join(delim);\r
16046             } else {\r
16047                 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));\r
16048                 e = this.format(e);\r
16049             }\r
16050             return this.parseComplex(t.style, b, e, pt, plugin);\r
16051         }});\r
16052         _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});\r
16053         _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)\r
16054         _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {\r
16055                 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
16056             }, color:true, formatter:function(v) {\r
16057                 var a = v.split(" ");\r
16058                 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];\r
16059             }});\r
16060         _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).\r
16061         _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {\r
16062             var s = t.style,\r
16063                 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";\r
16064             return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);\r
16065         }});\r
16066 \r
16067         //opacity-related\r
16068         var _setIEOpacityRatio = function(v) {\r
16069                 var t = this.t, //refers to the element's style property\r
16070                     filters = t.filter || _getStyle(this.data, "filter"),\r
16071                     val = (this.s + this.c * v) | 0,\r
16072                     skip;\r
16073                 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
16074                     if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {\r
16075                         t.removeAttribute("filter");\r
16076                         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
16077                     } else {\r
16078                         t.filter = filters.replace(_alphaFilterExp, "");\r
16079                         skip = true;\r
16080                     }\r
16081                 }\r
16082                 if (!skip) {\r
16083                     if (this.xn1) {\r
16084                         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
16085                     }\r
16086                     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
16087                         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
16088                             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
16089                         }\r
16090                     } else {\r
16091                         t.filter = filters.replace(_opacityExp, "opacity=" + val);\r
16092                     }\r
16093                 }\r
16094             };\r
16095         _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {\r
16096             var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),\r
16097                 style = t.style,\r
16098                 isAutoAlpha = (p === "autoAlpha");\r
16099             if (typeof(e) === "string" && e.charAt(1) === "=") {\r
16100                 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;\r
16101             }\r
16102             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
16103                 b = 0;\r
16104             }\r
16105             if (_supportsOpacity) {\r
16106                 pt = new CSSPropTween(style, "opacity", b, e - b, pt);\r
16107             } else {\r
16108                 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);\r
16109                 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
16110                 style.zoom = 1; //helps correct an IE issue.\r
16111                 pt.type = 2;\r
16112                 pt.b = "alpha(opacity=" + pt.s + ")";\r
16113                 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";\r
16114                 pt.data = t;\r
16115                 pt.plugin = plugin;\r
16116                 pt.setRatio = _setIEOpacityRatio;\r
16117             }\r
16118             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
16119                 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));\r
16120                 pt.xs0 = "inherit";\r
16121                 cssp._overwriteProps.push(pt.n);\r
16122                 cssp._overwriteProps.push(p);\r
16123             }\r
16124             return pt;\r
16125         }});\r
16126 \r
16127 \r
16128         var _removeProp = function(s, p) {\r
16129                 if (p) {\r
16130                     if (s.removeProperty) {\r
16131                         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
16132                             p = "M" + p.substr(1);\r
16133                         }\r
16134                         s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());\r
16135                     } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"\r
16136                         s.removeAttribute(p);\r
16137                     }\r
16138                 }\r
16139             },\r
16140             _setClassNameRatio = function(v) {\r
16141                 this.t._gsClassPT = this;\r
16142                 if (v === 1 || v === 0) {\r
16143                     this.t.setAttribute("class", (v === 0) ? this.b : this.e);\r
16144                     var mpt = this.data, //first MiniPropTween\r
16145                         s = this.t.style;\r
16146                     while (mpt) {\r
16147                         if (!mpt.v) {\r
16148                             _removeProp(s, mpt.p);\r
16149                         } else {\r
16150                             s[mpt.p] = mpt.v;\r
16151                         }\r
16152                         mpt = mpt._next;\r
16153                     }\r
16154                     if (v === 1 && this.t._gsClassPT === this) {\r
16155                         this.t._gsClassPT = null;\r
16156                     }\r
16157                 } else if (this.t.getAttribute("class") !== this.e) {\r
16158                     this.t.setAttribute("class", this.e);\r
16159                 }\r
16160             };\r
16161         _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {\r
16162             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
16163                 cssText = t.style.cssText,\r
16164                 difData, bs, cnpt, cnptLookup, mpt;\r
16165             pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);\r
16166             pt.setRatio = _setClassNameRatio;\r
16167             pt.pr = -11;\r
16168             _hasPriority = true;\r
16169             pt.b = b;\r
16170             bs = _getAllStyles(t, _cs);\r
16171             //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
16172             cnpt = t._gsClassPT;\r
16173             if (cnpt) {\r
16174                 cnptLookup = {};\r
16175                 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
16176                 while (mpt) {\r
16177                     cnptLookup[mpt.p] = 1;\r
16178                     mpt = mpt._next;\r
16179                 }\r
16180                 cnpt.setRatio(1);\r
16181             }\r
16182             t._gsClassPT = pt;\r
16183             pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");\r
16184             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
16185                 t.setAttribute("class", pt.e);\r
16186                 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);\r
16187                 t.setAttribute("class", b);\r
16188                 pt.data = difData.firstMPT;\r
16189                 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
16190                 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
16191             }\r
16192             return pt;\r
16193         }});\r
16194 \r
16195 \r
16196         var _setClearPropsRatio = function(v) {\r
16197             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
16198                 var s = this.t.style,\r
16199                     transformParse = _specialProps.transform.parse,\r
16200                     a, p, i, clearTransform;\r
16201                 if (this.e === "all") {\r
16202                     s.cssText = "";\r
16203                     clearTransform = true;\r
16204                 } else {\r
16205                     a = this.e.split(",");\r
16206                     i = a.length;\r
16207                     while (--i > -1) {\r
16208                         p = a[i];\r
16209                         if (_specialProps[p]) {\r
16210                             if (_specialProps[p].parse === transformParse) {\r
16211                                 clearTransform = true;\r
16212                             } else {\r
16213                                 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
16214                             }\r
16215                         }\r
16216                         _removeProp(s, p);\r
16217                     }\r
16218                 }\r
16219                 if (clearTransform) {\r
16220                     _removeProp(s, _transformProp);\r
16221                     if (this.t._gsTransform) {\r
16222                         delete this.t._gsTransform;\r
16223                     }\r
16224                 }\r
16225 \r
16226             }\r
16227         };\r
16228         _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {\r
16229             pt = new CSSPropTween(t, p, 0, 0, pt, 2);\r
16230             pt.setRatio = _setClearPropsRatio;\r
16231             pt.e = e;\r
16232             pt.pr = -10;\r
16233             pt.data = cssp._tween;\r
16234             _hasPriority = true;\r
16235             return pt;\r
16236         }});\r
16237 \r
16238         p = "bezier,throwProps,physicsProps,physics2D".split(",");\r
16239         i = p.length;\r
16240         while (i--) {\r
16241             _registerPluginProp(p[i]);\r
16242         }\r
16243 \r
16244 \r
16245 \r
16246 \r
16247 \r
16248 \r
16249 \r
16250 \r
16251         p = CSSPlugin.prototype;\r
16252         p._firstPT = null;\r
16253 \r
16254         //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.\r
16255         p._onInitTween = function(target, vars, tween) {\r
16256             if (!target.nodeType) { //css is only for dom elements\r
16257                 return false;\r
16258             }\r
16259             this._target = target;\r
16260             this._tween = tween;\r
16261             this._vars = vars;\r
16262             _autoRound = vars.autoRound;\r
16263             _hasPriority = false;\r
16264             _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;\r
16265             _cs = _getComputedStyle(target, "");\r
16266             _overwriteProps = this._overwriteProps;\r
16267             var style = target.style,\r
16268                 v, pt, pt2, first, last, next, zIndex, tpt, threeD;\r
16269             if (_reqSafariFix) if (style.zIndex === "") {\r
16270                 v = _getStyle(target, "zIndex", _cs);\r
16271                 if (v === "auto" || v === "") {\r
16272                     //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
16273                     this._addLazySet(style, "zIndex", 0);\r
16274                 }\r
16275             }\r
16276 \r
16277             if (typeof(vars) === "string") {\r
16278                 first = style.cssText;\r
16279                 v = _getAllStyles(target, _cs);\r
16280                 style.cssText = first + ";" + vars;\r
16281                 v = _cssDif(target, v, _getAllStyles(target)).difs;\r
16282                 if (!_supportsOpacity && _opacityValExp.test(vars)) {\r
16283                     v.opacity = parseFloat( RegExp.$1 );\r
16284                 }\r
16285                 vars = v;\r
16286                 style.cssText = first;\r
16287             }\r
16288             this._firstPT = pt = this.parse(target, vars, null);\r
16289 \r
16290             if (this._transformType) {\r
16291                 threeD = (this._transformType === 3);\r
16292                 if (!_transformProp) {\r
16293                     style.zoom = 1; //helps correct an IE issue.\r
16294                 } else if (_isSafari) {\r
16295                     _reqSafariFix = true;\r
16296                     //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).\r
16297                     if (style.zIndex === "") {\r
16298                         zIndex = _getStyle(target, "zIndex", _cs);\r
16299                         if (zIndex === "auto" || zIndex === "") {\r
16300                             this._addLazySet(style, "zIndex", 0);\r
16301                         }\r
16302                     }\r
16303                     //Setting WebkitBackfaceVisibility corrects 3 bugs:\r
16304                     // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.\r
16305                     // 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
16306                     // 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
16307                     //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.\r
16308                     if (_isSafariLT6) {\r
16309                         this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));\r
16310                     }\r
16311                 }\r
16312                 pt2 = pt;\r
16313                 while (pt2 && pt2._next) {\r
16314                     pt2 = pt2._next;\r
16315                 }\r
16316                 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);\r
16317                 this._linkCSSP(tpt, null, pt2);\r
16318                 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;\r
16319                 tpt.data = this._transform || _getTransform(target, _cs, true);\r
16320                 _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
16321             }\r
16322 \r
16323             if (_hasPriority) {\r
16324                 //reorders the linked list in order of pr (priority)\r
16325                 while (pt) {\r
16326                     next = pt._next;\r
16327                     pt2 = first;\r
16328                     while (pt2 && pt2.pr > pt.pr) {\r
16329                         pt2 = pt2._next;\r
16330                     }\r
16331                     if ((pt._prev = pt2 ? pt2._prev : last)) {\r
16332                         pt._prev._next = pt;\r
16333                     } else {\r
16334                         first = pt;\r
16335                     }\r
16336                     if ((pt._next = pt2)) {\r
16337                         pt2._prev = pt;\r
16338                     } else {\r
16339                         last = pt;\r
16340                     }\r
16341                     pt = next;\r
16342                 }\r
16343                 this._firstPT = first;\r
16344             }\r
16345             return true;\r
16346         };\r
16347 \r
16348 \r
16349         p.parse = function(target, vars, pt, plugin) {\r
16350             var style = target.style,\r
16351                 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;\r
16352             for (p in vars) {\r
16353                 es = vars[p]; //ending value string\r
16354                 sp = _specialProps[p]; //SpecialProp lookup.\r
16355                 if (sp) {\r
16356                     pt = sp.parse(target, es, p, this, pt, plugin, vars);\r
16357 \r
16358                 } else {\r
16359                     bs = _getStyle(target, p, _cs) + "";\r
16360                     isStr = (typeof(es) === "string");\r
16361                     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
16362                         if (!isStr) {\r
16363                             es = _parseColor(es);\r
16364                             es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";\r
16365                         }\r
16366                         pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);\r
16367 \r
16368                     } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {\r
16369                         pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);\r
16370 \r
16371                     } else {\r
16372                         bn = parseFloat(bs);\r
16373                         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
16374 \r
16375                         if (bs === "" || bs === "auto") {\r
16376                             if (p === "width" || p === "height") {\r
16377                                 bn = _getDimension(target, p, _cs);\r
16378                                 bsfx = "px";\r
16379                             } else if (p === "left" || p === "top") {\r
16380                                 bn = _calculateOffset(target, p, _cs);\r
16381                                 bsfx = "px";\r
16382                             } else {\r
16383                                 bn = (p !== "opacity") ? 0 : 1;\r
16384                                 bsfx = "";\r
16385                             }\r
16386                         }\r
16387 \r
16388                         rel = (isStr && es.charAt(1) === "=");\r
16389                         if (rel) {\r
16390                             en = parseInt(es.charAt(0) + "1", 10);\r
16391                             es = es.substr(2);\r
16392                             en *= parseFloat(es);\r
16393                             esfx = es.replace(_suffixExp, "");\r
16394                         } else {\r
16395                             en = parseFloat(es);\r
16396                             esfx = isStr ? es.substr((en + "").length) || "" : "";\r
16397                         }\r
16398 \r
16399                         if (esfx === "") {\r
16400                             esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.\r
16401                         }\r
16402 \r
16403                         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
16404 \r
16405                         //if the beginning/ending suffixes don't match, normalize them...\r
16406                         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
16407                             bn = _convertToPixels(target, p, bn, bsfx);\r
16408                             if (esfx === "%") {\r
16409                                 bn /= _convertToPixels(target, p, 100, "%") / 100;\r
16410                                 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
16411                                     bs = bn + "%";\r
16412                                 }\r
16413 \r
16414                             } else if (esfx === "em") {\r
16415                                 bn /= _convertToPixels(target, p, 1, "em");\r
16416 \r
16417                             //otherwise convert to pixels.\r
16418                             } else if (esfx !== "px") {\r
16419                                 en = _convertToPixels(target, p, en, esfx);\r
16420                                 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.\r
16421                             }\r
16422                             if (rel) if (en || en === 0) {\r
16423                                 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.\r
16424                             }\r
16425                         }\r
16426 \r
16427                         if (rel) {\r
16428                             en += bn;\r
16429                         }\r
16430 \r
16431                         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
16432                             pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);\r
16433                             pt.xs0 = esfx;\r
16434                             //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);\r
16435                         } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {\r
16436                             _log("invalid " + p + " tween value: " + vars[p]);\r
16437                         } else {\r
16438                             pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);\r
16439                             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
16440                             //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);\r
16441                         }\r
16442                     }\r
16443                 }\r
16444                 if (plugin) if (pt && !pt.plugin) {\r
16445                     pt.plugin = plugin;\r
16446                 }\r
16447             }\r
16448             return pt;\r
16449         };\r
16450 \r
16451 \r
16452         //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
16453         p.setRatio = function(v) {\r
16454             var pt = this._firstPT,\r
16455                 min = 0.000001,\r
16456                 val, str, i;\r
16457 \r
16458             //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
16459             if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {\r
16460                 while (pt) {\r
16461                     if (pt.type !== 2) {\r
16462                         pt.t[pt.p] = pt.e;\r
16463                     } else {\r
16464                         pt.setRatio(v);\r
16465                     }\r
16466                     pt = pt._next;\r
16467                 }\r
16468 \r
16469             } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {\r
16470                 while (pt) {\r
16471                     val = pt.c * v + pt.s;\r
16472                     if (pt.r) {\r
16473                         val = Math.round(val);\r
16474                     } else if (val < min) if (val > -min) {\r
16475                         val = 0;\r
16476                     }\r
16477                     if (!pt.type) {\r
16478                         pt.t[pt.p] = val + pt.xs0;\r
16479                     } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"\r
16480                         i = pt.l;\r
16481                         if (i === 2) {\r
16482                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;\r
16483                         } else if (i === 3) {\r
16484                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;\r
16485                         } else if (i === 4) {\r
16486                             pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;\r
16487                         } else if (i === 5) {\r
16488                             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
16489                         } else {\r
16490                             str = pt.xs0 + val + pt.xs1;\r
16491                             for (i = 1; i < pt.l; i++) {\r
16492                                 str += pt["xn"+i] + pt["xs"+(i+1)];\r
16493                             }\r
16494                             pt.t[pt.p] = str;\r
16495                         }\r
16496 \r
16497                     } else if (pt.type === -1) { //non-tweening value\r
16498                         pt.t[pt.p] = pt.xs0;\r
16499 \r
16500                     } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.\r
16501                         pt.setRatio(v);\r
16502                     }\r
16503                     pt = pt._next;\r
16504                 }\r
16505 \r
16506             //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
16507             } else {\r
16508                 while (pt) {\r
16509                     if (pt.type !== 2) {\r
16510                         pt.t[pt.p] = pt.b;\r
16511                     } else {\r
16512                         pt.setRatio(v);\r
16513                     }\r
16514                     pt = pt._next;\r
16515                 }\r
16516             }\r
16517         };\r
16518 \r
16519         /**\r
16520          * @private\r
16521          * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.\r
16522          * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked\r
16523          * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call\r
16524          * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin\r
16525          * doesn't have any transform-related properties of its own. You can call this method as many times as you\r
16526          * want and it won't create duplicate CSSPropTweens.\r
16527          *\r
16528          * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)\r
16529          */\r
16530         p._enableTransforms = function(threeD) {\r
16531             this._transformType = (threeD || this._transformType === 3) ? 3 : 2;\r
16532             this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.\r
16533         };\r
16534 \r
16535         var lazySet = function(v) {\r
16536             this.t[this.p] = this.e;\r
16537             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
16538         };\r
16539         /** @private Gives us a way to set a value on the first render (and only the first render). **/\r
16540         p._addLazySet = function(t, p, v) {\r
16541             var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);\r
16542             pt.e = v;\r
16543             pt.setRatio = lazySet;\r
16544             pt.data = this;\r
16545         };\r
16546 \r
16547         /** @private **/\r
16548         p._linkCSSP = function(pt, next, prev, remove) {\r
16549             if (pt) {\r
16550                 if (next) {\r
16551                     next._prev = pt;\r
16552                 }\r
16553                 if (pt._next) {\r
16554                     pt._next._prev = pt._prev;\r
16555                 }\r
16556                 if (pt._prev) {\r
16557                     pt._prev._next = pt._next;\r
16558                 } else if (this._firstPT === pt) {\r
16559                     this._firstPT = pt._next;\r
16560                     remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)\r
16561                 }\r
16562                 if (prev) {\r
16563                     prev._next = pt;\r
16564                 } else if (!remove && this._firstPT === null) {\r
16565                     this._firstPT = pt;\r
16566                 }\r
16567                 pt._next = next;\r
16568                 pt._prev = prev;\r
16569             }\r
16570             return pt;\r
16571         };\r
16572 \r
16573         //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.\r
16574         p._kill = function(lookup) {\r
16575             var copy = lookup,\r
16576                 pt, p, xfirst;\r
16577             if (lookup.autoAlpha || lookup.alpha) {\r
16578                 copy = {};\r
16579                 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.\r
16580                     copy[p] = lookup[p];\r
16581                 }\r
16582                 copy.opacity = 1;\r
16583                 if (copy.autoAlpha) {\r
16584                     copy.visibility = 1;\r
16585                 }\r
16586             }\r
16587             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
16588                 xfirst = pt.xfirst;\r
16589                 if (xfirst && xfirst._prev) {\r
16590                     this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev\r
16591                 } else if (xfirst === this._firstPT) {\r
16592                     this._firstPT = pt._next;\r
16593                 }\r
16594                 if (pt._next) {\r
16595                     this._linkCSSP(pt._next, pt._next._next, xfirst._prev);\r
16596                 }\r
16597                 this._classNamePT = null;\r
16598             }\r
16599             return TweenPlugin.prototype._kill.call(this, copy);\r
16600         };\r
16601 \r
16602 \r
16603 \r
16604         //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.\r
16605         var _getChildStyles = function(e, props, targets) {\r
16606                 var children, i, child, type;\r
16607                 if (e.slice) {\r
16608                     i = e.length;\r
16609                     while (--i > -1) {\r
16610                         _getChildStyles(e[i], props, targets);\r
16611                     }\r
16612                     return;\r
16613                 }\r
16614                 children = e.childNodes;\r
16615                 i = children.length;\r
16616                 while (--i > -1) {\r
16617                     child = children[i];\r
16618                     type = child.type;\r
16619                     if (child.style) {\r
16620                         props.push(_getAllStyles(child));\r
16621                         if (targets) {\r
16622                             targets.push(child);\r
16623                         }\r
16624                     }\r
16625                     if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {\r
16626                         _getChildStyles(child, props, targets);\r
16627                     }\r
16628                 }\r
16629             };\r
16630 \r
16631         /**\r
16632          * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite\r
16633          * and then compares the style properties of all the target's child elements at the tween's start and end, and\r
16634          * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting\r
16635          * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is\r
16636          * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens\r
16637          * is because it creates entirely new tweens that may have completely different targets than the original tween,\r
16638          * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API\r
16639          * and it would create other problems. For example:\r
16640          *  - 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
16641          *  - 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
16642          *  - 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
16643          *\r
16644          * @param {Object} target object to be tweened\r
16645          * @param {number} Duration in seconds (or frames for frames-based tweens)\r
16646          * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}\r
16647          * @return {Array} An array of TweenLite instances\r
16648          */\r
16649         CSSPlugin.cascadeTo = function(target, duration, vars) {\r
16650             var tween = TweenLite.to(target, duration, vars),\r
16651                 results = [tween],\r
16652                 b = [],\r
16653                 e = [],\r
16654                 targets = [],\r
16655                 _reservedProps = TweenLite._internals.reservedProps,\r
16656                 i, difs, p;\r
16657             target = tween._targets || tween.target;\r
16658             _getChildStyles(target, b, targets);\r
16659             tween.render(duration, true);\r
16660             _getChildStyles(target, e);\r
16661             tween.render(0, true);\r
16662             tween._enabled(true);\r
16663             i = targets.length;\r
16664             while (--i > -1) {\r
16665                 difs = _cssDif(targets[i], b[i], e[i]);\r
16666                 if (difs.firstMPT) {\r
16667                     difs = difs.difs;\r
16668                     for (p in vars) {\r
16669                         if (_reservedProps[p]) {\r
16670                             difs[p] = vars[p];\r
16671                         }\r
16672                     }\r
16673                     results.push( TweenLite.to(targets[i], duration, difs) );\r
16674                 }\r
16675             }\r
16676             return results;\r
16677         };\r
16678 \r
16679         TweenPlugin.activate([CSSPlugin]);\r
16680         return CSSPlugin;\r
16681 \r
16682     }, true);\r
16683 \r
16684     \r
16685     \r
16686     \r
16687     \r
16688     \r
16689     \r
16690     \r
16691     \r
16692     \r
16693     \r
16694 /*\r
16695  * ----------------------------------------------------------------\r
16696  * RoundPropsPlugin\r
16697  * ----------------------------------------------------------------\r
16698  */\r
16699     (function() {\r
16700 \r
16701         var RoundPropsPlugin = window._gsDefine.plugin({\r
16702                 propName: "roundProps",\r
16703                 priority: -1,\r
16704                 API: 2,\r
16705 \r
16706                 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
16707                 init: function(target, value, tween) {\r
16708                     this._tween = tween;\r
16709                     return true;\r
16710                 }\r
16711 \r
16712             }),\r
16713             p = RoundPropsPlugin.prototype;\r
16714 \r
16715         p._onInitAllProps = function() {\r
16716             var tween = this._tween,\r
16717                 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),\r
16718                 i = rp.length,\r
16719                 lookup = {},\r
16720                 rpt = tween._propLookup.roundProps,\r
16721                 prop, pt, next;\r
16722             while (--i > -1) {\r
16723                 lookup[rp[i]] = 1;\r
16724             }\r
16725             i = rp.length;\r
16726             while (--i > -1) {\r
16727                 prop = rp[i];\r
16728                 pt = tween._firstPT;\r
16729                 while (pt) {\r
16730                     next = pt._next; //record here, because it may get removed\r
16731                     if (pt.pg) {\r
16732                         pt.t._roundProps(lookup, true);\r
16733                     } else if (pt.n === prop) {\r
16734                         this._add(pt.t, prop, pt.s, pt.c);\r
16735                         //remove from linked list\r
16736                         if (next) {\r
16737                             next._prev = pt._prev;\r
16738                         }\r
16739                         if (pt._prev) {\r
16740                             pt._prev._next = next;\r
16741                         } else if (tween._firstPT === pt) {\r
16742                             tween._firstPT = next;\r
16743                         }\r
16744                         pt._next = pt._prev = null;\r
16745                         tween._propLookup[prop] = rpt;\r
16746                     }\r
16747                     pt = next;\r
16748                 }\r
16749             }\r
16750             return false;\r
16751         };\r
16752 \r
16753         p._add = function(target, p, s, c) {\r
16754             this._addTween(target, p, s, s + c, p, true);\r
16755             this._overwriteProps.push(p);\r
16756         };\r
16757 \r
16758     }());\r
16759 \r
16760 \r
16761 \r
16762 \r
16763 \r
16764 \r
16765 \r
16766 \r
16767 \r
16768 \r
16769 /*\r
16770  * ----------------------------------------------------------------\r
16771  * AttrPlugin\r
16772  * ----------------------------------------------------------------\r
16773  */\r
16774     window._gsDefine.plugin({\r
16775         propName: "attr",\r
16776         API: 2,\r
16777         version: "0.3.2",\r
16778 \r
16779         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
16780         init: function(target, value, tween) {\r
16781             var p, start, end;\r
16782             if (typeof(target.setAttribute) !== "function") {\r
16783                 return false;\r
16784             }\r
16785             this._target = target;\r
16786             this._proxy = {};\r
16787             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
16788             this._end = {};\r
16789             for (p in value) {\r
16790                 this._start[p] = this._proxy[p] = start = target.getAttribute(p);\r
16791                 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);\r
16792                 this._end[p] = end ? end.s + end.c : value[p];\r
16793                 this._overwriteProps.push(p);\r
16794             }\r
16795             return true;\r
16796         },\r
16797 \r
16798         //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
16799         set: function(ratio) {\r
16800             this._super.setRatio.call(this, ratio);\r
16801             var props = this._overwriteProps,\r
16802                 i = props.length,\r
16803                 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,\r
16804                 p;\r
16805             while (--i > -1) {\r
16806                 p = props[i];\r
16807                 this._target.setAttribute(p, lookup[p] + "");\r
16808             }\r
16809         }\r
16810 \r
16811     });\r
16812 \r
16813 \r
16814 \r
16815 \r
16816 \r
16817 \r
16818 \r
16819 \r
16820 \r
16821 \r
16822 /*\r
16823  * ----------------------------------------------------------------\r
16824  * DirectionalRotationPlugin\r
16825  * ----------------------------------------------------------------\r
16826  */\r
16827     window._gsDefine.plugin({\r
16828         propName: "directionalRotation",\r
16829         API: 2,\r
16830         version: "0.2.0",\r
16831 \r
16832         //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.\r
16833         init: function(target, value, tween) {\r
16834             if (typeof(value) !== "object") {\r
16835                 value = {rotation:value};\r
16836             }\r
16837             this.finals = {};\r
16838             var cap = (value.useRadians === true) ? Math.PI * 2 : 360,\r
16839                 min = 0.000001,\r
16840                 p, v, start, end, dif, split;\r
16841             for (p in value) {\r
16842                 if (p !== "useRadians") {\r
16843                     split = (value[p] + "").split("_");\r
16844                     v = split[0];\r
16845                     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
16846                     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
16847                     dif = end - start;\r
16848                     if (split.length) {\r
16849                         v = split.join("_");\r
16850                         if (v.indexOf("short") !== -1) {\r
16851                             dif = dif % cap;\r
16852                             if (dif !== dif % (cap / 2)) {\r
16853                                 dif = (dif < 0) ? dif + cap : dif - cap;\r
16854                             }\r
16855                         }\r
16856                         if (v.indexOf("_cw") !== -1 && dif < 0) {\r
16857                             dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
16858                         } else if (v.indexOf("ccw") !== -1 && dif > 0) {\r
16859                             dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;\r
16860                         }\r
16861                     }\r
16862                     if (dif > min || dif < -min) {\r
16863                         this._addTween(target, p, start, start + dif, p);\r
16864                         this._overwriteProps.push(p);\r
16865                     }\r
16866                 }\r
16867             }\r
16868             return true;\r
16869         },\r
16870 \r
16871         //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
16872         set: function(ratio) {\r
16873             var pt;\r
16874             if (ratio !== 1) {\r
16875                 this._super.setRatio.call(this, ratio);\r
16876             } else {\r
16877                 pt = this._firstPT;\r
16878                 while (pt) {\r
16879                     if (pt.f) {\r
16880                         pt.t[pt.p](this.finals[pt.p]);\r
16881                     } else {\r
16882                         pt.t[pt.p] = this.finals[pt.p];\r
16883                     }\r
16884                     pt = pt._next;\r
16885                 }\r
16886             }\r
16887         }\r
16888 \r
16889     })._autoCSS = true;\r
16890 \r
16891 \r
16892 \r
16893 \r
16894 \r
16895 \r
16896 \r
16897     \r
16898     \r
16899     \r
16900     \r
16901 /*\r
16902  * ----------------------------------------------------------------\r
16903  * EasePack\r
16904  * ----------------------------------------------------------------\r
16905  */\r
16906     window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {\r
16907         \r
16908         var w = (window.GreenSockGlobals || window),\r
16909             gs = w.com.greensock,\r
16910             _2PI = Math.PI * 2,\r
16911             _HALF_PI = Math.PI / 2,\r
16912             _class = gs._class,\r
16913             _create = function(n, f) {\r
16914                 var C = _class("easing." + n, function(){}, true),\r
16915                     p = C.prototype = new Ease();\r
16916                 p.constructor = C;\r
16917                 p.getRatio = f;\r
16918                 return C;\r
16919             },\r
16920             _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
16921             _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {\r
16922                 var C = _class("easing."+name, {\r
16923                     easeOut:new EaseOut(),\r
16924                     easeIn:new EaseIn(),\r
16925                     easeInOut:new EaseInOut()\r
16926                 }, true);\r
16927                 _easeReg(C, name);\r
16928                 return C;\r
16929             },\r
16930             EasePoint = function(time, value, next) {\r
16931                 this.t = time;\r
16932                 this.v = value;\r
16933                 if (next) {\r
16934                     this.next = next;\r
16935                     next.prev = this;\r
16936                     this.c = next.v - value;\r
16937                     this.gap = next.t - time;\r
16938                 }\r
16939             },\r
16940 \r
16941             //Back\r
16942             _createBack = function(n, f) {\r
16943                 var C = _class("easing." + n, function(overshoot) {\r
16944                         this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;\r
16945                         this._p2 = this._p1 * 1.525;\r
16946                     }, true),\r
16947                     p = C.prototype = new Ease();\r
16948                 p.constructor = C;\r
16949                 p.getRatio = f;\r
16950                 p.config = function(overshoot) {\r
16951                     return new C(overshoot);\r
16952                 };\r
16953                 return C;\r
16954             },\r
16955 \r
16956             Back = _wrap("Back",\r
16957                 _createBack("BackOut", function(p) {\r
16958                     return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);\r
16959                 }),\r
16960                 _createBack("BackIn", function(p) {\r
16961                     return p * p * ((this._p1 + 1) * p - this._p1);\r
16962                 }),\r
16963                 _createBack("BackInOut", function(p) {\r
16964                     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
16965                 })\r
16966             ),\r
16967 \r
16968 \r
16969             //SlowMo\r
16970             SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {\r
16971                 power = (power || power === 0) ? power : 0.7;\r
16972                 if (linearRatio == null) {\r
16973                     linearRatio = 0.7;\r
16974                 } else if (linearRatio > 1) {\r
16975                     linearRatio = 1;\r
16976                 }\r
16977                 this._p = (linearRatio !== 1) ? power : 0;\r
16978                 this._p1 = (1 - linearRatio) / 2;\r
16979                 this._p2 = linearRatio;\r
16980                 this._p3 = this._p1 + this._p2;\r
16981                 this._calcEnd = (yoyoMode === true);\r
16982             }, true),\r
16983             p = SlowMo.prototype = new Ease(),\r
16984             SteppedEase, RoughEase, _createElastic;\r
16985 \r
16986         p.constructor = SlowMo;\r
16987         p.getRatio = function(p) {\r
16988             var r = p + (0.5 - p) * this._p;\r
16989             if (p < this._p1) {\r
16990                 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);\r
16991             } else if (p > this._p3) {\r
16992                 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);\r
16993             }\r
16994             return this._calcEnd ? 1 : r;\r
16995         };\r
16996         SlowMo.ease = new SlowMo(0.7, 0.7);\r
16997 \r
16998         p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {\r
16999             return new SlowMo(linearRatio, power, yoyoMode);\r
17000         };\r
17001 \r
17002 \r
17003         //SteppedEase\r
17004         SteppedEase = _class("easing.SteppedEase", function(steps) {\r
17005                 steps = steps || 1;\r
17006                 this._p1 = 1 / steps;\r
17007                 this._p2 = steps + 1;\r
17008             }, true);\r
17009         p = SteppedEase.prototype = new Ease();\r
17010         p.constructor = SteppedEase;\r
17011         p.getRatio = function(p) {\r
17012             if (p < 0) {\r
17013                 p = 0;\r
17014             } else if (p >= 1) {\r
17015                 p = 0.999999999;\r
17016             }\r
17017             return ((this._p2 * p) >> 0) * this._p1;\r
17018         };\r
17019         p.config = SteppedEase.config = function(steps) {\r
17020             return new SteppedEase(steps);\r
17021         };\r
17022 \r
17023 \r
17024         //RoughEase\r
17025         RoughEase = _class("easing.RoughEase", function(vars) {\r
17026             vars = vars || {};\r
17027             var taper = vars.taper || "none",\r
17028                 a = [],\r
17029                 cnt = 0,\r
17030                 points = (vars.points || 20) | 0,\r
17031                 i = points,\r
17032                 randomize = (vars.randomize !== false),\r
17033                 clamp = (vars.clamp === true),\r
17034                 template = (vars.template instanceof Ease) ? vars.template : null,\r
17035                 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,\r
17036                 x, y, bump, invX, obj, pnt;\r
17037             while (--i > -1) {\r
17038                 x = randomize ? Math.random() : (1 / points) * i;\r
17039                 y = template ? template.getRatio(x) : x;\r
17040                 if (taper === "none") {\r
17041                     bump = strength;\r
17042                 } else if (taper === "out") {\r
17043                     invX = 1 - x;\r
17044                     bump = invX * invX * strength;\r
17045                 } else if (taper === "in") {\r
17046                     bump = x * x * strength;\r
17047                 } else if (x < 0.5) {  //"both" (start)\r
17048                     invX = x * 2;\r
17049                     bump = invX * invX * 0.5 * strength;\r
17050                 } else {                //"both" (end)\r
17051                     invX = (1 - x) * 2;\r
17052                     bump = invX * invX * 0.5 * strength;\r
17053                 }\r
17054                 if (randomize) {\r
17055                     y += (Math.random() * bump) - (bump * 0.5);\r
17056                 } else if (i % 2) {\r
17057                     y += bump * 0.5;\r
17058                 } else {\r
17059                     y -= bump * 0.5;\r
17060                 }\r
17061                 if (clamp) {\r
17062                     if (y > 1) {\r
17063                         y = 1;\r
17064                     } else if (y < 0) {\r
17065                         y = 0;\r
17066                     }\r
17067                 }\r
17068                 a[cnt++] = {x:x, y:y};\r
17069             }\r
17070             a.sort(function(a, b) {\r
17071                 return a.x - b.x;\r
17072             });\r
17073 \r
17074             pnt = new EasePoint(1, 1, null);\r
17075             i = points;\r
17076             while (--i > -1) {\r
17077                 obj = a[i];\r
17078                 pnt = new EasePoint(obj.x, obj.y, pnt);\r
17079             }\r
17080 \r
17081             this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);\r
17082         }, true);\r
17083         p = RoughEase.prototype = new Ease();\r
17084         p.constructor = RoughEase;\r
17085         p.getRatio = function(p) {\r
17086             var pnt = this._prev;\r
17087             if (p > pnt.t) {\r
17088                 while (pnt.next && p >= pnt.t) {\r
17089                     pnt = pnt.next;\r
17090                 }\r
17091                 pnt = pnt.prev;\r
17092             } else {\r
17093                 while (pnt.prev && p <= pnt.t) {\r
17094                     pnt = pnt.prev;\r
17095                 }\r
17096             }\r
17097             this._prev = pnt;\r
17098             return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);\r
17099         };\r
17100         p.config = function(vars) {\r
17101             return new RoughEase(vars);\r
17102         };\r
17103         RoughEase.ease = new RoughEase();\r
17104 \r
17105 \r
17106         //Bounce\r
17107         _wrap("Bounce",\r
17108             _create("BounceOut", function(p) {\r
17109                 if (p < 1 / 2.75) {\r
17110                     return 7.5625 * p * p;\r
17111                 } else if (p < 2 / 2.75) {\r
17112                     return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;\r
17113                 } else if (p < 2.5 / 2.75) {\r
17114                     return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;\r
17115                 }\r
17116                 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;\r
17117             }),\r
17118             _create("BounceIn", function(p) {\r
17119                 if ((p = 1 - p) < 1 / 2.75) {\r
17120                     return 1 - (7.5625 * p * p);\r
17121                 } else if (p < 2 / 2.75) {\r
17122                     return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);\r
17123                 } else if (p < 2.5 / 2.75) {\r
17124                     return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);\r
17125                 }\r
17126                 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);\r
17127             }),\r
17128             _create("BounceInOut", function(p) {\r
17129                 var invert = (p < 0.5);\r
17130                 if (invert) {\r
17131                     p = 1 - (p * 2);\r
17132                 } else {\r
17133                     p = (p * 2) - 1;\r
17134                 }\r
17135                 if (p < 1 / 2.75) {\r
17136                     p = 7.5625 * p * p;\r
17137                 } else if (p < 2 / 2.75) {\r
17138                     p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;\r
17139                 } else if (p < 2.5 / 2.75) {\r
17140                     p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;\r
17141                 } else {\r
17142                     p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;\r
17143                 }\r
17144                 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;\r
17145             })\r
17146         );\r
17147 \r
17148 \r
17149         //CIRC\r
17150         _wrap("Circ",\r
17151             _create("CircOut", function(p) {\r
17152                 return Math.sqrt(1 - (p = p - 1) * p);\r
17153             }),\r
17154             _create("CircIn", function(p) {\r
17155                 return -(Math.sqrt(1 - (p * p)) - 1);\r
17156             }),\r
17157             _create("CircInOut", function(p) {\r
17158                 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);\r
17159             })\r
17160         );\r
17161 \r
17162 \r
17163         //Elastic\r
17164         _createElastic = function(n, f, def) {\r
17165             var C = _class("easing." + n, function(amplitude, period) {\r
17166                     this._p1 = amplitude || 1;\r
17167                     this._p2 = period || def;\r
17168                     this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);\r
17169                 }, true),\r
17170                 p = C.prototype = new Ease();\r
17171             p.constructor = C;\r
17172             p.getRatio = f;\r
17173             p.config = function(amplitude, period) {\r
17174                 return new C(amplitude, period);\r
17175             };\r
17176             return C;\r
17177         };\r
17178         _wrap("Elastic",\r
17179             _createElastic("ElasticOut", function(p) {\r
17180                 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;\r
17181             }, 0.3),\r
17182             _createElastic("ElasticIn", function(p) {\r
17183                 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));\r
17184             }, 0.3),\r
17185             _createElastic("ElasticInOut", function(p) {\r
17186                 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
17187             }, 0.45)\r
17188         );\r
17189 \r
17190 \r
17191         //Expo\r
17192         _wrap("Expo",\r
17193             _create("ExpoOut", function(p) {\r
17194                 return 1 - Math.pow(2, -10 * p);\r
17195             }),\r
17196             _create("ExpoIn", function(p) {\r
17197                 return Math.pow(2, 10 * (p - 1)) - 0.001;\r
17198             }),\r
17199             _create("ExpoInOut", function(p) {\r
17200                 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));\r
17201             })\r
17202         );\r
17203 \r
17204 \r
17205         //Sine\r
17206         _wrap("Sine",\r
17207             _create("SineOut", function(p) {\r
17208                 return Math.sin(p * _HALF_PI);\r
17209             }),\r
17210             _create("SineIn", function(p) {\r
17211                 return -Math.cos(p * _HALF_PI) + 1;\r
17212             }),\r
17213             _create("SineInOut", function(p) {\r
17214                 return -0.5 * (Math.cos(Math.PI * p) - 1);\r
17215             })\r
17216         );\r
17217 \r
17218         _class("easing.EaseLookup", {\r
17219                 find:function(s) {\r
17220                     return Ease.map[s];\r
17221                 }\r
17222             }, true);\r
17223 \r
17224         //register the non-standard eases\r
17225         _easeReg(w.SlowMo, "SlowMo", "ease,");\r
17226         _easeReg(RoughEase, "RoughEase", "ease,");\r
17227         _easeReg(SteppedEase, "SteppedEase", "ease,");\r
17228 \r
17229         return Back;\r
17230         \r
17231     }, true);\r
17232 \r
17233 \r
17234 }); \r
17235 \r
17236 \r
17237 \r
17238 \r
17239 \r
17240 \r
17241 \r
17242 \r
17243 \r
17244 \r
17245 \r
17246 /*\r
17247  * ----------------------------------------------------------------\r
17248  * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.\r
17249  * ----------------------------------------------------------------\r
17250  */\r
17251 (function(window) {\r
17252 \r
17253         "use strict";\r
17254         var _globals = window.GreenSockGlobals || window;\r
17255         if (_globals.TweenLite) {\r
17256             return; //in case the core set of classes is already loaded, don't instantiate twice.\r
17257         }\r
17258         var _namespace = function(ns) {\r
17259                 var a = ns.split("."),\r
17260                     p = _globals, i;\r
17261                 for (i = 0; i < a.length; i++) {\r
17262                     p[a[i]] = p = p[a[i]] || {};\r
17263                 }\r
17264                 return p;\r
17265             },\r
17266             gs = _namespace("com.greensock"),\r
17267             _tinyNum = 0.0000000001,\r
17268             _slice = [].slice,\r
17269             _emptyFunc = function() {},\r
17270             _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
17271                 var toString = Object.prototype.toString,\r
17272                     array = toString.call([]);\r
17273                 return function(obj) {\r
17274                     return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));\r
17275                 };\r
17276             }()),\r
17277             a, i, p, _ticker, _tickerActive,\r
17278             _defLookup = {},\r
17279 \r
17280             /**\r
17281              * @constructor\r
17282              * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.\r
17283              * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is\r
17284              * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin\r
17285              * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.\r
17286              *\r
17287              * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,\r
17288              * 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
17289              * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so\r
17290              * 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
17291              * 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
17292              * 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
17293              * sandbox the banner one like:\r
17294              *\r
17295              * <script>\r
17296              *     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
17297              * </script>\r
17298              * <script src="js/greensock/v1.7/TweenMax.js"></script>\r
17299              * <script>\r
17300              *     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
17301              * </script>\r
17302              * <script src="js/greensock/v1.6/TweenMax.js"></script>\r
17303              * <script>\r
17304              *     gs.TweenLite.to(...); //would use v1.7\r
17305              *     TweenLite.to(...); //would use v1.6\r
17306              * </script>\r
17307              *\r
17308              * @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
17309              * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]\r
17310              * @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
17311              * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)\r
17312              */\r
17313             Definition = function(ns, dependencies, func, global) {\r
17314                 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses\r
17315                 _defLookup[ns] = this;\r
17316                 this.gsClass = null;\r
17317                 this.func = func;\r
17318                 var _classes = [];\r
17319                 this.check = function(init) {\r
17320                     var i = dependencies.length,\r
17321                         missing = i,\r
17322                         cur, a, n, cl;\r
17323                     while (--i > -1) {\r
17324                         if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {\r
17325                             _classes[i] = cur.gsClass;\r
17326                             missing--;\r
17327                         } else if (init) {\r
17328                             cur.sc.push(this);\r
17329                         }\r
17330                     }\r
17331                     if (missing === 0 && func) {\r
17332                         a = ("com.greensock." + ns).split(".");\r
17333                         n = a.pop();\r
17334                         cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);\r
17335 \r
17336                         //exports to multiple environments\r
17337                         if (global) {\r
17338                             _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
17339                             if (typeof(define) === "function" && define.amd){ //AMD\r
17340                                 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });\r
17341                             } else if (typeof(module) !== "undefined" && module.exports){ //node\r
17342                                 module.exports = cl;\r
17343                             }\r
17344                         }\r
17345                         for (i = 0; i < this.sc.length; i++) {\r
17346                             this.sc[i].check();\r
17347                         }\r
17348                     }\r
17349                 };\r
17350                 this.check(true);\r
17351             },\r
17352 \r
17353             //used to create Definition instances (which basically registers a class that has dependencies).\r
17354             _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {\r
17355                 return new Definition(ns, dependencies, func, global);\r
17356             },\r
17357 \r
17358             //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
17359             _class = gs._class = function(ns, func, global) {\r
17360                 func = func || function() {};\r
17361                 _gsDefine(ns, [], function(){ return func; }, global);\r
17362                 return func;\r
17363             };\r
17364 \r
17365         _gsDefine.globals = _globals;\r
17366 \r
17367 \r
17368 \r
17369 /*\r
17370  * ----------------------------------------------------------------\r
17371  * Ease\r
17372  * ----------------------------------------------------------------\r
17373  */\r
17374         var _baseParams = [0, 0, 1, 1],\r
17375             _blankArray = [],\r
17376             Ease = _class("easing.Ease", function(func, extraParams, type, power) {\r
17377                 this._func = func;\r
17378                 this._type = type || 0;\r
17379                 this._power = power || 0;\r
17380                 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;\r
17381             }, true),\r
17382             _easeMap = Ease.map = {},\r
17383             _easeReg = Ease.register = function(ease, names, types, create) {\r
17384                 var na = names.split(","),\r
17385                     i = na.length,\r
17386                     ta = (types || "easeIn,easeOut,easeInOut").split(","),\r
17387                     e, name, j, type;\r
17388                 while (--i > -1) {\r
17389                     name = na[i];\r
17390                     e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};\r
17391                     j = ta.length;\r
17392                     while (--j > -1) {\r
17393                         type = ta[j];\r
17394                         _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();\r
17395                     }\r
17396                 }\r
17397             };\r
17398 \r
17399         p = Ease.prototype;\r
17400         p._calcEnd = false;\r
17401         p.getRatio = function(p) {\r
17402             if (this._func) {\r
17403                 this._params[0] = p;\r
17404                 return this._func.apply(null, this._params);\r
17405             }\r
17406             var t = this._type,\r
17407                 pw = this._power,\r
17408                 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;\r
17409             if (pw === 1) {\r
17410                 r *= r;\r
17411             } else if (pw === 2) {\r
17412                 r *= r * r;\r
17413             } else if (pw === 3) {\r
17414                 r *= r * r * r;\r
17415             } else if (pw === 4) {\r
17416                 r *= r * r * r * r;\r
17417             }\r
17418             return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);\r
17419         };\r
17420 \r
17421         //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
17422         a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];\r
17423         i = a.length;\r
17424         while (--i > -1) {\r
17425             p = a[i]+",Power"+i;\r
17426             _easeReg(new Ease(null,null,1,i), p, "easeOut", true);\r
17427             _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));\r
17428             _easeReg(new Ease(null,null,3,i), p, "easeInOut");\r
17429         }\r
17430         _easeMap.linear = gs.easing.Linear.easeIn;\r
17431         _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks\r
17432 \r
17433 \r
17434 /*\r
17435  * ----------------------------------------------------------------\r
17436  * EventDispatcher\r
17437  * ----------------------------------------------------------------\r
17438  */\r
17439         var EventDispatcher = _class("events.EventDispatcher", function(target) {\r
17440             this._listeners = {};\r
17441             this._eventTarget = target || this;\r
17442         });\r
17443         p = EventDispatcher.prototype;\r
17444 \r
17445         p.addEventListener = function(type, callback, scope, useParam, priority) {\r
17446             priority = priority || 0;\r
17447             var list = this._listeners[type],\r
17448                 index = 0,\r
17449                 listener, i;\r
17450             if (list == null) {\r
17451                 this._listeners[type] = list = [];\r
17452             }\r
17453             i = list.length;\r
17454             while (--i > -1) {\r
17455                 listener = list[i];\r
17456                 if (listener.c === callback && listener.s === scope) {\r
17457                     list.splice(i, 1);\r
17458                 } else if (index === 0 && listener.pr < priority) {\r
17459                     index = i + 1;\r
17460                 }\r
17461             }\r
17462             list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});\r
17463             if (this === _ticker && !_tickerActive) {\r
17464                 _ticker.wake();\r
17465             }\r
17466         };\r
17467 \r
17468         p.removeEventListener = function(type, callback) {\r
17469             var list = this._listeners[type], i;\r
17470             if (list) {\r
17471                 i = list.length;\r
17472                 while (--i > -1) {\r
17473                     if (list[i].c === callback) {\r
17474                         list.splice(i, 1);\r
17475                         return;\r
17476                     }\r
17477                 }\r
17478             }\r
17479         };\r
17480 \r
17481         p.dispatchEvent = function(type) {\r
17482             var list = this._listeners[type],\r
17483                 i, t, listener;\r
17484             if (list) {\r
17485                 i = list.length;\r
17486                 t = this._eventTarget;\r
17487                 while (--i > -1) {\r
17488                     listener = list[i];\r
17489                     if (listener.up) {\r
17490                         listener.c.call(listener.s || t, {type:type, target:t});\r
17491                     } else {\r
17492                         listener.c.call(listener.s || t);\r
17493                     }\r
17494                 }\r
17495             }\r
17496         };\r
17497 \r
17498 \r
17499 /*\r
17500  * ----------------------------------------------------------------\r
17501  * Ticker\r
17502  * ----------------------------------------------------------------\r
17503  */\r
17504         var _reqAnimFrame = window.requestAnimationFrame,\r
17505             _cancelAnimFrame = window.cancelAnimationFrame,\r
17506             _getTime = Date.now || function() {return new Date().getTime();},\r
17507             _lastUpdate = _getTime();\r
17508 \r
17509         //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.\r
17510         a = ["ms","moz","webkit","o"];\r
17511         i = a.length;\r
17512         while (--i > -1 && !_reqAnimFrame) {\r
17513             _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];\r
17514             _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];\r
17515         }\r
17516 \r
17517         _class("Ticker", function(fps, useRAF) {\r
17518             var _self = this,\r
17519                 _startTime = _getTime(),\r
17520                 _useRAF = (useRAF !== false && _reqAnimFrame),\r
17521                 _lagThreshold = 500,\r
17522                 _adjustedLag = 33,\r
17523                 _fps, _req, _id, _gap, _nextTime,\r
17524                 _tick = function(manual) {\r
17525                     var elapsed = _getTime() - _lastUpdate,\r
17526                         overlap, dispatch;\r
17527                     if (elapsed > _lagThreshold) {\r
17528                         _startTime += elapsed - _adjustedLag;\r
17529                     }\r
17530                     _lastUpdate += elapsed;\r
17531                     _self.time = (_lastUpdate - _startTime) / 1000;\r
17532                     overlap = _self.time - _nextTime;\r
17533                     if (!_fps || overlap > 0 || manual === true) {\r
17534                         _self.frame++;\r
17535                         _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);\r
17536                         dispatch = true;\r
17537                     }\r
17538                     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
17539                         _id = _req(_tick);\r
17540                     }\r
17541                     if (dispatch) {\r
17542                         _self.dispatchEvent("tick");\r
17543                     }\r
17544                 };\r
17545 \r
17546             EventDispatcher.call(_self);\r
17547             _self.time = _self.frame = 0;\r
17548             _self.tick = function() {\r
17549                 _tick(true);\r
17550             };\r
17551 \r
17552             _self.lagSmoothing = function(threshold, adjustedLag) {\r
17553                 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited\r
17554                 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);\r
17555             };\r
17556 \r
17557             _self.sleep = function() {\r
17558                 if (_id == null) {\r
17559                     return;\r
17560                 }\r
17561                 if (!_useRAF || !_cancelAnimFrame) {\r
17562                     clearTimeout(_id);\r
17563                 } else {\r
17564                     _cancelAnimFrame(_id);\r
17565                 }\r
17566                 _req = _emptyFunc;\r
17567                 _id = null;\r
17568                 if (_self === _ticker) {\r
17569                     _tickerActive = false;\r
17570                 }\r
17571             };\r
17572 \r
17573             _self.wake = function() {\r
17574                 if (_id !== null) {\r
17575                     _self.sleep();\r
17576                 } 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
17577                     _lastUpdate = _getTime() - _lagThreshold + 5;\r
17578                 }\r
17579                 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;\r
17580                 if (_self === _ticker) {\r
17581                     _tickerActive = true;\r
17582                 }\r
17583                 _tick(2);\r
17584             };\r
17585 \r
17586             _self.fps = function(value) {\r
17587                 if (!arguments.length) {\r
17588                     return _fps;\r
17589                 }\r
17590                 _fps = value;\r
17591                 _gap = 1 / (_fps || 60);\r
17592                 _nextTime = this.time + _gap;\r
17593                 _self.wake();\r
17594             };\r
17595 \r
17596             _self.useRAF = function(value) {\r
17597                 if (!arguments.length) {\r
17598                     return _useRAF;\r
17599                 }\r
17600                 _self.sleep();\r
17601                 _useRAF = value;\r
17602                 _self.fps(_fps);\r
17603             };\r
17604             _self.fps(fps);\r
17605 \r
17606             //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
17607             setTimeout(function() {\r
17608                 if (_useRAF && (!_id || _self.frame < 5)) {\r
17609                     _self.useRAF(false);\r
17610                 }\r
17611             }, 1500);\r
17612         });\r
17613 \r
17614         p = gs.Ticker.prototype = new gs.events.EventDispatcher();\r
17615         p.constructor = gs.Ticker;\r
17616 \r
17617 \r
17618 /*\r
17619  * ----------------------------------------------------------------\r
17620  * Animation\r
17621  * ----------------------------------------------------------------\r
17622  */\r
17623         var Animation = _class("core.Animation", function(duration, vars) {\r
17624                 this.vars = vars = vars || {};\r
17625                 this._duration = this._totalDuration = duration || 0;\r
17626                 this._delay = Number(vars.delay) || 0;\r
17627                 this._timeScale = 1;\r
17628                 this._active = (vars.immediateRender === true);\r
17629                 this.data = vars.data;\r
17630                 this._reversed = (vars.reversed === true);\r
17631 \r
17632                 if (!_rootTimeline) {\r
17633                     return;\r
17634                 }\r
17635                 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
17636                     _ticker.wake();\r
17637                 }\r
17638 \r
17639                 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;\r
17640                 tl.add(this, tl._time);\r
17641 \r
17642                 if (this.vars.paused) {\r
17643                     this.paused(true);\r
17644                 }\r
17645             });\r
17646 \r
17647         _ticker = Animation.ticker = new gs.Ticker();\r
17648         p = Animation.prototype;\r
17649         p._dirty = p._gc = p._initted = p._paused = false;\r
17650         p._totalTime = p._time = 0;\r
17651         p._rawPrevTime = -1;\r
17652         p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;\r
17653         p._paused = false;\r
17654 \r
17655 \r
17656         //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
17657         var _checkTimeout = function() {\r
17658                 if (_tickerActive && _getTime() - _lastUpdate > 2000) {\r
17659                     _ticker.wake();\r
17660                 }\r
17661                 setTimeout(_checkTimeout, 2000);\r
17662             };\r
17663         _checkTimeout();\r
17664 \r
17665 \r
17666         p.play = function(from, suppressEvents) {\r
17667             if (from != null) {\r
17668                 this.seek(from, suppressEvents);\r
17669             }\r
17670             return this.reversed(false).paused(false);\r
17671         };\r
17672 \r
17673         p.pause = function(atTime, suppressEvents) {\r
17674             if (atTime != null) {\r
17675                 this.seek(atTime, suppressEvents);\r
17676             }\r
17677             return this.paused(true);\r
17678         };\r
17679 \r
17680         p.resume = function(from, suppressEvents) {\r
17681             if (from != null) {\r
17682                 this.seek(from, suppressEvents);\r
17683             }\r
17684             return this.paused(false);\r
17685         };\r
17686 \r
17687         p.seek = function(time, suppressEvents) {\r
17688             return this.totalTime(Number(time), suppressEvents !== false);\r
17689         };\r
17690 \r
17691         p.restart = function(includeDelay, suppressEvents) {\r
17692             return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);\r
17693         };\r
17694 \r
17695         p.reverse = function(from, suppressEvents) {\r
17696             if (from != null) {\r
17697                 this.seek((from || this.totalDuration()), suppressEvents);\r
17698             }\r
17699             return this.reversed(true).paused(false);\r
17700         };\r
17701 \r
17702         p.render = function(time, suppressEvents, force) {\r
17703             //stub - we override this method in subclasses.\r
17704         };\r
17705 \r
17706         p.invalidate = function() {\r
17707             return this;\r
17708         };\r
17709 \r
17710         p.isActive = function() {\r
17711             var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.\r
17712                 startTime = this._startTime,\r
17713                 rawTime;\r
17714             return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));\r
17715         };\r
17716 \r
17717         p._enabled = function (enabled, ignoreTimeline) {\r
17718             if (!_tickerActive) {\r
17719                 _ticker.wake();\r
17720             }\r
17721             this._gc = !enabled;\r
17722             this._active = this.isActive();\r
17723             if (ignoreTimeline !== true) {\r
17724                 if (enabled && !this.timeline) {\r
17725                     this._timeline.add(this, this._startTime - this._delay);\r
17726                 } else if (!enabled && this.timeline) {\r
17727                     this._timeline._remove(this, true);\r
17728                 }\r
17729             }\r
17730             return false;\r
17731         };\r
17732 \r
17733 \r
17734         p._kill = function(vars, target) {\r
17735             return this._enabled(false, false);\r
17736         };\r
17737 \r
17738         p.kill = function(vars, target) {\r
17739             this._kill(vars, target);\r
17740             return this;\r
17741         };\r
17742 \r
17743         p._uncache = function(includeSelf) {\r
17744             var tween = includeSelf ? this : this.timeline;\r
17745             while (tween) {\r
17746                 tween._dirty = true;\r
17747                 tween = tween.timeline;\r
17748             }\r
17749             return this;\r
17750         };\r
17751 \r
17752         p._swapSelfInParams = function(params) {\r
17753             var i = params.length,\r
17754                 copy = params.concat();\r
17755             while (--i > -1) {\r
17756                 if (params[i] === "{self}") {\r
17757                     copy[i] = this;\r
17758                 }\r
17759             }\r
17760             return copy;\r
17761         };\r
17762 \r
17763 //----Animation getters/setters --------------------------------------------------------\r
17764 \r
17765         p.eventCallback = function(type, callback, params, scope) {\r
17766             if ((type || "").substr(0,2) === "on") {\r
17767                 var v = this.vars;\r
17768                 if (arguments.length === 1) {\r
17769                     return v[type];\r
17770                 }\r
17771                 if (callback == null) {\r
17772                     delete v[type];\r
17773                 } else {\r
17774                     v[type] = callback;\r
17775                     v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;\r
17776                     v[type + "Scope"] = scope;\r
17777                 }\r
17778                 if (type === "onUpdate") {\r
17779                     this._onUpdate = callback;\r
17780                 }\r
17781             }\r
17782             return this;\r
17783         };\r
17784 \r
17785         p.delay = function(value) {\r
17786             if (!arguments.length) {\r
17787                 return this._delay;\r
17788             }\r
17789             if (this._timeline.smoothChildTiming) {\r
17790                 this.startTime( this._startTime + value - this._delay );\r
17791             }\r
17792             this._delay = value;\r
17793             return this;\r
17794         };\r
17795 \r
17796         p.duration = function(value) {\r
17797             if (!arguments.length) {\r
17798                 this._dirty = false;\r
17799                 return this._duration;\r
17800             }\r
17801             this._duration = this._totalDuration = value;\r
17802             this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.\r
17803             if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {\r
17804                 this.totalTime(this._totalTime * (value / this._duration), true);\r
17805             }\r
17806             return this;\r
17807         };\r
17808 \r
17809         p.totalDuration = function(value) {\r
17810             this._dirty = false;\r
17811             return (!arguments.length) ? this._totalDuration : this.duration(value);\r
17812         };\r
17813 \r
17814         p.time = function(value, suppressEvents) {\r
17815             if (!arguments.length) {\r
17816                 return this._time;\r
17817             }\r
17818             if (this._dirty) {\r
17819                 this.totalDuration();\r
17820             }\r
17821             return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);\r
17822         };\r
17823 \r
17824         p.totalTime = function(time, suppressEvents, uncapped) {\r
17825             if (!_tickerActive) {\r
17826                 _ticker.wake();\r
17827             }\r
17828             if (!arguments.length) {\r
17829                 return this._totalTime;\r
17830             }\r
17831             if (this._timeline) {\r
17832                 if (time < 0 && !uncapped) {\r
17833                     time += this.totalDuration();\r
17834                 }\r
17835                 if (this._timeline.smoothChildTiming) {\r
17836                     if (this._dirty) {\r
17837                         this.totalDuration();\r
17838                     }\r
17839                     var totalDuration = this._totalDuration,\r
17840                         tl = this._timeline;\r
17841                     if (time > totalDuration && !uncapped) {\r
17842                         time = totalDuration;\r
17843                     }\r
17844                     this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);\r
17845                     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
17846                         this._uncache(false);\r
17847                     }\r
17848                     //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
17849                     if (tl._timeline) {\r
17850                         while (tl._timeline) {\r
17851                             if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {\r
17852                                 tl.totalTime(tl._totalTime, true);\r
17853                             }\r
17854                             tl = tl._timeline;\r
17855                         }\r
17856                     }\r
17857                 }\r
17858                 if (this._gc) {\r
17859                     this._enabled(true, false);\r
17860                 }\r
17861                 if (this._totalTime !== time || this._duration === 0) {\r
17862                     this.render(time, suppressEvents, false);\r
17863                     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
17864                         _lazyRender();\r
17865                     }\r
17866                 }\r
17867             }\r
17868             return this;\r
17869         };\r
17870 \r
17871         p.progress = p.totalProgress = function(value, suppressEvents) {\r
17872             return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);\r
17873         };\r
17874 \r
17875         p.startTime = function(value) {\r
17876             if (!arguments.length) {\r
17877                 return this._startTime;\r
17878             }\r
17879             if (value !== this._startTime) {\r
17880                 this._startTime = value;\r
17881                 if (this.timeline) if (this.timeline._sortChildren) {\r
17882                     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
17883                 }\r
17884             }\r
17885             return this;\r
17886         };\r
17887 \r
17888         p.timeScale = function(value) {\r
17889             if (!arguments.length) {\r
17890                 return this._timeScale;\r
17891             }\r
17892             value = value || _tinyNum; //can't allow zero because it'll throw the math off\r
17893             if (this._timeline && this._timeline.smoothChildTiming) {\r
17894                 var pauseTime = this._pauseTime,\r
17895                     t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();\r
17896                 this._startTime = t - ((t - this._startTime) * this._timeScale / value);\r
17897             }\r
17898             this._timeScale = value;\r
17899             return this._uncache(false);\r
17900         };\r
17901 \r
17902         p.reversed = function(value) {\r
17903             if (!arguments.length) {\r
17904                 return this._reversed;\r
17905             }\r
17906             if (value != this._reversed) {\r
17907                 this._reversed = value;\r
17908                 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);\r
17909             }\r
17910             return this;\r
17911         };\r
17912 \r
17913         p.paused = function(value) {\r
17914             if (!arguments.length) {\r
17915                 return this._paused;\r
17916             }\r
17917             if (value != this._paused) if (this._timeline) {\r
17918                 if (!_tickerActive && !value) {\r
17919                     _ticker.wake();\r
17920                 }\r
17921                 var tl = this._timeline,\r
17922                     raw = tl.rawTime(),\r
17923                     elapsed = raw - this._pauseTime;\r
17924                 if (!value && tl.smoothChildTiming) {\r
17925                     this._startTime += elapsed;\r
17926                     this._uncache(false);\r
17927                 }\r
17928                 this._pauseTime = value ? raw : null;\r
17929                 this._paused = value;\r
17930                 this._active = this.isActive();\r
17931                 if (!value && elapsed !== 0 && this._initted && this.duration()) {\r
17932                     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
17933                 }\r
17934             }\r
17935             if (this._gc && !value) {\r
17936                 this._enabled(true, false);\r
17937             }\r
17938             return this;\r
17939         };\r
17940 \r
17941 \r
17942 /*\r
17943  * ----------------------------------------------------------------\r
17944  * SimpleTimeline\r
17945  * ----------------------------------------------------------------\r
17946  */\r
17947         var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {\r
17948             Animation.call(this, 0, vars);\r
17949             this.autoRemoveChildren = this.smoothChildTiming = true;\r
17950         });\r
17951 \r
17952         p = SimpleTimeline.prototype = new Animation();\r
17953         p.constructor = SimpleTimeline;\r
17954         p.kill()._gc = false;\r
17955         p._first = p._last = null;\r
17956         p._sortChildren = false;\r
17957 \r
17958         p.add = p.insert = function(child, position, align, stagger) {\r
17959             var prevTween, st;\r
17960             child._startTime = Number(position || 0) + child._delay;\r
17961             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
17962                 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);\r
17963             }\r
17964             if (child.timeline) {\r
17965                 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.\r
17966             }\r
17967             child.timeline = child._timeline = this;\r
17968             if (child._gc) {\r
17969                 child._enabled(true, true);\r
17970             }\r
17971             prevTween = this._last;\r
17972             if (this._sortChildren) {\r
17973                 st = child._startTime;\r
17974                 while (prevTween && prevTween._startTime > st) {\r
17975                     prevTween = prevTween._prev;\r
17976                 }\r
17977             }\r
17978             if (prevTween) {\r
17979                 child._next = prevTween._next;\r
17980                 prevTween._next = child;\r
17981             } else {\r
17982                 child._next = this._first;\r
17983                 this._first = child;\r
17984             }\r
17985             if (child._next) {\r
17986                 child._next._prev = child;\r
17987             } else {\r
17988                 this._last = child;\r
17989             }\r
17990             child._prev = prevTween;\r
17991             if (this._timeline) {\r
17992                 this._uncache(true);\r
17993             }\r
17994             return this;\r
17995         };\r
17996 \r
17997         p._remove = function(tween, skipDisable) {\r
17998             if (tween.timeline === this) {\r
17999                 if (!skipDisable) {\r
18000                     tween._enabled(false, true);\r
18001                 }\r
18002                 tween.timeline = null;\r
18003 \r
18004                 if (tween._prev) {\r
18005                     tween._prev._next = tween._next;\r
18006                 } else if (this._first === tween) {\r
18007                     this._first = tween._next;\r
18008                 }\r
18009                 if (tween._next) {\r
18010                     tween._next._prev = tween._prev;\r
18011                 } else if (this._last === tween) {\r
18012                     this._last = tween._prev;\r
18013                 }\r
18014 \r
18015                 if (this._timeline) {\r
18016                     this._uncache(true);\r
18017                 }\r
18018             }\r
18019             return this;\r
18020         };\r
18021 \r
18022         p.render = function(time, suppressEvents, force) {\r
18023             var tween = this._first,\r
18024                 next;\r
18025             this._totalTime = this._time = this._rawPrevTime = time;\r
18026             while (tween) {\r
18027                 next = tween._next; //record it here because the value could change after rendering...\r
18028                 if (tween._active || (time >= tween._startTime && !tween._paused)) {\r
18029                     if (!tween._reversed) {\r
18030                         tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);\r
18031                     } else {\r
18032                         tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);\r
18033                     }\r
18034                 }\r
18035                 tween = next;\r
18036             }\r
18037         };\r
18038 \r
18039         p.rawTime = function() {\r
18040             if (!_tickerActive) {\r
18041                 _ticker.wake();\r
18042             }\r
18043             return this._totalTime;\r
18044         };\r
18045 \r
18046 /*\r
18047  * ----------------------------------------------------------------\r
18048  * TweenLite\r
18049  * ----------------------------------------------------------------\r
18050  */\r
18051         var TweenLite = _class("TweenLite", function(target, duration, vars) {\r
18052                 Animation.call(this, duration, vars);\r
18053                 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)\r
18054 \r
18055                 if (target == null) {\r
18056                     throw "Cannot tween a null target.";\r
18057                 }\r
18058 \r
18059                 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;\r
18060 \r
18061                 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),\r
18062                     overwrite = this.vars.overwrite,\r
18063                     i, targ, targets;\r
18064 \r
18065                 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];\r
18066 \r
18067                 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {\r
18068                     this._targets = targets = _slice.call(target, 0);\r
18069                     this._propLookup = [];\r
18070                     this._siblings = [];\r
18071                     for (i = 0; i < targets.length; i++) {\r
18072                         targ = targets[i];\r
18073                         if (!targ) {\r
18074                             targets.splice(i--, 1);\r
18075                             continue;\r
18076                         } else if (typeof(targ) === "string") {\r
18077                             targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings\r
18078                             if (typeof(targ) === "string") {\r
18079                                 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
18080                             }\r
18081                             continue;\r
18082                         } 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
18083                             targets.splice(i--, 1);\r
18084                             this._targets = targets = targets.concat(_slice.call(targ, 0));\r
18085                             continue;\r
18086                         }\r
18087                         this._siblings[i] = _register(targ, this, false);\r
18088                         if (overwrite === 1) if (this._siblings[i].length > 1) {\r
18089                             _applyOverwrite(targ, this, null, 1, this._siblings[i]);\r
18090                         }\r
18091                     }\r
18092 \r
18093                 } else {\r
18094                     this._propLookup = {};\r
18095                     this._siblings = _register(target, this, false);\r
18096                     if (overwrite === 1) if (this._siblings.length > 1) {\r
18097                         _applyOverwrite(target, this, null, 1, this._siblings);\r
18098                     }\r
18099                 }\r
18100                 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {\r
18101                     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
18102                     this.render(-this._delay);\r
18103                 }\r
18104             }, true),\r
18105             _isSelector = function(v) {\r
18106                 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
18107             },\r
18108             _autoCSS = function(vars, target) {\r
18109                 var css = {},\r
18110                     p;\r
18111                 for (p in vars) {\r
18112                     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
18113                         css[p] = vars[p];\r
18114                         delete vars[p];\r
18115                     }\r
18116                 }\r
18117                 vars.css = css;\r
18118             };\r
18119 \r
18120         p = TweenLite.prototype = new Animation();\r
18121         p.constructor = TweenLite;\r
18122         p.kill()._gc = false;\r
18123 \r
18124 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------\r
18125 \r
18126         p.ratio = 0;\r
18127         p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;\r
18128         p._notifyPluginsOfEnabled = p._lazy = false;\r
18129 \r
18130         TweenLite.version = "1.12.1";\r
18131         TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);\r
18132         TweenLite.defaultOverwrite = "auto";\r
18133         TweenLite.ticker = _ticker;\r
18134         TweenLite.autoSleep = true;\r
18135         TweenLite.lagSmoothing = function(threshold, adjustedLag) {\r
18136             _ticker.lagSmoothing(threshold, adjustedLag);\r
18137         };\r
18138         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
18139 \r
18140         var _lazyTweens = [],\r
18141             _lazyLookup = {},\r
18142             _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
18143             _plugins = TweenLite._plugins = {},\r
18144             _tweenLookup = _internals.tweenLookup = {},\r
18145             _tweenLookupNum = 0,\r
18146             _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
18147             _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},\r
18148             _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),\r
18149             _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),\r
18150             _lazyRender = function() {\r
18151                 var i = _lazyTweens.length;\r
18152                 _lazyLookup = {};\r
18153                 while (--i > -1) {\r
18154                     a = _lazyTweens[i];\r
18155                     if (a && a._lazy !== false) {\r
18156                         a.render(a._lazy, false, true);\r
18157                         a._lazy = false;\r
18158                     }\r
18159                 }\r
18160                 _lazyTweens.length = 0;\r
18161             };\r
18162 \r
18163         _rootTimeline._startTime = _ticker.time;\r
18164         _rootFramesTimeline._startTime = _ticker.frame;\r
18165         _rootTimeline._active = _rootFramesTimeline._active = true;\r
18166         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
18167 \r
18168         Animation._updateRoot = TweenLite.render = function() {\r
18169                 var i, a, p;\r
18170                 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
18171                     _lazyRender();\r
18172                 }\r
18173                 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);\r
18174                 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);\r
18175                 if (_lazyTweens.length) {\r
18176                     _lazyRender();\r
18177                 }\r
18178                 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...\r
18179                     for (p in _tweenLookup) {\r
18180                         a = _tweenLookup[p].tweens;\r
18181                         i = a.length;\r
18182                         while (--i > -1) {\r
18183                             if (a[i]._gc) {\r
18184                                 a.splice(i, 1);\r
18185                             }\r
18186                         }\r
18187                         if (a.length === 0) {\r
18188                             delete _tweenLookup[p];\r
18189                         }\r
18190                     }\r
18191                     //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
18192                     p = _rootTimeline._first;\r
18193                     if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {\r
18194                         while (p && p._paused) {\r
18195                             p = p._next;\r
18196                         }\r
18197                         if (!p) {\r
18198                             _ticker.sleep();\r
18199                         }\r
18200                     }\r
18201                 }\r
18202             };\r
18203 \r
18204         _ticker.addEventListener("tick", Animation._updateRoot);\r
18205 \r
18206         var _register = function(target, tween, scrub) {\r
18207                 var id = target._gsTweenID, a, i;\r
18208                 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {\r
18209                     _tweenLookup[id] = {target:target, tweens:[]};\r
18210                 }\r
18211                 if (tween) {\r
18212                     a = _tweenLookup[id].tweens;\r
18213                     a[(i = a.length)] = tween;\r
18214                     if (scrub) {\r
18215                         while (--i > -1) {\r
18216                             if (a[i] === tween) {\r
18217                                 a.splice(i, 1);\r
18218                             }\r
18219                         }\r
18220                     }\r
18221                 }\r
18222                 return _tweenLookup[id].tweens;\r
18223             },\r
18224 \r
18225             _applyOverwrite = function(target, tween, props, mode, siblings) {\r
18226                 var i, changed, curTween, l;\r
18227                 if (mode === 1 || mode >= 4) {\r
18228                     l = siblings.length;\r
18229                     for (i = 0; i < l; i++) {\r
18230                         if ((curTween = siblings[i]) !== tween) {\r
18231                             if (!curTween._gc) if (curTween._enabled(false, false)) {\r
18232                                 changed = true;\r
18233                             }\r
18234                         } else if (mode === 5) {\r
18235                             break;\r
18236                         }\r
18237                     }\r
18238                     return changed;\r
18239                 }\r
18240                 //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
18241                 var startTime = tween._startTime + _tinyNum,\r
18242                     overlaps = [],\r
18243                     oCount = 0,\r
18244                     zeroDur = (tween._duration === 0),\r
18245                     globalStart;\r
18246                 i = siblings.length;\r
18247                 while (--i > -1) {\r
18248                     if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {\r
18249                         //ignore\r
18250                     } else if (curTween._timeline !== tween._timeline) {\r
18251                         globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);\r
18252                         if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {\r
18253                             overlaps[oCount++] = curTween;\r
18254                         }\r
18255                     } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {\r
18256                         overlaps[oCount++] = curTween;\r
18257                     }\r
18258                 }\r
18259 \r
18260                 i = oCount;\r
18261                 while (--i > -1) {\r
18262                     curTween = overlaps[i];\r
18263                     if (mode === 2) if (curTween._kill(props, target)) {\r
18264                         changed = true;\r
18265                     }\r
18266                     if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {\r
18267                         if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.\r
18268                             changed = true;\r
18269                         }\r
18270                     }\r
18271                 }\r
18272                 return changed;\r
18273             },\r
18274 \r
18275             _checkOverlap = function(tween, reference, zeroDur) {\r
18276                 var tl = tween._timeline,\r
18277                     ts = tl._timeScale,\r
18278                     t = tween._startTime;\r
18279                 while (tl._timeline) {\r
18280                     t += tl._startTime;\r
18281                     ts *= tl._timeScale;\r
18282                     if (tl._paused) {\r
18283                         return -100;\r
18284                     }\r
18285                     tl = tl._timeline;\r
18286                 }\r
18287                 t /= ts;\r
18288                 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
18289             };\r
18290 \r
18291 \r
18292 //---- TweenLite instance methods -----------------------------------------------------------------------------\r
18293 \r
18294         p._init = function() {\r
18295             var v = this.vars,\r
18296                 op = this._overwrittenProps,\r
18297                 dur = this._duration,\r
18298                 immediate = !!v.immediateRender,\r
18299                 ease = v.ease,\r
18300                 i, initPlugins, pt, p, startVars;\r
18301             if (v.startAt) {\r
18302                 if (this._startAt) {\r
18303                     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
18304                     this._startAt.kill();\r
18305                 }\r
18306                 startVars = {};\r
18307                 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
18308                     startVars[p] = v.startAt[p];\r
18309                 }\r
18310                 startVars.overwrite = false;\r
18311                 startVars.immediateRender = true;\r
18312                 startVars.lazy = (immediate && v.lazy !== false);\r
18313                 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).\r
18314                 this._startAt = TweenLite.to(this.target, 0, startVars);\r
18315                 if (immediate) {\r
18316                     if (this._time > 0) {\r
18317                         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
18318                     } else if (dur !== 0) {\r
18319                         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
18320                     }\r
18321                 }\r
18322             } else if (v.runBackwards && dur !== 0) {\r
18323                 //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
18324                 if (this._startAt) {\r
18325                     this._startAt.render(-1, true);\r
18326                     this._startAt.kill();\r
18327                     this._startAt = null;\r
18328                 } else {\r
18329                     pt = {};\r
18330                     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
18331                         if (!_reservedProps[p] || p === "autoCSS") {\r
18332                             pt[p] = v[p];\r
18333                         }\r
18334                     }\r
18335                     pt.overwrite = 0;\r
18336                     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
18337                     pt.lazy = (immediate && v.lazy !== false);\r
18338                     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
18339                     this._startAt = TweenLite.to(this.target, 0, pt);\r
18340                     if (!immediate) {\r
18341                         this._startAt._init(); //ensures that the initial values are recorded\r
18342                         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
18343                     } else if (this._time === 0) {\r
18344                         return;\r
18345                     }\r
18346                 }\r
18347             }\r
18348             if (!ease) {\r
18349                 this._ease = TweenLite.defaultEase;\r
18350             } else if (ease instanceof Ease) {\r
18351                 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;\r
18352             } else {\r
18353                 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;\r
18354             }\r
18355             this._easeType = this._ease._type;\r
18356             this._easePower = this._ease._power;\r
18357             this._firstPT = null;\r
18358 \r
18359             if (this._targets) {\r
18360                 i = this._targets.length;\r
18361                 while (--i > -1) {\r
18362                     if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {\r
18363                         initPlugins = true;\r
18364                     }\r
18365                 }\r
18366             } else {\r
18367                 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);\r
18368             }\r
18369 \r
18370             if (initPlugins) {\r
18371                 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
18372             }\r
18373             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
18374                 this._enabled(false, false);\r
18375             }\r
18376             if (v.runBackwards) {\r
18377                 pt = this._firstPT;\r
18378                 while (pt) {\r
18379                     pt.s += pt.c;\r
18380                     pt.c = -pt.c;\r
18381                     pt = pt._next;\r
18382                 }\r
18383             }\r
18384             this._onUpdate = v.onUpdate;\r
18385             this._initted = true;\r
18386         };\r
18387 \r
18388         p._initProps = function(target, propLookup, siblings, overwrittenProps) {\r
18389             var p, i, initPlugins, plugin, pt, v;\r
18390             if (target == null) {\r
18391                 return false;\r
18392             }\r
18393 \r
18394             if (_lazyLookup[target._gsTweenID]) {\r
18395                 _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
18396             }\r
18397 \r
18398             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
18399                 _autoCSS(this.vars, target);\r
18400             }\r
18401             for (p in this.vars) {\r
18402                 v = this.vars[p];\r
18403                 if (_reservedProps[p]) {\r
18404                     if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {\r
18405                         this.vars[p] = v = this._swapSelfInParams(v, this);\r
18406                     }\r
18407 \r
18408                 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {\r
18409 \r
18410                     //t - target        [object]\r
18411                     //p - property      [string]\r
18412                     //s - start         [number]\r
18413                     //c - change        [number]\r
18414                     //f - isFunction    [boolean]\r
18415                     //n - name          [string]\r
18416                     //pg - isPlugin     [boolean]\r
18417                     //pr - priority     [number]\r
18418                     this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};\r
18419                     i = plugin._overwriteProps.length;\r
18420                     while (--i > -1) {\r
18421                         propLookup[plugin._overwriteProps[i]] = this._firstPT;\r
18422                     }\r
18423                     if (plugin._priority || plugin._onInitAllProps) {\r
18424                         initPlugins = true;\r
18425                     }\r
18426                     if (plugin._onDisable || plugin._onEnable) {\r
18427                         this._notifyPluginsOfEnabled = true;\r
18428                     }\r
18429 \r
18430                 } else {\r
18431                     this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};\r
18432                     pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();\r
18433                     pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;\r
18434                 }\r
18435                 if (pt) if (pt._next) {\r
18436                     pt._next._prev = pt;\r
18437                 }\r
18438             }\r
18439 \r
18440             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
18441                 return this._initProps(target, propLookup, siblings, overwrittenProps);\r
18442             }\r
18443             if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {\r
18444                 this._kill(propLookup, target);\r
18445                 return this._initProps(target, propLookup, siblings, overwrittenProps);\r
18446             }\r
18447             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
18448                 _lazyLookup[target._gsTweenID] = true;\r
18449             }\r
18450             return initPlugins;\r
18451         };\r
18452 \r
18453         p.render = function(time, suppressEvents, force) {\r
18454             var prevTime = this._time,\r
18455                 duration = this._duration,\r
18456                 prevRawPrevTime = this._rawPrevTime,\r
18457                 isComplete, callback, pt, rawPrevTime;\r
18458             if (time >= duration) {\r
18459                 this._totalTime = this._time = duration;\r
18460                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;\r
18461                 if (!this._reversed ) {\r
18462                     isComplete = true;\r
18463                     callback = "onComplete";\r
18464                 }\r
18465                 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
18466                     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
18467                         time = 0;\r
18468                     }\r
18469                     if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {\r
18470                         force = true;\r
18471                         if (prevRawPrevTime > _tinyNum) {\r
18472                             callback = "onReverseComplete";\r
18473                         }\r
18474                     }\r
18475                     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
18476                 }\r
18477 \r
18478             } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.\r
18479                 this._totalTime = this._time = 0;\r
18480                 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;\r
18481                 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {\r
18482                     callback = "onReverseComplete";\r
18483                     isComplete = this._reversed;\r
18484                 }\r
18485                 if (time < 0) {\r
18486                     this._active = false;\r
18487                     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
18488                         if (prevRawPrevTime >= 0) {\r
18489                             force = true;\r
18490                         }\r
18491                         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
18492                     }\r
18493                 } 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
18494                     force = true;\r
18495                 }\r
18496             } else {\r
18497                 this._totalTime = this._time = time;\r
18498 \r
18499                 if (this._easeType) {\r
18500                     var r = time / duration, type = this._easeType, pow = this._easePower;\r
18501                     if (type === 1 || (type === 3 && r >= 0.5)) {\r
18502                         r = 1 - r;\r
18503                     }\r
18504                     if (type === 3) {\r
18505                         r *= 2;\r
18506                     }\r
18507                     if (pow === 1) {\r
18508                         r *= r;\r
18509                     } else if (pow === 2) {\r
18510                         r *= r * r;\r
18511                     } else if (pow === 3) {\r
18512                         r *= r * r * r;\r
18513                     } else if (pow === 4) {\r
18514                         r *= r * r * r * r;\r
18515                     }\r
18516 \r
18517                     if (type === 1) {\r
18518                         this.ratio = 1 - r;\r
18519                     } else if (type === 2) {\r
18520                         this.ratio = r;\r
18521                     } else if (time / duration < 0.5) {\r
18522                         this.ratio = r / 2;\r
18523                     } else {\r
18524                         this.ratio = 1 - (r / 2);\r
18525                     }\r
18526 \r
18527                 } else {\r
18528                     this.ratio = this._ease.getRatio(time / duration);\r
18529                 }\r
18530             }\r
18531 \r
18532             if (this._time === prevTime && !force) {\r
18533                 return;\r
18534             } else if (!this._initted) {\r
18535                 this._init();\r
18536                 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
18537                     return;\r
18538                 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {\r
18539                     this._time = this._totalTime = prevTime;\r
18540                     this._rawPrevTime = prevRawPrevTime;\r
18541                     _lazyTweens.push(this);\r
18542                     this._lazy = time;\r
18543                     return;\r
18544                 }\r
18545                 //_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
18546                 if (this._time && !isComplete) {\r
18547                     this.ratio = this._ease.getRatio(this._time / duration);\r
18548                 } else if (isComplete && this._ease._calcEnd) {\r
18549                     this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);\r
18550                 }\r
18551             }\r
18552             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
18553                 this._lazy = false;\r
18554             }\r
18555             if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {\r
18556                 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
18557             }\r
18558             if (prevTime === 0) {\r
18559                 if (this._startAt) {\r
18560                     if (time >= 0) {\r
18561                         this._startAt.render(time, suppressEvents, force);\r
18562                     } else if (!callback) {\r
18563                         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
18564                     }\r
18565                 }\r
18566                 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {\r
18567                     this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);\r
18568                 }\r
18569             }\r
18570 \r
18571             pt = this._firstPT;\r
18572             while (pt) {\r
18573                 if (pt.f) {\r
18574                     pt.t[pt.p](pt.c * this.ratio + pt.s);\r
18575                 } else {\r
18576                     pt.t[pt.p] = pt.c * this.ratio + pt.s;\r
18577                 }\r
18578                 pt = pt._next;\r
18579             }\r
18580 \r
18581             if (this._onUpdate) {\r
18582                 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
18583                     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
18584                 }\r
18585                 if (!suppressEvents) if (this._time !== prevTime || isComplete) {\r
18586                     this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);\r
18587                 }\r
18588             }\r
18589 \r
18590             if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate\r
18591                 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
18592                     this._startAt.render(time, suppressEvents, force);\r
18593                 }\r
18594                 if (isComplete) {\r
18595                     if (this._timeline.autoRemoveChildren) {\r
18596                         this._enabled(false, false);\r
18597                     }\r
18598                     this._active = false;\r
18599                 }\r
18600                 if (!suppressEvents && this.vars[callback]) {\r
18601                     this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);\r
18602                 }\r
18603                 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
18604                     this._rawPrevTime = 0;\r
18605                 }\r
18606             }\r
18607 \r
18608         };\r
18609 \r
18610         p._kill = function(vars, target) {\r
18611             if (vars === "all") {\r
18612                 vars = null;\r
18613             }\r
18614             if (vars == null) if (target == null || target === this.target) {\r
18615                 this._lazy = false;\r
18616                 return this._enabled(false, false);\r
18617             }\r
18618             target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;\r
18619             var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;\r
18620             if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {\r
18621                 i = target.length;\r
18622                 while (--i > -1) {\r
18623                     if (this._kill(vars, target[i])) {\r
18624                         changed = true;\r
18625                     }\r
18626                 }\r
18627             } else {\r
18628                 if (this._targets) {\r
18629                     i = this._targets.length;\r
18630                     while (--i > -1) {\r
18631                         if (target === this._targets[i]) {\r
18632                             propLookup = this._propLookup[i] || {};\r
18633                             this._overwrittenProps = this._overwrittenProps || [];\r
18634                             overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";\r
18635                             break;\r
18636                         }\r
18637                     }\r
18638                 } else if (target !== this.target) {\r
18639                     return false;\r
18640                 } else {\r
18641                     propLookup = this._propLookup;\r
18642                     overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";\r
18643                 }\r
18644 \r
18645                 if (propLookup) {\r
18646                     killProps = vars || propLookup;\r
18647                     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
18648                     for (p in killProps) {\r
18649                         if ((pt = propLookup[p])) {\r
18650                             if (pt.pg && pt.t._kill(killProps)) {\r
18651                                 changed = true; //some plugins need to be notified so they can perform cleanup tasks first\r
18652                             }\r
18653                             if (!pt.pg || pt.t._overwriteProps.length === 0) {\r
18654                                 if (pt._prev) {\r
18655                                     pt._prev._next = pt._next;\r
18656                                 } else if (pt === this._firstPT) {\r
18657                                     this._firstPT = pt._next;\r
18658                                 }\r
18659                                 if (pt._next) {\r
18660                                     pt._next._prev = pt._prev;\r
18661                                 }\r
18662                                 pt._next = pt._prev = null;\r
18663                             }\r
18664                             delete propLookup[p];\r
18665                         }\r
18666                         if (record) {\r
18667                             overwrittenProps[p] = 1;\r
18668                         }\r
18669                     }\r
18670                     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
18671                         this._enabled(false, false);\r
18672                     }\r
18673                 }\r
18674             }\r
18675             return changed;\r
18676         };\r
18677 \r
18678         p.invalidate = function() {\r
18679             if (this._notifyPluginsOfEnabled) {\r
18680                 TweenLite._onPluginEvent("_onDisable", this);\r
18681             }\r
18682             this._firstPT = null;\r
18683             this._overwrittenProps = null;\r
18684             this._onUpdate = null;\r
18685             this._startAt = null;\r
18686             this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;\r
18687             this._propLookup = (this._targets) ? {} : [];\r
18688             return this;\r
18689         };\r
18690 \r
18691         p._enabled = function(enabled, ignoreTimeline) {\r
18692             if (!_tickerActive) {\r
18693                 _ticker.wake();\r
18694             }\r
18695             if (enabled && this._gc) {\r
18696                 var targets = this._targets,\r
18697                     i;\r
18698                 if (targets) {\r
18699                     i = targets.length;\r
18700                     while (--i > -1) {\r
18701                         this._siblings[i] = _register(targets[i], this, true);\r
18702                     }\r
18703                 } else {\r
18704                     this._siblings = _register(this.target, this, true);\r
18705                 }\r
18706             }\r
18707             Animation.prototype._enabled.call(this, enabled, ignoreTimeline);\r
18708             if (this._notifyPluginsOfEnabled) if (this._firstPT) {\r
18709                 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);\r
18710             }\r
18711             return false;\r
18712         };\r
18713 \r
18714 \r
18715 //----TweenLite static methods -----------------------------------------------------\r
18716 \r
18717         TweenLite.to = function(target, duration, vars) {\r
18718             return new TweenLite(target, duration, vars);\r
18719         };\r
18720 \r
18721         TweenLite.from = function(target, duration, vars) {\r
18722             vars.runBackwards = true;\r
18723             vars.immediateRender = (vars.immediateRender != false);\r
18724             return new TweenLite(target, duration, vars);\r
18725         };\r
18726 \r
18727         TweenLite.fromTo = function(target, duration, fromVars, toVars) {\r
18728             toVars.startAt = fromVars;\r
18729             toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);\r
18730             return new TweenLite(target, duration, toVars);\r
18731         };\r
18732 \r
18733         TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {\r
18734             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
18735         };\r
18736 \r
18737         TweenLite.set = function(target, vars) {\r
18738             return new TweenLite(target, 0, vars);\r
18739         };\r
18740 \r
18741         TweenLite.getTweensOf = function(target, onlyActive) {\r
18742             if (target == null) { return []; }\r
18743             target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;\r
18744             var i, a, j, t;\r
18745             if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {\r
18746                 i = target.length;\r
18747                 a = [];\r
18748                 while (--i > -1) {\r
18749                     a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));\r
18750                 }\r
18751                 i = a.length;\r
18752                 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)\r
18753                 while (--i > -1) {\r
18754                     t = a[i];\r
18755                     j = i;\r
18756                     while (--j > -1) {\r
18757                         if (t === a[j]) {\r
18758                             a.splice(i, 1);\r
18759                         }\r
18760                     }\r
18761                 }\r
18762             } else {\r
18763                 a = _register(target).concat();\r
18764                 i = a.length;\r
18765                 while (--i > -1) {\r
18766                     if (a[i]._gc || (onlyActive && !a[i].isActive())) {\r
18767                         a.splice(i, 1);\r
18768                     }\r
18769                 }\r
18770             }\r
18771             return a;\r
18772         };\r
18773 \r
18774         TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {\r
18775             if (typeof(onlyActive) === "object") {\r
18776                 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)\r
18777                 onlyActive = false;\r
18778             }\r
18779             var a = TweenLite.getTweensOf(target, onlyActive),\r
18780                 i = a.length;\r
18781             while (--i > -1) {\r
18782                 a[i]._kill(vars, target);\r
18783             }\r
18784         };\r
18785 \r
18786 \r
18787 \r
18788 /*\r
18789  * ----------------------------------------------------------------\r
18790  * 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
18791  * ----------------------------------------------------------------\r
18792  */\r
18793         var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {\r
18794                     this._overwriteProps = (props || "").split(",");\r
18795                     this._propName = this._overwriteProps[0];\r
18796                     this._priority = priority || 0;\r
18797                     this._super = TweenPlugin.prototype;\r
18798                 }, true);\r
18799 \r
18800         p = TweenPlugin.prototype;\r
18801         TweenPlugin.version = "1.10.1";\r
18802         TweenPlugin.API = 2;\r
18803         p._firstPT = null;\r
18804 \r
18805         p._addTween = function(target, prop, start, end, overwriteProp, round) {\r
18806             var c, pt;\r
18807             if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {\r
18808                 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
18809                 if (pt._next) {\r
18810                     pt._next._prev = pt;\r
18811                 }\r
18812                 return pt;\r
18813             }\r
18814         };\r
18815 \r
18816         p.setRatio = function(v) {\r
18817             var pt = this._firstPT,\r
18818                 min = 0.000001,\r
18819                 val;\r
18820             while (pt) {\r
18821                 val = pt.c * v + pt.s;\r
18822                 if (pt.r) {\r
18823                     val = Math.round(val);\r
18824                 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser\r
18825                     val = 0;\r
18826                 }\r
18827                 if (pt.f) {\r
18828                     pt.t[pt.p](val);\r
18829                 } else {\r
18830                     pt.t[pt.p] = val;\r
18831                 }\r
18832                 pt = pt._next;\r
18833             }\r
18834         };\r
18835 \r
18836         p._kill = function(lookup) {\r
18837             var a = this._overwriteProps,\r
18838                 pt = this._firstPT,\r
18839                 i;\r
18840             if (lookup[this._propName] != null) {\r
18841                 this._overwriteProps = [];\r
18842             } else {\r
18843                 i = a.length;\r
18844                 while (--i > -1) {\r
18845                     if (lookup[a[i]] != null) {\r
18846                         a.splice(i, 1);\r
18847                     }\r
18848                 }\r
18849             }\r
18850             while (pt) {\r
18851                 if (lookup[pt.n] != null) {\r
18852                     if (pt._next) {\r
18853                         pt._next._prev = pt._prev;\r
18854                     }\r
18855                     if (pt._prev) {\r
18856                         pt._prev._next = pt._next;\r
18857                         pt._prev = null;\r
18858                     } else if (this._firstPT === pt) {\r
18859                         this._firstPT = pt._next;\r
18860                     }\r
18861                 }\r
18862                 pt = pt._next;\r
18863             }\r
18864             return false;\r
18865         };\r
18866 \r
18867         p._roundProps = function(lookup, value) {\r
18868             var pt = this._firstPT;\r
18869             while (pt) {\r
18870                 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
18871                     pt.r = value;\r
18872                 }\r
18873                 pt = pt._next;\r
18874             }\r
18875         };\r
18876 \r
18877         TweenLite._onPluginEvent = function(type, tween) {\r
18878             var pt = tween._firstPT,\r
18879                 changed, pt2, first, last, next;\r
18880             if (type === "_onInitAllProps") {\r
18881                 //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
18882                 while (pt) {\r
18883                     next = pt._next;\r
18884                     pt2 = first;\r
18885                     while (pt2 && pt2.pr > pt.pr) {\r
18886                         pt2 = pt2._next;\r
18887                     }\r
18888                     if ((pt._prev = pt2 ? pt2._prev : last)) {\r
18889                         pt._prev._next = pt;\r
18890                     } else {\r
18891                         first = pt;\r
18892                     }\r
18893                     if ((pt._next = pt2)) {\r
18894                         pt2._prev = pt;\r
18895                     } else {\r
18896                         last = pt;\r
18897                     }\r
18898                     pt = next;\r
18899                 }\r
18900                 pt = tween._firstPT = first;\r
18901             }\r
18902             while (pt) {\r
18903                 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {\r
18904                     changed = true;\r
18905                 }\r
18906                 pt = pt._next;\r
18907             }\r
18908             return changed;\r
18909         };\r
18910 \r
18911         TweenPlugin.activate = function(plugins) {\r
18912             var i = plugins.length;\r
18913             while (--i > -1) {\r
18914                 if (plugins[i].API === TweenPlugin.API) {\r
18915                     _plugins[(new plugins[i]())._propName] = plugins[i];\r
18916                 }\r
18917             }\r
18918             return true;\r
18919         };\r
18920 \r
18921         //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
18922         _gsDefine.plugin = function(config) {\r
18923             if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }\r
18924             var propName = config.propName,\r
18925                 priority = config.priority || 0,\r
18926                 overwriteProps = config.overwriteProps,\r
18927                 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},\r
18928                 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",\r
18929                     function() {\r
18930                         TweenPlugin.call(this, propName, priority);\r
18931                         this._overwriteProps = overwriteProps || [];\r
18932                     }, (config.global === true)),\r
18933                 p = Plugin.prototype = new TweenPlugin(propName),\r
18934                 prop;\r
18935             p.constructor = Plugin;\r
18936             Plugin.API = config.API;\r
18937             for (prop in map) {\r
18938                 if (typeof(config[prop]) === "function") {\r
18939                     p[map[prop]] = config[prop];\r
18940                 }\r
18941             }\r
18942             Plugin.version = config.version;\r
18943             TweenPlugin.activate([Plugin]);\r
18944             return Plugin;\r
18945         };\r
18946 \r
18947 \r
18948         //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
18949         a = window._gsQueue;\r
18950         if (a) {\r
18951             for (i = 0; i < a.length; i++) {\r
18952                 a[i]();\r
18953             }\r
18954             for (p in _defLookup) {\r
18955                 if (!_defLookup[p].func) {\r
18956                     //window.console.log("GSAP encountered missing dependency: com.greensock." + p);\r
18957                 }\r
18958             }\r
18959         }\r
18960 \r
18961         _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated\r
18962 \r
18963 })(window);\r
18964 \r
18965 angular.module('b2b.att.collapse', ['b2b.att.transition'])\r
18966 \r
18967 // The collapsible directive indicates a block of html that will expand and collapse\r
18968 .directive('b2bCollapse', ['$transition', function($transition) {\r
18969     // CSS transitions don't work with height: auto, so we have to manually change the height to a\r
18970     // specific value and then once the animation completes, we can reset the height to auto.\r
18971     // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class\r
18972     // "collapse") then you trigger a change to height 0 in between.\r
18973     // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!\r
18974 \r
18975     var props = {\r
18976         open: {\r
18977             marginTop: null,\r
18978             marginBottom: null,\r
18979             paddingTop: null,\r
18980             paddingBottom: null,\r
18981             display: 'block'\r
18982         },\r
18983         closed: {\r
18984             marginTop: 0,\r
18985             marginBottom: 0,\r
18986             paddingTop: 0,\r
18987             paddingBottom: 0,\r
18988             display: 'none'\r
18989         }\r
18990     };\r
18991 \r
18992     var fixUpHeight = function(scope, element, height) {\r
18993         // We remove the collapse CSS class to prevent a transition when we change to height: auto\r
18994         element.removeClass('b2bCollapse');\r
18995         element.css({height: height});\r
18996         //adjusting for any margin or padding\r
18997         if (height === 0) {\r
18998             element.css(props.closed);\r
18999         } else {\r
19000             element.css(props.open);\r
19001         }\r
19002         // It appears that  reading offsetWidth makes the browser realise that we have changed the\r
19003         // height already :-/\r
19004         var x = element[0].offsetWidth;\r
19005         element.addClass('b2bCollapse');\r
19006     };\r
19007 \r
19008     return {\r
19009         link: function(scope, element, attrs) {\r
19010             var isCollapsed;\r
19011             var initialAnimSkip = true;\r
19012             scope.$watch(function() {\r
19013                 return element[0].scrollHeight;\r
19014             }, function(value) {\r
19015                 //The listener is called when scrollHeight changes\r
19016                 //It actually does on 2 scenarios: \r
19017                 // 1. Parent is set to display none\r
19018                 // 2. angular bindings inside are resolved\r
19019                 //When we have a change of scrollHeight we are setting again the correct height if the group is opened\r
19020                 if (element[0].scrollHeight !== 0) {\r
19021                     if (!isCollapsed) {\r
19022                         if (initialAnimSkip) {\r
19023                             fixUpHeight(scope, element, element[0].scrollHeight + 'px');\r
19024                         } else {\r
19025                             fixUpHeight(scope, element, 'auto');\r
19026                             element.css({overflow: 'visible'});\r
19027                         }\r
19028                     }\r
19029                 }\r
19030             });\r
19031 \r
19032             scope.$watch(attrs.b2bCollapse, function(value) {\r
19033                 if (value) {\r
19034                     collapse();\r
19035                 } else {\r
19036                     expand();\r
19037                 }\r
19038             });\r
19039 \r
19040 \r
19041             var currentTransition;\r
19042             var doTransition = function(change) {\r
19043                 if (currentTransition) {\r
19044                     currentTransition.cancel();\r
19045                 }\r
19046                 currentTransition = $transition(element, change);\r
19047                 currentTransition.then(\r
19048                         function() {\r
19049                             currentTransition = undefined;\r
19050                         },\r
19051                         function() {\r
19052                             currentTransition = undefined;\r
19053                         }\r
19054                 );\r
19055                 return currentTransition;\r
19056             };\r
19057 \r
19058             var expand = function() {\r
19059                 scope.postTransition = true; \r
19060                 if (initialAnimSkip) {\r
19061                     initialAnimSkip = false;\r
19062                     if (!isCollapsed) {\r
19063                         fixUpHeight(scope, element, 'auto');\r
19064                     }\r
19065                 } else {\r
19066                     //doTransition({ height : element[0].scrollHeight + 'px' })\r
19067                     doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))\r
19068                             .then(function() {\r
19069                                 // This check ensures that we don't accidentally update the height if the user has closed\r
19070                                 // the group while the animation was still running\r
19071                                 if (!isCollapsed) {\r
19072                                     fixUpHeight(scope, element, 'auto');\r
19073                                 }\r
19074                             });\r
19075                 }\r
19076                 isCollapsed = false;\r
19077             };\r
19078 \r
19079             var collapse = function() {\r
19080                 isCollapsed = true;\r
19081                 if (initialAnimSkip) {\r
19082                     initialAnimSkip = false;\r
19083                     fixUpHeight(scope, element, 0);\r
19084                 } else {\r
19085                     fixUpHeight(scope, element, element[0].scrollHeight + 'px');\r
19086                     doTransition(angular.extend({height: 0}, props.closed)).then(function() {\r
19087                         scope.postTransition = false;\r
19088                     });\r
19089                     element.css({overflow: 'hidden'});\r
19090                 }\r
19091             };\r
19092         }\r
19093     };\r
19094 }]);\r
19095 angular.module('b2b.att.position', [])\r
19096 \r
19097 .factory('$position', ['$document', '$window', function ($document, $window) {\r
19098     function getStyle(el, cssprop) {\r
19099         if (el.currentStyle) { //IE\r
19100             return el.currentStyle[cssprop];\r
19101         } else if ($window.getComputedStyle) {\r
19102             return $window.getComputedStyle(el)[cssprop];\r
19103         }\r
19104         // finally try and get inline style\r
19105         return el.style[cssprop];\r
19106     }\r
19107 \r
19108     /**\r
19109      * Checks if a given element is statically positioned\r
19110      * @param element - raw DOM element\r
19111      */\r
19112     function isStaticPositioned(element) {\r
19113         return (getStyle(element, "position") || 'static') === 'static';\r
19114     }\r
19115 \r
19116     /**\r
19117      * returns the closest, non-statically positioned parentOffset of a given element\r
19118      * @param element\r
19119      */\r
19120     var parentOffsetEl = function (element) {\r
19121         var docDomEl = $document[0];\r
19122         var offsetParent = element.offsetParent || docDomEl;\r
19123         while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {\r
19124             offsetParent = offsetParent.offsetParent;\r
19125         }\r
19126         return offsetParent || docDomEl;\r
19127     };\r
19128 \r
19129     return {\r
19130         /**\r
19131          * Provides read-only equivalent of jQuery's position function:\r
19132          * http://api.jquery.com/position/\r
19133          */\r
19134         position: function (element) {\r
19135             var elBCR = this.offset(element);\r
19136             var offsetParentBCR = {\r
19137                 top: 0,\r
19138                 left: 0\r
19139             };\r
19140             var offsetParentEl = parentOffsetEl(element[0]);\r
19141             if (offsetParentEl !== $document[0]) {\r
19142                 offsetParentBCR = this.offset(angular.element(offsetParentEl));\r
19143                 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;\r
19144                 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;\r
19145             }\r
19146 \r
19147             return {\r
19148                 width: element.prop('offsetWidth'),\r
19149                 height: element.prop('offsetHeight'),\r
19150                 top: elBCR.top - offsetParentBCR.top,\r
19151                 left: elBCR.left - offsetParentBCR.left\r
19152             };\r
19153         },\r
19154 \r
19155         /**\r
19156          * Provides read-only equivalent of jQuery's offset function:\r
19157          * http://api.jquery.com/offset/\r
19158          */\r
19159         offset: function (element) {\r
19160             var boundingClientRect = element[0].getBoundingClientRect();\r
19161             return {\r
19162                 width: element.prop('offsetWidth'),\r
19163                 height: element.prop('offsetHeight'),\r
19164                 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),\r
19165                 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)\r
19166             };\r
19167         },\r
19168         \r
19169          /**\r
19170          * Provides functionality to check whether an element is in view port.\r
19171          */\r
19172         isElementInViewport: function (element) {\r
19173             if (element) {\r
19174                 var rect = element[0].getBoundingClientRect();\r
19175                 return (\r
19176                     rect.top >= 0 &&\r
19177                     rect.left >= 0 &&\r
19178                     rect.bottom <= ($window.innerHeight || $document[0].documentElement.clientHeight) &&\r
19179                     rect.right <= ($window.innerWidth || $document[0].documentElement.clientWidth)\r
19180                 );\r
19181             } else {\r
19182                 return false;\r
19183             }\r
19184         }\r
19185     };\r
19186 }])\r
19187 \r
19188 .factory('$isElement', [function () {\r
19189     var isElement = function (currentElem, targetElem, alternateElem) {\r
19190         if (currentElem[0] === targetElem[0]) {\r
19191             return true;\r
19192         } else if (currentElem[0] === alternateElem[0]) {\r
19193             return false;\r
19194         } else {\r
19195             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);\r
19196         }\r
19197     };\r
19198 \r
19199     return isElement;\r
19200 }])\r
19201 \r
19202 .directive('attPosition', ['$position', function ($position) {\r
19203     return {\r
19204         restrict: 'A',\r
19205         link: function (scope, elem, attr) {\r
19206             scope.$watchCollection(function () {\r
19207                 return $position.position(elem);\r
19208             }, function (value) {\r
19209                 scope[attr.attPosition] = value;\r
19210             });\r
19211         }\r
19212     };\r
19213 }]);\r
19214 \r
19215 angular.module('b2b.att.transition', [])\r
19216 \r
19217 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {\r
19218 \r
19219   var $transition = function(element, trigger, options) {\r
19220     options = options || {};\r
19221     var deferred = $q.defer();\r
19222     var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];\r
19223 \r
19224     var transitionEndHandler = function() {\r
19225       $rootScope.$apply(function() {\r
19226         element.unbind(endEventName, transitionEndHandler);\r
19227         deferred.resolve(element);\r
19228       });\r
19229     };\r
19230 \r
19231     if (endEventName) {\r
19232       element.bind(endEventName, transitionEndHandler);\r
19233     }\r
19234 \r
19235     // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur\r
19236     $timeout(function() {\r
19237       if ( angular.isString(trigger) ) {\r
19238         element.addClass(trigger);\r
19239       } else if ( angular.isFunction(trigger) ) {\r
19240         trigger(element);\r
19241       } else if ( angular.isObject(trigger) ) {\r
19242         element.css(trigger);\r
19243       }\r
19244       //If browser does not support transitions, instantly resolve\r
19245       if ( !endEventName ) {\r
19246         deferred.resolve(element);\r
19247       }\r
19248     }, 100);\r
19249 \r
19250     // Add our custom cancel function to the promise that is returned\r
19251     // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,\r
19252     // i.e. it will therefore never raise a transitionEnd event for that transition\r
19253     deferred.promise.cancel = function() {\r
19254       if ( endEventName ) {\r
19255         element.unbind(endEventName, transitionEndHandler);\r
19256       }\r
19257       deferred.reject('Transition cancelled');\r
19258     };\r
19259 \r
19260     return deferred.promise;\r
19261   };\r
19262 \r
19263   // Work out the name of the transitionEnd event\r
19264   var transElement = document.createElement('trans');\r
19265   var transitionEndEventNames = {\r
19266     'WebkitTransition': 'webkitTransitionEnd',\r
19267     'MozTransition': 'transitionend',\r
19268     'OTransition': 'oTransitionEnd',\r
19269     'transition': 'transitionend'\r
19270   };\r
19271   var animationEndEventNames = {\r
19272     'WebkitTransition': 'webkitAnimationEnd',\r
19273     'MozTransition': 'animationend',\r
19274     'OTransition': 'oAnimationEnd',\r
19275     'transition': 'animationend'\r
19276   };\r
19277   function findEndEventName(endEventNames) {\r
19278     for (var name in endEventNames){\r
19279       if (transElement.style[name] !== undefined) {\r
19280         return endEventNames[name];\r
19281       }\r
19282     }\r
19283   }\r
19284   $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);\r
19285   $transition.animationEndEventName = findEndEventName(animationEndEventNames);\r
19286   return $transition;\r
19287 }])\r
19288 \r
19289 .factory('$scrollTo', ['$window', function($window) {\r
19290     var $scrollTo = function(offsetLeft, offsetTop, duration) {\r
19291         TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});\r
19292     };\r
19293     return $scrollTo;\r
19294 }])\r
19295 .factory('animation', function(){\r
19296     return TweenMax;\r
19297 })\r
19298 .factory('$progressBar', function(){\r
19299 \r
19300    //Provides a function to pass in code for closure purposes\r
19301    var loadingAnimationCreator = function(onUpdateCallback){\r
19302 \r
19303       //Use closure to setup some resuable code\r
19304       var loadingAnimation = function(callback, duration){\r
19305           TweenMax.to({}, duration, {\r
19306               onUpdateParams: ["{self}"],\r
19307               onUpdate: onUpdateCallback,\r
19308               onComplete: callback\r
19309           });\r
19310       };\r
19311       //Returns a function that takes a callback function and a duration for the animation\r
19312       return (function(){\r
19313         return loadingAnimation;\r
19314       })();\r
19315     };\r
19316 \r
19317   return loadingAnimationCreator;\r
19318 })\r
19319 .factory('$height', function(){\r
19320   var heightAnimation = function(element,duration,height,alpha){\r
19321     TweenMax.to(element,\r
19322       duration,\r
19323       {height:height, autoAlpha:alpha},\r
19324       0);\r
19325   };\r
19326   return heightAnimation;\r
19327 });\r
19328 angular.module('b2b.att.utilities', ['ngSanitize'])\r
19329 .constant('b2bUtilitiesConfig', {\r
19330     prev: '37',\r
19331     up: '38',\r
19332     next: '39',\r
19333     down: '40',\r
19334     type: 'list',\r
19335     columns: 1,\r
19336     enableSearch: false,\r
19337     searchTimer: 200,\r
19338     circularTraversal: false\r
19339 })\r
19340 .constant('b2bWhenScrollEndsConstants', {\r
19341     'threshold': 100,\r
19342     'width': 0,\r
19343     'height': 0\r
19344 })\r
19345 // All breakpoints ranges from >= min and < max\r
19346 .constant('b2bAwdBreakpoints', {\r
19347     breakpoints: {\r
19348         mobile: {\r
19349             min: 1,\r
19350             max: 768\r
19351         },\r
19352         tablet: {\r
19353             min: 768,\r
19354             max: 1025\r
19355         },\r
19356         desktop: {\r
19357             min: 1025,\r
19358             max: 1920\r
19359         }\r
19360     }\r
19361 })\r
19362 .filter('groupBy', function ($timeout) {\r
19363     //Custom GroupBy Filter for treeNav, returns key string and value.childarray as set of grouped elements\r
19364     return function (data, key) {\r
19365         if (!key) return data;\r
19366         var outputPropertyName = '__groupBy__' + key;\r
19367         if (!data[outputPropertyName]) {\r
19368             var result = {};\r
19369             for (var i = 0; i < data.length; i++) {\r
19370                 if (!result[data[i][key]])\r
19371                     result[data[i][key]] = {};\r
19372                 if (!result[data[i][key]].childArray) {\r
19373                     result[data[i][key]].childArray = [];\r
19374                 }\r
19375                 result[data[i][key]].childArray.push(data[i]);\r
19376                 if (data[i].activeGrp && data[i].activeGrp == true) {\r
19377                     console.log('make ' + data[i].grpChild + ' active');\r
19378                     result[data[i][key]].showGroup = true;\r
19379                 }\r
19380             }\r
19381             Object.defineProperty(result, 'length', {enumerable: false,value: Object.keys(result).length});\r
19382             Object.defineProperty(data, outputPropertyName, {enumerable: false,configurable: true,writable:false,value:result});\r
19383             $timeout(function(){delete data[outputPropertyName];},0,false);\r
19384         }\r
19385         return data[outputPropertyName];\r
19386     };\r
19387 })\r
19388 .filter('searchObjectPropertiesFilter', [function() {\r
19389     return function(items, searchText, attrs) {\r
19390         if(!searchText){\r
19391             return items;\r
19392         }\r
19393         var filtered = [];\r
19394         searchText = searchText.toLowerCase();\r
19395         angular.forEach(items, function(item) {\r
19396             angular.forEach(attrs, function(attr) {\r
19397                 if (item.hasOwnProperty(attr) && item[attr].toLowerCase().includes(searchText)) {\r
19398                     filtered.push(item);\r
19399                     return;\r
19400                 }\r
19401             });\r
19402         });\r
19403         return filtered;\r
19404     };\r
19405 }])\r
19406 .filter('unsafe',[ '$sce', function ($sce) { \r
19407     return function(val){ \r
19408        return $sce.trustAsHtml(val); \r
19409     }; \r
19410 }])\r
19411 .filter('b2bHighlight', function () {\r
19412     function escapeRegexp(queryToEscape) {\r
19413         return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');\r
19414     }\r
19415     return function (matchItem, query, className) {\r
19416         return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;\r
19417     }\r
19418 })\r
19419 /*License (MIT)\r
19420 Copyright Â© 2013 Matt Diamond\r
19421 https://github.com/cwilso/AudioRecorder/blob/master/js/recorderjs/recorder.js\r
19422 */\r
19423 .factory('b2bRecorder', function() {\r
19424 \r
19425     var Recorder = function(source, cfg) {\r
19426         var WORKER_PATH = 'recorderWorker.js';\r
19427         var config = cfg || {};\r
19428         var bufferLen = config.bufferLen || 4096;\r
19429         this.context = source.context;\r
19430         if(!this.context.createScriptProcessor) {\r
19431             this.node = this.context.createJavacriptProcessor(bufferLen, 2, 2);\r
19432         } else {\r
19433             this.node = this.context.createScriptProcessor(bufferLen, 2, 2);\r
19434         }\r
19435         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
19436         var blob = new Blob([workerCode]);\r
19437 \r
19438         var worker = new Worker(window.URL.createObjectURL(blob)); //TODO: Use a blob instead\r
19439         worker.postMessage({\r
19440             command: 'init',\r
19441             config: {\r
19442                 sampleRate: this.context.sampleRate\r
19443             }\r
19444         });\r
19445         var recording = false,\r
19446             currCallback;\r
19447 \r
19448         this.node.onaudioprocess = function(e) {\r
19449             if (!recording) return;\r
19450             worker.postMessage({\r
19451                 command: 'record',\r
19452                 buffer: [\r
19453                     e.inputBuffer.getChannelData(0),\r
19454                     e.inputBuffer.getChannelData(1)\r
19455                 ]\r
19456             });\r
19457         };\r
19458 \r
19459         this.configure = function(cfg) {\r
19460             for (var prop in cfg) {//TODO: look into using angular.extend() here\r
19461                 if (cfg.hasOwnProperty(prop)) {\r
19462                     config[prop] = cfg[prop];\r
19463                 }\r
19464             }\r
19465         };\r
19466 \r
19467         this.record = function() {\r
19468             recording = true;\r
19469         };\r
19470 \r
19471         this.stop = function() {\r
19472             recording = false;\r
19473         };\r
19474 \r
19475         this.clear = function() {\r
19476             worker.postMessage({ command: 'clear' });\r
19477             window.URL.revokeObjectURL(blob);\r
19478         };\r
19479 \r
19480         this.getBuffers = function(cb) {\r
19481             currCallback = cb || config.callback;\r
19482             worker.postMessage({ command: 'getBuffers' });\r
19483         };\r
19484 \r
19485         this.exportWAV = function(cb, type) {\r
19486             currCallback = cb || config.callback;\r
19487             type = type || config.type || 'audio/wav';\r
19488             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');\r
19489             worker.postMessage({\r
19490                 command: 'exportWAV',\r
19491                 type: type\r
19492             });\r
19493         };\r
19494 \r
19495         this.exportMonoWAV = function(cb, type) {\r
19496             currCallback = cb || config.callback;\r
19497             type = type || config.type || 'audio/wav';\r
19498             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');\r
19499             worker.postMessage({\r
19500                 command: 'exportMonoWAV',\r
19501                 type: type\r
19502             });\r
19503         };\r
19504 \r
19505         worker.onmessage = function(e) {\r
19506             var blob = e.data;\r
19507             currCallback(blob);\r
19508         };\r
19509 \r
19510         source.connect(this.node);\r
19511         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
19512 \r
19513     };\r
19514 \r
19515     return Recorder;\r
19516 \r
19517 })\r
19518 .factory('b2bViewport', function() {\r
19519   /* Source: https://gist.github.com/bjankord/2399828 */\r
19520   var _viewportWidth = function() {\r
19521     var vpw;\r
19522     var webkit = (!(window.webkitConvertPointFromNodeToPage == null));\r
19523     \r
19524     // Webkit:\r
19525     if ( webkit ) {\r
19526       var vpwtest = document.createElement( "div" );\r
19527       // Sets test div to width 100%, !important overrides any other misc. box model styles that may be set in the CSS\r
19528       vpwtest.style.cssText = "width:100% !important; margin:0 !important; padding:0 !important; border:none !important;";\r
19529       document.documentElement.insertBefore( vpwtest, document.documentElement.firstChild );\r
19530       vpw = vpwtest.offsetWidth;\r
19531       document.documentElement.removeChild( vpwtest );\r
19532     }\r
19533     // IE 6-8:\r
19534     else if ( window.innerWidth === undefined ) { \r
19535       vpw = document.documentElement.clientWidth; \r
19536     }\r
19537     // Other:\r
19538     else{\r
19539       vpw =  window.innerWidth;\r
19540     }\r
19541 \r
19542     return (vpw);\r
19543   }\r
19544   return {\r
19545     viewportWidth: _viewportWidth\r
19546   };\r
19547 })\r
19548 .directive('b2bWhenScrollEnds', function(b2bWhenScrollEndsConstants, $log) {\r
19549     return {\r
19550         restrict: 'A',\r
19551         link: function (scope, element, attrs) {\r
19552             /**\r
19553             * Exposed Attributes:\r
19554             *       threshold - integer - number of pixels before scrollbar hits end that callback is called\r
19555             *       width - integer - override for element's width (px)\r
19556             *       height - integer - override for element's height (px)\r
19557             *       axis - string - x/y for scroll bar axis\r
19558             */\r
19559             var threshold = parseInt(attrs.threshold, 10) || b2bWhenScrollEndsConstants.threshold;\r
19560 \r
19561             if (!attrs.axis || attrs.axis === '') {\r
19562                 $log.warn('axis attribute must be defined for b2bWhenScrollEnds.');\r
19563                 return;\r
19564             }\r
19565 \r
19566             if (attrs.axis === 'x') {\r
19567                 visibleWidth = parseInt(attrs.width, 10) || b2bWhenScrollEndsConstants.width;\r
19568                 if (element.css('width')) {\r
19569                     visibleWidth = element.css('width').split('px')[0];  \r
19570                 }\r
19571 \r
19572                 element[0].addEventListener('scroll', function() {\r
19573                     var scrollableWidth = element.prop('scrollWidth');\r
19574                     if (scrollableWidth === undefined) {\r
19575                         scrollableWidth = 1;\r
19576                     }\r
19577                     var hiddenContentWidth = scrollableWidth - visibleWidth;\r
19578 \r
19579                     if (hiddenContentWidth - element[0].scrollLeft <= threshold) {\r
19580                         /* Scroll almost at bottom, load more rows */\r
19581                         scope.$apply(attrs.b2bWhenScrollEnds);\r
19582                     }\r
19583                 });\r
19584             } else if (attrs.axis === 'y') {\r
19585                 visibleHeight = parseInt(attrs.height, 10) || b2bWhenScrollEndsConstants.height;\r
19586                 if (element.css('width')) {\r
19587                     visibleHeight = element.css('height').split('px')[0]; \r
19588                 }\r
19589 \r
19590                 element[0].addEventListener('scroll', function() {\r
19591                     var scrollableHeight = element.prop('scrollHeight');\r
19592                     if (scrollableHeight === undefined) {\r
19593                         scrollableHeight = 1;\r
19594                     }\r
19595                     var hiddenContentHeight = scrollableHeight - visibleHeight;\r
19596 \r
19597                     if (hiddenContentHeight - element[0].scrollTop <= threshold) {\r
19598                         /* Scroll almost at bottom, load more rows */\r
19599                         scope.$apply(attrs.b2bWhenScrollEnds);\r
19600                     }\r
19601                 });\r
19602             }\r
19603         }\r
19604     };\r
19605 })\r
19606 \r
19607 .factory('$windowBind', ['$window', '$timeout', function($window, $timeout) {\r
19608     var win = angular.element($window);\r
19609     var _scroll = function (flag, callbackFunc, scope) {\r
19610         scope.$watch(flag, function (val) {\r
19611             $timeout(function () {\r
19612                 if (val) {\r
19613                     win.bind('scroll', callbackFunc);\r
19614                 } else {\r
19615                     win.unbind('scroll', callbackFunc);\r
19616                 }\r
19617             });\r
19618         });\r
19619     };\r
19620 \r
19621     var throttle = function(type, name, obj) {\r
19622         obj = obj || window;\r
19623         var running = false;\r
19624         var func = function() {\r
19625             if (running) { return; }\r
19626             running = true;\r
19627              requestAnimationFrame(function() {\r
19628                 obj.dispatchEvent(new CustomEvent(name));\r
19629                 running = false;\r
19630             });\r
19631         };\r
19632         obj.addEventListener(type, func);\r
19633     };\r
19634 \r
19635     var _resize = function(callbackFunc, scope) {\r
19636         throttle("resize", "optimizedResize");\r
19637         window.addEventListener("optimizedResize", function(event) {\r
19638             callbackFunc();\r
19639             //win.bind(event, callbackFunc);\r
19640             if (!scope.$$phase) {\r
19641                 scope.$digest();\r
19642             }\r
19643         });\r
19644     };\r
19645 \r
19646     var _click = function (flag, callbackFunc, scope) {\r
19647         scope.$watch(flag, function (val) {\r
19648             $timeout(function () {\r
19649                 if (val) {\r
19650                     win.bind('click', callbackFunc);\r
19651                 } else {\r
19652                     win.unbind('click', callbackFunc);\r
19653                 }\r
19654             });\r
19655         });\r
19656     };\r
19657 \r
19658     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {\r
19659         if (timeoutFlag) {\r
19660             if (!(timeoutValue)) {\r
19661                 timeoutValue = 0;\r
19662             }\r
19663             scope.$watch(flag, function (newVal, oldVal) {\r
19664                 if (newVal !== oldVal) {\r
19665                     $timeout(function () {\r
19666                         if (newVal) {\r
19667                             win.bind(event, callbackFunc);\r
19668                         } else {\r
19669                             win.unbind(event, callbackFunc);\r
19670                         }\r
19671                     }, timeoutValue);\r
19672                 }\r
19673             });\r
19674         } else {\r
19675             scope.$watch(flag, function (newVal, oldVal) {\r
19676                 if (newVal !== oldVal) {\r
19677                     if (newVal) {\r
19678                         win.bind(event, callbackFunc);\r
19679                     } else {\r
19680                         win.unbind(event, callbackFunc);\r
19681                     }\r
19682                 }\r
19683             });\r
19684         }\r
19685     };\r
19686 \r
19687     return {\r
19688         click: _click,\r
19689         scroll: _scroll,\r
19690         event: _event, \r
19691         resize: _resize\r
19692     };\r
19693 }])\r
19694 \r
19695 .factory('keymap', function () {\r
19696     return {\r
19697         KEY: {\r
19698             TAB: 9,\r
19699             ENTER: 13,\r
19700             ESC: 27,\r
19701             SPACE: 32,\r
19702             LEFT: 37,\r
19703             UP: 38,\r
19704             RIGHT: 39,\r
19705             DOWN: 40,\r
19706             SHIFT: 16,\r
19707             CTRL: 17,\r
19708             ALT: 18,\r
19709             PAGE_UP: 33,\r
19710             PAGE_DOWN: 34,\r
19711             HOME: 36,\r
19712             END: 35,\r
19713             BACKSPACE: 8,\r
19714             DELETE: 46,\r
19715             COMMAND: 91\r
19716         },\r
19717         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
19718         },\r
19719         isControl: function (e) {\r
19720             var k = e.keyCode;\r
19721             switch (k) {\r
19722             case this.KEY.COMMAND:\r
19723             case this.KEY.SHIFT:\r
19724             case this.KEY.CTRL:\r
19725             case this.KEY.ALT:\r
19726                 return true;\r
19727             default:;\r
19728             }\r
19729 \r
19730             if (e.metaKey) {\r
19731                 return true;\r
19732             }\r
19733 \r
19734             return false;\r
19735         },\r
19736         isFunctionKey: function (k) {\r
19737             k = k.keyCode ? k.keyCode : k;\r
19738             return k >= 112 && k <= 123;\r
19739         },\r
19740         isVerticalMovement: function (k) {\r
19741             return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);\r
19742         },\r
19743         isHorizontalMovement: function (k) {\r
19744             return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);\r
19745         },\r
19746         isAllowedKey: function (k) {\r
19747             return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);\r
19748         },\r
19749         isNumericKey: function (e) {\r
19750             var k = e.keyCode;\r
19751             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105)) {\r
19752                 return true;\r
19753             } else {\r
19754                 return false;\r
19755             }\r
19756         },\r
19757         isAlphaNumericKey: function (e) {\r
19758             var k = e.keyCode;\r
19759             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105) || (k >= 65 && k <= 90)) {\r
19760                 return true;\r
19761             } else {\r
19762                 return false;\r
19763             }\r
19764         }\r
19765     };\r
19766 })\r
19767 \r
19768 .factory('$isElement', [function () {\r
19769     var isElement = function (currentElem, targetElem, alternateElem) {\r
19770         if (currentElem[0] === targetElem[0]) {\r
19771             return true;\r
19772         } else if (currentElem[0] === alternateElem[0]) {\r
19773             return false;\r
19774         } else {\r
19775             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);\r
19776         }\r
19777     };\r
19778 \r
19779     return isElement;\r
19780 }])\r
19781 \r
19782 .factory('events', function () {\r
19783     var _stopPropagation = function (evt) {\r
19784         if (evt.stopPropagation) {\r
19785             evt.stopPropagation();\r
19786         } else {\r
19787             evt.returnValue = false;\r
19788         }\r
19789     };\r
19790     var _preventDefault = function (evt) {\r
19791         if (evt.preventDefault) {\r
19792             evt.preventDefault();\r
19793         } else {\r
19794             evt.returnValue = false;\r
19795         }\r
19796     }\r
19797     return {\r
19798         stopPropagation: _stopPropagation,\r
19799         preventDefault: _preventDefault\r
19800     };\r
19801 })\r
19802 \r
19803 \r
19804 .factory('$documentBind', ['$document', '$timeout', function ($document, $timeout) {\r
19805     var _click = function (flag, callbackFunc, scope) {\r
19806         scope.$watch(flag, function (val) {\r
19807             $timeout(function () {\r
19808                 if (val) {\r
19809                     $document.bind('click', callbackFunc);\r
19810                 } else {\r
19811                     $document.unbind('click', callbackFunc);\r
19812                 }\r
19813             });\r
19814         });\r
19815     };\r
19816 \r
19817     var _scroll = function (flag, callbackFunc, scope) {\r
19818         scope.$watch(flag, function (val) {\r
19819             $timeout(function () {\r
19820                 if (val) {\r
19821                     $document.bind('scroll', callbackFunc);\r
19822                 } else {\r
19823                     $document.unbind('scroll', callbackFunc);\r
19824                 }\r
19825             });\r
19826         });\r
19827     };\r
19828 \r
19829     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {\r
19830         if (timeoutFlag) {\r
19831             if (!(timeoutValue)) {\r
19832                 timeoutValue = 0;\r
19833             }\r
19834             scope.$watch(flag, function (newVal, oldVal) {\r
19835                 if (newVal !== oldVal) {\r
19836                     $timeout(function () {\r
19837                         if (newVal) {\r
19838                             $document.bind(event, callbackFunc);\r
19839                         } else {\r
19840                             $document.unbind(event, callbackFunc);\r
19841                         }\r
19842                     }, timeoutValue);\r
19843                 }\r
19844             });\r
19845         } else {\r
19846             scope.$watch(flag, function (newVal, oldVal) {\r
19847                 if (newVal !== oldVal) {\r
19848                     if (newVal) {\r
19849                         $document.bind(event, callbackFunc);\r
19850                     } else {\r
19851                         $document.unbind(event, callbackFunc);\r
19852                     }\r
19853                 }\r
19854             });\r
19855         }\r
19856     };\r
19857 \r
19858     return {\r
19859         click: _click,\r
19860         scroll: _scroll,\r
19861         event: _event\r
19862     };\r
19863 }])\r
19864 \r
19865 .directive('b2bOnlyNums', function (keymap) {\r
19866     return {\r
19867         restrict: 'A',\r
19868         require: 'ngModel',\r
19869         link: function (scope, elm, attrs, ctrl) {\r
19870             var maxChars = attrs.b2bOnlyNums ? attrs.b2bOnlyNums : 4;\r
19871             elm.on('keydown', function (event) {\r
19872                 if ((event.which >= 48 && event.which <= 57) || (event.which >= 96 && event.which <= 105)) {\r
19873                     // check for maximum characters allowed\r
19874                     if (elm.val().length < maxChars){\r
19875                         return true;\r
19876                     } else {\r
19877                         event.preventDefault();\r
19878                         return false;\r
19879                     }\r
19880                 } else if ([8, 9, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {\r
19881                     // to allow backspace, tab, enter, escape, arrows\r
19882                     return true;\r
19883                 } else if (event.altKey || event.ctrlKey) {\r
19884                     // to allow alter, control, and shift keys\r
19885                     return true;\r
19886                 } else {\r
19887                     // to stop others\r
19888                     event.preventDefault();\r
19889                     return false;\r
19890                 }\r
19891             });\r
19892 \r
19893             var validateString = function (value) {\r
19894                 if (angular.isUndefined(value) || value === null || value === '') {\r
19895                     return ctrl.$modelValue;\r
19896                 }\r
19897                 return value;\r
19898             };\r
19899             ctrl.$parsers.unshift(validateString);\r
19900         }\r
19901     }\r
19902 })\r
19903 \r
19904 .directive('b2bKeyupClick', [ function () {\r
19905     return {\r
19906         restrict: 'A',\r
19907         link: function (scope, elem, attr) {\r
19908             var keyCode = [];\r
19909             attr.$observe('b2bKeyupClick', function (value) {\r
19910                 if (value) {\r
19911                     keyCode = value.split(',');\r
19912                 }\r
19913             });\r
19914             elem.bind('keydown keyup', function (ev) {\r
19915                 var keyCodeCondition = function () {\r
19916                     var flag = false;\r
19917                     if (!(ev.keyCode)) {\r
19918                         if (ev.which) {\r
19919                             ev.keyCode = ev.which;\r
19920                         } else if (ev.charCode) {\r
19921                             ev.keyCode = ev.charCode;\r
19922                         }\r
19923                     }\r
19924                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {\r
19925                         flag = true;\r
19926                     }\r
19927                     return flag;\r
19928                 };\r
19929                 if (ev.type === 'keydown' && keyCodeCondition()) {\r
19930                     ev.preventDefault();\r
19931                 }\r
19932                 else if (ev.type === 'keyup' && keyCodeCondition()) {\r
19933                     elem[0].click();\r
19934                 }\r
19935             });\r
19936         }\r
19937     };\r
19938 }])\r
19939 \r
19940 .factory('b2bDOMHelper', function() {\r
19941 \r
19942     var _isTabable = function(node) {\r
19943         var element = angular.element(node);\r
19944         var tagName = element[0].tagName.toUpperCase();\r
19945 \r
19946         if (isHidden(element)) {\r
19947             return false;\r
19948         }\r
19949         if (element.attr('tabindex') !== undefined) {\r
19950             return (parseInt(element.attr('tabindex'), 10) >= 0);\r
19951         }\r
19952         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {\r
19953             if (tagName === 'A' || tagName === 'AREA') {\r
19954                 // anchors/areas without href are not focusable\r
19955                 return (element[0].href !== '');\r
19956             }\r
19957             return !(element[0].disabled || element[0].readOnly);\r
19958         }\r
19959         return false;\r
19960     };\r
19961 \r
19962     function isValidChild(child) {\r
19963         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';\r
19964     }\r
19965     \r
19966     function isHidden(obj) {\r
19967         var elem = angular.element(obj);\r
19968         var elemStyle = undefined;\r
19969         if(obj instanceof HTMLElement){\r
19970             elemStyle = window.getComputedStyle(obj);\r
19971         }\r
19972         else {\r
19973             elemStyle = window.getComputedStyle(obj[0]);\r
19974         }\r
19975         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || elemStyle.display === 'none' || elemStyle.visibility === 'hidden' || elem.css('visibility') === 'hidden';\r
19976     }\r
19977 \r
19978     function hasValidParent(obj) {\r
19979         return (isValidChild(obj) && obj.parentElement.nodeName !== 'BODY');\r
19980     }\r
19981 \r
19982     function traverse(obj, fromTop) {\r
19983         var obj = obj || document.getElementsByTagName('body')[0];\r
19984         if (isValidChild(obj) && _isTabable(obj)) {\r
19985             return obj;\r
19986         }\r
19987         // If object is hidden, skip it's children\r
19988         if (isValidChild(obj) && isHidden(obj)) {\r
19989             return undefined;\r
19990         } \r
19991         // If object is hidden, skip it's children\r
19992         if (angular.element(obj).hasClass('ng-hide')) {\r
19993             return undefined;\r
19994         }  \r
19995         if (obj.hasChildNodes()) {\r
19996             var child;\r
19997             if (fromTop) {\r
19998                 child = obj.firstChild;\r
19999             } else {\r
20000                 child = obj.lastChild;\r
20001             }\r
20002             while(child) {\r
20003                 var res =  traverse(child, fromTop);\r
20004                 if(res){\r
20005                     return res;\r
20006                 }\r
20007                 else{\r
20008                     if (fromTop) {\r
20009                         child = child.nextSibling;\r
20010                     } else {\r
20011                         child = child.previousSibling;\r
20012                     }\r
20013                 }\r
20014             }\r
20015         }\r
20016         else{\r
20017             return undefined;\r
20018         }\r
20019     }\r
20020 \r
20021     var _previousElement = function(el, isFocusable){\r
20022 \r
20023         var elem = el;\r
20024         if (el.hasOwnProperty('length')) {\r
20025             elem = el[0];\r
20026         }\r
20027 \r
20028         var parent = elem.parentElement;\r
20029         var previousElem = undefined;\r
20030 \r
20031         if(isFocusable) {\r
20032             if (hasValidParent(elem)) {\r
20033                 var siblings = angular.element(parent).children();\r
20034                 if (siblings.length > 0) {\r
20035                     // Good practice to splice out the elem from siblings if there, saving some time.\r
20036                     // We allow for a quick check for jumping to parent first before removing. \r
20037                     if (siblings[0] === elem) {\r
20038                         // If we are looking at immidiate parent and elem is first child, we need to go higher\r
20039                         var e = _previousElement(angular.element(elem).parent(), isFocusable);\r
20040                         if (_isTabable(e)) {\r
20041                             return e;\r
20042                         }\r
20043                     } else {\r
20044                         // I need to filter myself and any nodes next to me from the siblings\r
20045                         var indexOfElem = Array.prototype.indexOf.call(siblings, elem);\r
20046                         siblings = Array.prototype.filter.call(siblings, function(item, itemIndex) {\r
20047                             if (!angular.equals(elem, item) && itemIndex < indexOfElem) {\r
20048                                 return true;\r
20049                             }\r
20050                         });\r
20051                     }\r
20052                     // We need to search backwards\r
20053                     for (var i = 0; i <= siblings.length-1; i++) {//for (var i = siblings.length-1; i >= 0; i--) {\r
20054                         var ret = traverse(siblings[i], false);\r
20055                         if (ret !== undefined) {\r
20056                             return ret;\r
20057                         }\r
20058                     }\r
20059 \r
20060                     var e = _previousElement(angular.element(elem).parent(), isFocusable);\r
20061                     if (_isTabable(e)) {\r
20062                         return e;\r
20063                     }\r
20064                 }\r
20065             }\r
20066         } else {\r
20067             var siblings = angular.element(parent).children();\r
20068             if (siblings.length > 1) {\r
20069                 // Since indexOf is on Array.prototype and parent.children is a NodeList, we have to use call()\r
20070                 var index = Array.prototype.indexOf.call(siblings, elem);\r
20071                 previousElem = siblings[index-1];\r
20072             }\r
20073         }\r
20074         return previousElem;\r
20075     };\r
20076 \r
20077     var _lastTabableElement = function(el) {\r
20078         /* This will return the first tabable element from the parent el */\r
20079         var elem = el;\r
20080         if (el.hasOwnProperty('length')) {\r
20081             elem = el[0];\r
20082         }\r
20083 \r
20084         return traverse(elem, false);\r
20085     };\r
20086 \r
20087     var _firstTabableElement = function(el) {\r
20088         /* This will return the first tabable element from the parent el */\r
20089         var elem = el;\r
20090         if (el.hasOwnProperty('length')) {\r
20091             elem = el[0];\r
20092         }\r
20093 \r
20094         return traverse(elem, true);\r
20095     };\r
20096 \r
20097     var _isInDOM = function(obj) {\r
20098       return document.documentElement.contains(obj);\r
20099     }\r
20100 \r
20101     return {\r
20102         firstTabableElement: _firstTabableElement,\r
20103         lastTabableElement: _lastTabableElement,\r
20104         previousElement: _previousElement,\r
20105         isInDOM: _isInDOM,\r
20106         isTabable: _isTabable,\r
20107         isHidden: isHidden\r
20108     };\r
20109 })\r
20110 \r
20111 .factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', function ($document, $isElement, DOMHelper, keymap) {\r
20112     var elementStack = [];\r
20113     var stackHead = undefined;\r
20114     var trapFocusInElement = function (flag) {\r
20115         var bodyElements = $document.find('body').children();\r
20116 \r
20117         var firstTabableElement = angular.element(DOMHelper.firstTabableElement(stackHead));\r
20118         var lastTabableElement = angular.element(DOMHelper.lastTabableElement(stackHead));\r
20119 \r
20120         var trapKeyboardFocusInFirstElement = function (e) {\r
20121             if (!e.keyCode) {\r
20122                 e.keyCode = e.which;\r
20123             }\r
20124 \r
20125             if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {\r
20126                 lastTabableElement[0].focus();\r
20127                 e.preventDefault(e);\r
20128                 e.stopPropagation(e);\r
20129             }\r
20130 \r
20131         };\r
20132 \r
20133         var trapKeyboardFocusInLastElement = function (e) {\r
20134             if (!e.keyCode) {\r
20135                 e.keyCode = e.which;\r
20136             }\r
20137 \r
20138             if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {\r
20139                 firstTabableElement[0].focus();\r
20140                 e.preventDefault(e);\r
20141                 e.stopPropagation(e);\r
20142             }\r
20143         };\r
20144 \r
20145         if (flag) {\r
20146             for (var i = 0; i < bodyElements.length; i++) {\r
20147                 if (bodyElements[i] !== stackHead[0]) {\r
20148                     bodyElements.eq(i).attr('aria-hidden', true);\r
20149                 }\r
20150             }\r
20151             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);\r
20152             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);\r
20153         } else {\r
20154             for (var j = 0; j < bodyElements.length; j++) {\r
20155                 if (bodyElements[j] !== stackHead[0]) {\r
20156                     bodyElements.eq(j).removeAttr('aria-hidden');\r
20157                 }\r
20158             }\r
20159             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);\r
20160             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);\r
20161         }\r
20162     };\r
20163     var toggleTrapFocusInElement = function (flag, element) {\r
20164         if (angular.isDefined(flag) && angular.isDefined(element)) {\r
20165             if (angular.isUndefined(stackHead)) {\r
20166                 stackHead = element;\r
20167                 trapFocusInElement(flag);\r
20168             } else {\r
20169                 if (flag) {\r
20170                     trapFocusInElement(false);\r
20171                     elementStack.push(stackHead);\r
20172                     stackHead = element;\r
20173                     trapFocusInElement(true);\r
20174                 } else {\r
20175                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {\r
20176                         trapFocusInElement(false);\r
20177                         stackHead = elementStack.pop();\r
20178                         if (angular.isDefined(stackHead)) {\r
20179                             trapFocusInElement(true);\r
20180                         }\r
20181                     }\r
20182                 }\r
20183             }\r
20184         }\r
20185     };\r
20186 \r
20187     return toggleTrapFocusInElement;\r
20188 }])\r
20189 \r
20190 .factory('DOMHelper', function () {\r
20191 \r
20192     var _isTabable = function (node) {\r
20193         var element = angular.element(node);\r
20194         var tagName = element[0].tagName.toUpperCase();\r
20195 \r
20196         if (isHidden(element)) {\r
20197             return false;\r
20198         }\r
20199         if (element.attr('tabindex') !== undefined) {\r
20200             return (parseInt(element.attr('tabindex'), 10) >= 0);\r
20201         }\r
20202         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {\r
20203             if (tagName === 'A' || tagName === 'AREA') {\r
20204                 // anchors/areas without href are not focusable\r
20205                 return (element[0].href !== '');\r
20206             }\r
20207             return !(element[0].disabled || element[0].readOnly);\r
20208         }\r
20209         return false;\r
20210     };\r
20211 \r
20212     function isValidChild(child) {\r
20213         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';\r
20214     }\r
20215 \r
20216     function isHidden(obj) {\r
20217         var elem = angular.element(obj);\r
20218         var style;\r
20219         try {\r
20220             style = window.getComputedStyle(obj);\r
20221         }\r
20222         catch(err) {\r
20223             style = window.getComputedStyle(obj[0]);\r
20224         }\r
20225 \r
20226         // getComputedStyle() for Zepto object returns null\r
20227         if (style === null){\r
20228             return elem.hasClass('ng-hide') || elem.css('display') === 'none';\r
20229         }\r
20230 \r
20231         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || style.display === 'none' || style.display === 'hidden';\r
20232     }\r
20233 \r
20234     function traverse(obj, fromTop) {\r
20235         var obj = obj || document.getElementsByTagName('body')[0];\r
20236 \r
20237         if (isValidChild(obj) && _isTabable(obj)) {\r
20238             return obj;\r
20239         }\r
20240 \r
20241         // If object is hidden, skip it's children\r
20242         if (isValidChild(obj) && isHidden(obj)) {\r
20243             return undefined;\r
20244         }\r
20245         // If object is hidden, skip it's children\r
20246         if (angular.element(obj).hasClass('ng-hide')) {\r
20247             return undefined;\r
20248         }\r
20249 \r
20250         if (obj.hasChildNodes()) {\r
20251             var child;\r
20252             if (fromTop) {\r
20253                 child = obj.firstChild;\r
20254             } else {\r
20255                 child = obj.lastChild;\r
20256             }\r
20257             while (child) {\r
20258                 var res = traverse(child, fromTop);\r
20259                 if (res) {\r
20260                     return res;\r
20261                 } else {\r
20262                     if (fromTop) {\r
20263                         child = child.nextSibling;\r
20264                     } else {\r
20265                         child = child.previousSibling;\r
20266                     }\r
20267                 }\r
20268             }\r
20269         } else {\r
20270             return undefined;\r
20271         }\r
20272     }\r
20273 \r
20274     var _lastTabableElement = function (el) {\r
20275         /* This will return the last tabable element from the parent el */\r
20276         var elem = el;\r
20277         if (el.hasOwnProperty('length')) {\r
20278             elem = el[0];\r
20279         }\r
20280 \r
20281         return traverse(elem, false);\r
20282     };\r
20283 \r
20284     var _firstTabableElement = function (el) {\r
20285         /* This will return the first tabable element from the parent el */\r
20286         var elem = el;\r
20287         if (el.hasOwnProperty('length')) {\r
20288             elem = el[0];\r
20289         }\r
20290 \r
20291         return traverse(elem, true);\r
20292     };\r
20293 \r
20294     return {\r
20295         firstTabableElement: _firstTabableElement,\r
20296         lastTabableElement: _lastTabableElement,\r
20297         isTabable: _isTabable\r
20298     };\r
20299 })\r
20300 \r
20301 .factory('windowOrientation', ['$window', function ($window) {\r
20302     var _isPotrait = function () {\r
20303         if ($window.innerHeight > $window.innerWidth) {\r
20304             return true;\r
20305         } else {\r
20306             return false;\r
20307         }\r
20308     };\r
20309     var _isLandscape = 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 \r
20317     return {\r
20318         isPotrait: _isPotrait,\r
20319         isLandscape: _isLandscape\r
20320     };\r
20321 }])\r
20322 \r
20323 .directive('b2bNextElement', function() {\r
20324   return {\r
20325     restrict: 'A',\r
20326     transclude: false,\r
20327     link: function (scope, elem, attr, ctrls) {\r
20328 \r
20329         var keys = attr.b2bNextElement.split(',');\r
20330 \r
20331         elem.bind('keydown', function (e) {\r
20332             var nextElement = elem.next();\r
20333             if(e.keyCode == 39 || e.keyCode == 40){ // if e.keyCode in keys\r
20334                 if(nextElement.length) {\r
20335                     e.preventDefault();\r
20336                     nextElement[0].focus();\r
20337                 }\r
20338             }\r
20339         });\r
20340     }\r
20341   }\r
20342 })\r
20343 \r
20344 .directive('b2bAccessibilityClick', [function () {\r
20345     return {\r
20346         restrict: 'A',\r
20347         link: function (scope, elem, attr, ctrl) {\r
20348             var keyCode = [];\r
20349             attr.$observe('b2bAccessibilityClick', function (value) {\r
20350                 if (value) {\r
20351                     keyCode = value.split(',');\r
20352                 }\r
20353             });\r
20354             elem.bind('keydown keypress', function (ev) {\r
20355                 var keyCodeCondition = function () {\r
20356                     var flag = false;\r
20357                     if (!(ev.keyCode)) {\r
20358                         if (ev.which) {\r
20359                             ev.keyCode = ev.which; \r
20360                         } else if (ev.charCode) {\r
20361                             ev.keyCode = ev.charCode;\r
20362                         }\r
20363                     }\r
20364                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {\r
20365                         flag = true;\r
20366                     }\r
20367                     return flag;\r
20368                 };\r
20369                 if (keyCode.length > 0 && keyCodeCondition()) {\r
20370                     elem[0].click();\r
20371                     ev.preventDefault();\r
20372                 }\r
20373             });\r
20374         }\r
20375     };\r
20376 }])\r
20377 \r
20378 .directive('b2bReset', ['$compile', function ($compile) {\r
20379         return {\r
20380             restrict: 'A',\r
20381             require: ['?ngModel', 'b2bReset'],\r
20382             controller: ['$scope', function ($scope) {\r
20383                 var resetButton = angular.element('<button type="button" class="reset-field" tabindex="-1" aria-label="Click to reset" aria-hidden="true" role="button"></button>');\r
20384 \r
20385                 this.getResetButton = function () {\r
20386                     return resetButton;\r
20387                 };\r
20388             }],\r
20389             link: function (scope, element, attrs, ctrls) {\r
20390 \r
20391                 var ngModelCtrl = ctrls[0];\r
20392                 var ctrl = ctrls[1];\r
20393 \r
20394                 var resetButton = ctrl.getResetButton();\r
20395 \r
20396 \r
20397                 resetButton.on('click', function () {\r
20398                     element[0].value = '';\r
20399 \r
20400                     if (ngModelCtrl) {\r
20401                         if (attrs.b2bReset) {\r
20402                             ngModelCtrl.$setViewValue(attrs.b2bReset);\r
20403                         } else {\r
20404                             ngModelCtrl.$setViewValue('');\r
20405                         }\r
20406                         element[0].value = ngModelCtrl.$viewValue;\r
20407                         ngModelCtrl.$render();\r
20408                         scope.$digest();\r
20409                     }\r
20410                     element[0].focus();\r
20411                     element[0].select();\r
20412                 });\r
20413 \r
20414                 var addResetButton = function () {\r
20415                     element.after(resetButton);\r
20416                     element.unbind('focus input', addResetButton);\r
20417                 };\r
20418 \r
20419                 element.bind('focus input', addResetButton);\r
20420             }\r
20421         };\r
20422     }])\r
20423 \r
20424 .directive('b2bPrevElement', ['b2bDOMHelper', 'keymap', function (b2bDOMHelper, keymap) {\r
20425   return {\r
20426     restrict: 'A',\r
20427     transclude: false,\r
20428     link: function (scope, elem, attr) {\r
20429 \r
20430         elem.bind('keydown', function (e) {\r
20431             if(e.keyCode == 37 || e.keyCode == 38){\r
20432                 var prev = b2bDOMHelper.previousElement(elem, false);\r
20433                 if(prev !== undefined) {\r
20434                     e.preventDefault();\r
20435                     prev.focus();\r
20436                 }\r
20437             }\r
20438         });\r
20439     }\r
20440   }\r
20441 }])\r
20442 /**\r
20443  * @param {integer} delay - Timeout before first and last focusable elements are found\r
20444  * @param {boolean} trigger - A variable on scope that will trigger refinding first/last focusable elements \r
20445  */\r
20446 .directive('b2bTrapFocusInsideElement', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {\r
20447     return {\r
20448         restrict: 'A',\r
20449         transclude: false,\r
20450         link: function (scope, elem, attr) {\r
20451 \r
20452             var delay = parseInt(attr.delay, 10) || 10;\r
20453 \r
20454             /* Before opening modal, find the focused element */\r
20455             var firstTabableElement = undefined,\r
20456                 lastTabableElement = undefined;\r
20457                 \r
20458             function init() {\r
20459                 $timeout(function () {\r
20460                     firstTabableElement = b2bDOMHelper.firstTabableElement(elem);\r
20461                     lastTabableElement = b2bDOMHelper.lastTabableElement(elem);\r
20462                     angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);\r
20463                     angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);\r
20464                 }, delay, false);\r
20465             }\r
20466 \r
20467             if (attr.trigger !== undefined) {\r
20468                 scope.$watch('trigger', function() {\r
20469                     if (scope.trigger) {\r
20470                         init();\r
20471                     }\r
20472                 });\r
20473             }\r
20474 \r
20475             var firstTabableElementKeyhandler = function(e) {\r
20476                 if (!e.keyCode) {\r
20477                     e.keyCode = e.which;\r
20478                 }\r
20479                 if (e.keyCode === keymap.KEY.TAB && e.shiftKey) {\r
20480                     if (attr.trapFocusInsideElement === 'true') {\r
20481                         var temp = b2bDOMHelper.lastTabableElement(elem);\r
20482                         if (lastTabableElement !== temp) {\r
20483                             // Unbind keydown handler on lastTabableElement\r
20484                             angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);\r
20485                             lastTabableElement = temp;\r
20486                             angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);\r
20487                         }\r
20488                     }\r
20489                     lastTabableElement.focus();\r
20490                     events.preventDefault(e);\r
20491                     events.stopPropagation(e);\r
20492                 }\r
20493             };\r
20494 \r
20495             var lastTabableElementKeyhandler = function(e) {\r
20496                 if (!e.keyCode) {\r
20497                     e.keyCode = e.which;\r
20498                 }\r
20499                 if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {\r
20500                     if (attr.trapFocusInsideElement === 'true') {\r
20501                         var temp = b2bDOMHelper.firstTabableElement(elem);\r
20502                         if (firstTabableElement !== temp) {\r
20503                             // Unbind keydown handler on firstTabableElement\r
20504                             angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);\r
20505                             firstTabableElement = temp;\r
20506                             angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);\r
20507                         }\r
20508                     }\r
20509                     firstTabableElement.focus();\r
20510                     events.preventDefault(e);\r
20511                     events.stopPropagation(e);\r
20512                 }\r
20513             };\r
20514 \r
20515             init();\r
20516         }\r
20517     };\r
20518 }])\r
20519 \r
20520 .factory('trapFocusInElement', ['$document', '$isElement', 'DOMHelper', 'keymap', '$interval', function ($document, $isElement, DOMHelper, keymap, $interval) {\r
20521     var elementStack = [];\r
20522     var stackHead = undefined;\r
20523     var stopInterval = undefined;\r
20524     var intervalRequired = false;\r
20525     var interval = 1000;\r
20526     var firstTabableElement, lastTabableElement;\r
20527 \r
20528     var trapKeyboardFocusInFirstElement = function (e) {\r
20529         if (!e.keyCode) {\r
20530             e.keyCode = e.which;\r
20531         }\r
20532 \r
20533         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {\r
20534             lastTabableElement[0].focus();\r
20535             e.preventDefault(e);\r
20536             e.stopPropagation(e);\r
20537         }\r
20538 \r
20539     };\r
20540 \r
20541     var trapKeyboardFocusInLastElement = function (e) {\r
20542         if (!e.keyCode) {\r
20543             e.keyCode = e.which;\r
20544         }\r
20545 \r
20546         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {\r
20547             firstTabableElement[0].focus();\r
20548             e.preventDefault(e);\r
20549             e.stopPropagation(e);\r
20550         }\r
20551     };\r
20552 \r
20553     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {\r
20554         var bodyElements = $document.find('body').children();\r
20555 \r
20556         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(DOMHelper.firstTabableElement(stackHead));\r
20557         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(DOMHelper.lastTabableElement(stackHead));\r
20558 \r
20559         if (flag) {\r
20560             for (var i = 0; i < bodyElements.length; i++) {\r
20561                 if (bodyElements[i] !== stackHead[0]) {\r
20562                     bodyElements.eq(i).attr('aria-hidden', true);\r
20563                 }\r
20564             }\r
20565             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);\r
20566             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);\r
20567         } else {\r
20568             for (var j = 0; j < bodyElements.length; j++) {\r
20569                 if (bodyElements[j] !== stackHead[0]) {\r
20570                     bodyElements.eq(j).removeAttr('aria-hidden');\r
20571                 }\r
20572             }\r
20573             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);\r
20574             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);\r
20575         }\r
20576 \r
20577         if (intervalRequired && flag) {\r
20578             stopInterval = $interval(function () {\r
20579                 var firstTabableElementTemp = angular.element(DOMHelper.firstTabableElement(stackHead));\r
20580                 var lastTabableElementTemp = angular.element(DOMHelper.lastTabableElement(stackHead));\r
20581                 if (firstTabableElementTemp[0] !== firstTabableElement[0] || lastTabableElementTemp[0] !== lastTabableElement[0]) {\r
20582                     $interval.cancel(stopInterval);\r
20583                     stopInterval = undefined;\r
20584                     trapFocusInElement(false, firstTabableElement, lastTabableElement);\r
20585                     trapFocusInElement(true, firstTabableElementTemp, lastTabableElementTemp);\r
20586                 }\r
20587             }, interval);\r
20588         } else {\r
20589             if (stopInterval) {\r
20590                 $interval.cancel(stopInterval);\r
20591                 stopInterval = undefined;\r
20592             }\r
20593         }\r
20594     };\r
20595     var toggleTrapFocusInElement = function (flag, element, intervalRequiredParam, intervalParam) {\r
20596         intervalRequired = intervalRequiredParam ? intervalRequiredParam : intervalRequired;\r
20597         interval = intervalParam ? intervalParam : interval;\r
20598         if (angular.isDefined(flag) && angular.isDefined(element)) {\r
20599             if (flag && angular.isUndefined(stackHead)) {\r
20600                 stackHead = element;\r
20601                 trapFocusInElement(flag);\r
20602             } else {\r
20603                 if (flag) {\r
20604                     trapFocusInElement(false);\r
20605                     elementStack.push(stackHead);\r
20606                     stackHead = element;\r
20607                     trapFocusInElement(true);\r
20608                 } else {\r
20609                     if (angular.isDefined(stackHead) && (stackHead[0] === element[0])) {\r
20610                         trapFocusInElement(false);\r
20611                         stackHead = elementStack.pop();\r
20612                         if (angular.isDefined(stackHead)) {\r
20613                             trapFocusInElement(true);\r
20614                         }\r
20615                     }\r
20616                 }\r
20617             }\r
20618         } else {\r
20619             if (angular.isDefined(stackHead)) {\r
20620                 trapFocusInElement(false, firstTabableElement, lastTabableElement);\r
20621                 trapFocusInElement(true);\r
20622             }\r
20623         }\r
20624     };\r
20625 \r
20626     return toggleTrapFocusInElement;\r
20627 }])\r
20628 \r
20629 .directive('b2bSetNextFocusOn', ['b2bDOMHelper', '$timeout', function(b2bDOMHelper, $timeout) {\r
20630     return {\r
20631         restrict: 'A',\r
20632         scope: true,\r
20633         link: function (scope, elem, attr) {\r
20634             elem.bind('click', function(){\r
20635                 var firstFocusableElement = undefined; \r
20636                 var containerElem = undefined; \r
20637                 var containerArray = [];\r
20638                 var timeout = parseInt(attr.setNextFocusTimeout, 0) | 100;\r
20639                 var index = parseInt(attr.b2bSetNextFocusIndex, 0) | 0;\r
20640 \r
20641                  /*\r
20642                   *Fix for IE7 and lower \r
20643                   *polyfill src: https://github.com/HubSpot/pace/issues/102\r
20644                   */\r
20645                 if (!document.querySelectorAll) {\r
20646                     document.querySelectorAll = function (selectors) {\r
20647                         var style = document.createElement('style'), elements = [], element;\r
20648                         document.documentElement.firstChild.appendChild(style);\r
20649                         document._qsa = [];\r
20650 \r
20651                         style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';\r
20652                         window.scrollBy(0, 0);\r
20653                         style.parentNode.removeChild(style);\r
20654 \r
20655                         while (document._qsa.length) {\r
20656                             element = document._qsa.shift();\r
20657                             element.style.removeAttribute('x-qsa');\r
20658                             elements.push(element);\r
20659                         }\r
20660                         document._qsa = null;\r
20661                         return elements;\r
20662                     };\r
20663                 }\r
20664 \r
20665                 if (attr.b2bSetNextFocusOn === '') {\r
20666                     return;\r
20667                 } else {\r
20668                     containerArray = attr.b2bSetNextFocusOn.split(' ');\r
20669                 }\r
20670                 $timeout(function(){\r
20671                     var i = 0;\r
20672                     do { // cycles thru containerArray until finds a match in DOM to set focus to\r
20673                         containerElem = document.querySelectorAll(containerArray[i])[index]; \r
20674                         i++;\r
20675                     } while ( (!containerElem) && (i < containerArray.length) );\r
20676                     if(containerElem){\r
20677                         if (!angular.isDefined(firstFocusableElement)) { \r
20678                             firstFocusableElement = b2bDOMHelper.firstTabableElement(containerElem); \r
20679                         }\r
20680                         firstFocusableElement.focus(); \r
20681                     }\r
20682                 }, timeout, false)\r
20683             });\r
20684         }\r
20685 \r
20686     };\r
20687 }])\r
20688 \r
20689 .directive('b2bInputAllow', [function() {\r
20690     return {\r
20691         restrict: 'A',\r
20692         require: 'ngModel',\r
20693         link: function (scope, elem, attr, ctrl) {\r
20694             var regexExpression = null;\r
20695             attr.$observe('b2bInputAllow', function (value) {\r
20696                 if (value) {\r
20697                     regexExpression = new RegExp(value);\r
20698                 }\r
20699             });\r
20700             var isValid = function(str) {\r
20701                 if (regexExpression !== null) {\r
20702                     return regexExpression.test(str);\r
20703                 }\r
20704                 return false;\r
20705             };\r
20706             elem.bind('keypress', function($event) {\r
20707                 var charcode = String.fromCharCode($event.which || $event.keyCode);\r
20708                 if (!isValid(charcode)) {\r
20709                     $event.preventDefault();\r
20710                     $event.stopPropagation();\r
20711                 }\r
20712             });\r
20713             elem.bind('input', function (evt) {\r
20714                 var inputString = ctrl.$viewValue;\r
20715                 if (isValid(inputString)) {\r
20716                     ctrl.$setViewValue(inputString);\r
20717                     ctrl.$render();\r
20718                     scope.$apply();\r
20719                 }\r
20720             });\r
20721         }\r
20722     };\r
20723 }])\r
20724 \r
20725 .directive('b2bInputDeny', [function() {\r
20726     return {\r
20727         restrict: 'A',\r
20728         require: 'ngModel',\r
20729         link: function (scope, elem, attr, ctrl) {\r
20730             var regexExpression = null;\r
20731             attr.$observe('b2bInputDeny', function (value) {\r
20732                 if (value) {\r
20733                     regexExpression = new RegExp(value, 'g');\r
20734                 }\r
20735             });\r
20736             elem.bind('input', function () {\r
20737                 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');\r
20738                 if (inputString !== ctrl.$viewValue) {\r
20739                     ctrl.$setViewValue(inputString);\r
20740                     ctrl.$render();\r
20741                     scope.$apply();\r
20742                 }\r
20743             });\r
20744         }\r
20745     };\r
20746 }])\r
20747 \r
20748 .directive('b2bDragonInput', [function() {\r
20749     return {\r
20750         restrict: 'A',\r
20751         require: 'ngModel',\r
20752         link: function (scope, elem, attr, ctrl) {\r
20753             elem.on('focus keyup', function(){\r
20754                 elem.triggerHandler('change');\r
20755             });\r
20756         }\r
20757     };\r
20758 }])\r
20759 \r
20760 .directive('b2bKey', ['b2bUtilitiesConfig', '$timeout', 'keymap', function (b2bUtilitiesConfig, $timeout, keymap) {\r
20761     return {\r
20762         restrict: 'EA',\r
20763         controller: ['$scope', '$element', '$attrs', function ($scope, $element,attr) {\r
20764             this.childElements = [];\r
20765             this.disableNodes = {};\r
20766             this.enableSearch = attr.enableSearch !== undefined ? true : b2bUtilitiesConfig.enableSearch;\r
20767             this.circularTraversal = attr.circularTraversal !== undefined ? true : b2bUtilitiesConfig.circularTraversal;\r
20768             this.counter = -1;\r
20769             if (this.enableSearch) {\r
20770                 this.searchKeys = [];\r
20771             }\r
20772             var searchString = '';\r
20773 \r
20774             var selfCtrl = this;\r
20775 \r
20776             this.childElementsList = [];\r
20777 \r
20778             this.b2bKeyID = "";\r
20779 \r
20780             if (angular.isDefined(attr.b2bKey)) {\r
20781                 this.b2bKeyID = attr.b2bKey;\r
20782             }\r
20783 \r
20784             this.calculateChildElementsList = function () {\r
20785                 return $element[0].querySelectorAll("[b2b-key-item='" + this.b2bKeyID + "']:not([disabled])");\r
20786             };\r
20787 \r
20788             this.resetChildElementsList = function () {\r
20789                 return $timeout(function () {\r
20790                     selfCtrl.childElementsList = selfCtrl.calculateChildElementsList();\r
20791                 });\r
20792             };\r
20793 \r
20794             this.resetChildElementsList();\r
20795 \r
20796             $scope.$on('b2b-key-reset-child-elements-list', function () {\r
20797                 selfCtrl.resetChildElementsList();\r
20798             });\r
20799 \r
20800 \r
20801             this.registerElement = function (childElement, searchKey) {\r
20802                 this.childElements.push(childElement);\r
20803                 if (this.enableSearch) {\r
20804                     this.searchKeys.push(searchKey);\r
20805                 }\r
20806                 var count = this.childElements.length - 1;\r
20807                 this.maxLength = count + 1;\r
20808                 return count;\r
20809             };\r
20810             this.toggleDisable = function (count, state) {\r
20811                 this.disableNodes[count] = state;\r
20812             };\r
20813             this.searchElement = function (searchExp) {\r
20814                 var regex = new RegExp("\\b" + searchExp, "gi");\r
20815                 var position = this.searchKeys.regexIndexOf(regex, this.counter + 1, true);\r
20816                 if (position > -1) {\r
20817                     this.counter = position;\r
20818                     this.moveFocus(this.counter);\r
20819                 }\r
20820             };\r
20821             this.startTimer = function (time) {\r
20822                 if (searchString === '') {\r
20823                     $timeout(function () {\r
20824                         searchString = '';\r
20825                     }, time);\r
20826                 }\r
20827             };\r
20828             this.resetCounter = function (count) {\r
20829                 this.counter = count;\r
20830             };\r
20831             this.moveNext = function (count) {\r
20832                 this.counter = (this.counter + count) < this.maxLength ? this.counter + count : (this.circularTraversal ? 0 : this.counter);\r
20833                 if (this.disableNodes[this.counter]) {\r
20834                     if ((this.counter + count) < this.maxLength) {\r
20835                         this.moveNext(count);\r
20836                     }\r
20837                 } else {\r
20838                     this.moveFocus(this.counter);\r
20839                 }\r
20840             };\r
20841             this.movePrev = function (count) {\r
20842                 this.counter = (this.counter - count) > -1 ? this.counter - count : (this.circularTraversal ? this.maxLength-1 : this.counter);\r
20843                 if (this.disableNodes[this.counter]) {\r
20844                     if ((this.counter - count) > -1) {\r
20845                         this.movePrev(count);\r
20846                     }\r
20847                 } else {\r
20848                     this.moveFocus(this.counter);\r
20849                 }\r
20850             };\r
20851             this.moveFocus = function (index) {\r
20852                 this.childElements[index][0].focus();\r
20853             };\r
20854 \r
20855             this.keyDownHandler = function (ev, count) {\r
20856                 if (angular.isDefined(count) && !isNaN(count) && count !== this.counter) {\r
20857                     this.resetCounter(count);\r
20858                 }\r
20859                 if (!ev.keyCode) {\r
20860                     if (ev.which) {\r
20861                         ev.keyCode = ev.which;\r
20862                     } else if (ev.charCode) {\r
20863                         ev.keyCode = ev.charCode;\r
20864                     }\r
20865                 }\r
20866                 if (ev.keyCode) {\r
20867                     if (this.prev && this.prev.indexOf(ev.keyCode.toString()) > -1) {\r
20868                         this.movePrev(1);\r
20869                         ev.preventDefault();\r
20870                         ev.stopPropagation();\r
20871                     } else if (this.next && this.next.indexOf(ev.keyCode.toString()) > -1) {\r
20872                         this.moveNext(1);\r
20873                         ev.preventDefault();\r
20874                         ev.stopPropagation();\r
20875                     } else if (this.up && this.up.indexOf(ev.keyCode.toString()) > -1) {\r
20876                         if (this.type === 'table') {\r
20877                             this.movePrev(this.columns);\r
20878                             ev.preventDefault();\r
20879                             ev.stopPropagation();\r
20880                         }\r
20881                     } else if (this.down && this.down.indexOf(ev.keyCode.toString()) > -1) {\r
20882                         if (this.type === 'table') {\r
20883                             this.moveNext(this.columns);\r
20884                             ev.preventDefault();\r
20885                             ev.stopPropagation();\r
20886                         }\r
20887                     } else if (ev.keyCode === keymap.KEY.HOME) {\r
20888                         var firstIndex = 0;\r
20889                         while (this.disableNodes[firstIndex] !== false) {\r
20890                             firstIndex++;\r
20891                         };\r
20892                         var count = this.counter - firstIndex;\r
20893                         this.movePrev(count);\r
20894                         ev.preventDefault();\r
20895                         ev.stopPropagation();\r
20896                     } else if (ev.keyCode === keymap.KEY.END) {\r
20897                         var lastIndex = this.childElements.length - 1;\r
20898                         while (this.disableNodes[lastIndex] !== false) {\r
20899                             lastIndex--;\r
20900                         };\r
20901                         var count = lastIndex - this.counter;\r
20902                         this.moveNext(count);\r
20903                         ev.preventDefault();\r
20904                         ev.stopPropagation();\r
20905                     } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {\r
20906                         if (this.enableSearch) {\r
20907                             this.startTimer(b2bUtilitiesConfig.searchTimer);\r
20908                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');\r
20909                             this.searchElement(searchString);\r
20910                             ev.preventDefault();\r
20911                             ev.stopPropagation();\r
20912                         }\r
20913                     }\r
20914                 }\r
20915             };\r
20916         }],\r
20917         link: function (scope, elem, attr, ctrl) {\r
20918             ctrl.prev = attr.prev ? attr.prev.split(',') : b2bUtilitiesConfig.prev.split(',');\r
20919             ctrl.next = attr.next ? attr.next.split(',') : b2bUtilitiesConfig.next.split(',');\r
20920             ctrl.type = attr.type ? attr.type : b2bUtilitiesConfig.type;\r
20921             if (ctrl.type === 'table') {\r
20922                 ctrl.up = attr.up ? attr.up.split(',') : b2bUtilitiesConfig.up.split(',');\r
20923                 ctrl.down = attr.down ? attr.down.split(',') : b2bUtilitiesConfig.down.split(',');\r
20924                 ctrl.columns = attr.columns ? parseInt(attr.columns, 10) : b2bUtilitiesConfig.columns;\r
20925             }\r
20926 \r
20927             elem.bind('keydown', function (ev) {\r
20928                 ctrl.keyDownHandler(ev);\r
20929             });\r
20930         }\r
20931     };\r
20932 }])\r
20933 \r
20934 .directive('b2bKeyItem', [function () {\r
20935     return {\r
20936         restrict: 'EA',\r
20937         link: function (scope, elem, attr, ctrl) {\r
20938             var parentCtrl = (elem.parent() && elem.parent().controller('b2bKey')) || undefined;\r
20939             if (angular.isDefined(parentCtrl)) {\r
20940                 var count = parentCtrl.registerElement(elem, attr.searchKey);\r
20941                 elem.bind('keydown', function (ev) {\r
20942                     parentCtrl.keyDownHandler(ev, count);\r
20943                 });\r
20944                 scope.$watch(attr.b2bKeyItem, function (value) {\r
20945                     value = value === undefined ? true : value;\r
20946                     parentCtrl.toggleDisable(count, !value); \r
20947                 });\r
20948                 scope.$on('$destroy', function () {\r
20949                     parentCtrl.toggleDisable(count, true);\r
20950                 });\r
20951             }\r
20952         }\r
20953     };\r
20954 }])\r
20955 \r
20956 .directive('b2bElementFocus', [function () {\r
20957     return {\r
20958         restrict: 'A',\r
20959         link: function (scope, elem, attr, ctrl) {\r
20960             scope.$watch(attr.b2bElementFocus, function (value) {\r
20961                 if (value === true) {\r
20962                     elem[0].focus();\r
20963                 }\r
20964             });\r
20965         }\r
20966     };\r
20967 }])\r
20968 \r
20969 \r
20970 .directive('b2bAppendElement', ['$compile', function ($compile) {\r
20971     return {\r
20972         restrict: 'A',\r
20973         link: function (scope, elem, attr, ctrl) {\r
20974             var parameters = attr.b2bAppendElement.split(':');\r
20975             if (parameters.length === 1) {\r
20976                 elem.append(scope.$eval(parameters[0]));\r
20977             } else if (parameters.length === 2) {\r
20978                 if (parameters[1] === 'compile') {\r
20979                     var element = angular.element('<span>' + scope.$eval(parameters[0]) + '</span>');\r
20980                     elem.append($compile(element)(scope));\r
20981                 }\r
20982             }\r
20983 \r
20984         }\r
20985     };\r
20986 }])\r
20987 \r
20988 .directive('b2bKeyItemRefreshInNgRepeat', [function () {\r
20989     return {\r
20990         restrict: 'EA',\r
20991         require: '^^b2bKey',\r
20992         link: function (scope, elem, attr, parentCtrl) {\r
20993             if (angular.isDefined(parentCtrl)) {\r
20994 \r
20995                 var attrToObserve = 'attrToObserve';\r
20996 \r
20997                 if (attr.b2bKeyItemRefreshInNgRepeat) {\r
20998                     attrToObserve = 'b2bKeyItemRefreshInNgRepeat';\r
20999                 }\r
21000 \r
21001                 attr.$observe(attrToObserve, function (newVal, oldVal) {\r
21002                     if (newVal && newVal !== oldVal) {\r
21003                         parentCtrl.resetChildElementsList();\r
21004                     }\r
21005                 });\r
21006             }\r
21007         }\r
21008     };\r
21009 }])\r
21010 \r
21011 .filter('b2bMultiSepartorHighlight', function($sce) {\r
21012         return function(text, searchText, searchSeperator) {\r
21013             var splitText = function(string) {\r
21014                 if(angular.isDefined(searchSeperator)){\r
21015                     if (string.indexOf(searchSeperator) > -1) {\r
21016                         return string.split(searchSeperator);\r
21017                     } else {\r
21018                         return string\r
21019                     }\r
21020                 }else{\r
21021                     return string;\r
21022                 }\r
21023             }\r
21024             if (text) {\r
21025                 var newText = splitText(text);\r
21026                 var newPhrase = splitText(searchText);\r
21027                 if (angular.isArray(newPhrase)) {\r
21028                     for (var i = 0; i < newText.length; i++) {\r
21029                         if (i <= 0) {\r
21030                             text = newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),\r
21031                                 '<span class="b2b-search-hightlight">$1</span>');\r
21032                         } else {\r
21033                             text = text + searchSeperator + ' ' + (newPhrase[i] ? newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),\r
21034                                 '<span class="b2b-search-hightlight">$1</span>') : newText[i]);\r
21035                         }\r
21036                     }\r
21037                 } else {\r
21038                     text = text.replace(new RegExp('(' + searchText + ')', 'gi'),\r
21039                         '<span class="b2b-search-hightlight">$1</span>');\r
21040                 }\r
21041             }\r
21042             return $sce.trustAsHtml(text)\r
21043         }\r
21044     })\r
21045     \r
21046     .factory('b2bUserAgent', [function() {\r
21047         var _isMobile = function() {\r
21048             return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\r
21049         };\r
21050         var _notMobile = function() {\r
21051             return !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\r
21052         };\r
21053         var _isIE = function() {\r
21054             return /msie|trident/i.test(navigator.userAgent);\r
21055         };\r
21056         var _isFF = function() {\r
21057             return /Firefox/.test(navigator.userAgent);\r
21058         };\r
21059         var _isChrome = function() {\r
21060             return /Google Inc/.test(navigator.vendor);\r
21061         };\r
21062         var _isSafari = function() {\r
21063             return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);\r
21064         };\r
21065 \r
21066         return {\r
21067             isMobile: _isMobile,\r
21068             notMobile: _notMobile,\r
21069             isIE: _isIE,\r
21070             isFF: _isFF,\r
21071             isChrome: _isChrome,\r
21072             isSafari: _isSafari\r
21073         };\r
21074     }])\r
21075     .run(['$document', 'b2bUserAgent', function($document, b2bUserAgent) {\r
21076         var html = $document.find('html').eq(0);\r
21077         if (b2bUserAgent.isIE()) {\r
21078             html.addClass('isIE');\r
21079         } else {\r
21080             html.removeClass('isIE');\r
21081         }\r
21082     }]);\r
21083     \r
21084 \r
21085 (function () {\r
21086     String.prototype.toSnakeCase = function () {\r
21087         return this.replace(/([A-Z])/g, function ($1) {\r
21088             return "-" + $1.toLowerCase();\r
21089         });\r
21090     };\r
21091     var concat = function (character, times) {\r
21092         character = character || '';\r
21093         times = (!isNaN(times) && times) || 0;\r
21094         var finalChar = '';\r
21095         for (var i = 0; i < times; i++) {\r
21096             finalChar += character;\r
21097         }\r
21098         return finalChar;\r
21099     };\r
21100 \r
21101     // direction: true for left and false for right\r
21102     var pad = function (actualString, width, character, direction) {\r
21103         actualString = actualString || '';\r
21104         width = (!isNaN(width) && width) || 0;\r
21105         character = character || '';\r
21106         if (width > actualString.length) {\r
21107             if (direction) {\r
21108                 return concat(character, (width - actualString.length)) + actualString;\r
21109             } else {\r
21110                 return actualString + concat(character, (width - actualString.length));\r
21111             }\r
21112         }\r
21113         return actualString;\r
21114     };\r
21115 \r
21116     String.prototype.lPad = function (width, character) {\r
21117         return pad(this, width, character, true);\r
21118     };\r
21119 \r
21120     String.prototype.rPad = function (width, character) {\r
21121         return pad(this, width, character, false);\r
21122     };\r
21123 \r
21124     if (!Array.prototype.indexOf) {\r
21125         Array.prototype.indexOf = function (val) {\r
21126             for (var index = 0; index < this.length; index++) {\r
21127                 if (this[index] === val) {\r
21128                     return index;\r
21129                 }\r
21130             }\r
21131             return -1;\r
21132         };\r
21133     }\r
21134 \r
21135     if (!Array.prototype.regexIndexOf) {\r
21136         Object.defineProperty(Array.prototype, 'regexIndexOf', {\r
21137             enumerable: false,\r
21138             value: function (regex, startIndex, loop) {\r
21139                 startIndex = startIndex && startIndex > -1 ? startIndex : 0;\r
21140                 for (var index = startIndex; index < this.length; index++) {\r
21141                     if (this[index].toString().match(regex)) {\r
21142                         return index;\r
21143                     }\r
21144                 }\r
21145                 if (loop) {\r
21146                     for (var index = 0; index < startIndex; index++) {\r
21147                         if (this[index].toString().match(regex)) {\r
21148                             return index;\r
21149                         }\r
21150                     }\r
21151                 }\r
21152                 return -1;\r
21153             }\r
21154         })\r
21155     }\r
21156 })();\r
21157 angular.module("b2bTemplate/audioPlayer/audioPlayer.html", []).run(["$templateCache", function($templateCache) {\r
21158   $templateCache.put("b2bTemplate/audioPlayer/audioPlayer.html",\r
21159     "<div class=\"b2b-audio\">\n" +\r
21160     "   <audio preload=\"auto\">\n" +\r
21161     "       <source ng-src=\"{{audio.mp3 | trustedAudioUrl}}\" type=\"audio/mp3\"></source>\n" +\r
21162     "       <i>Your browser does not support the audio element.</i>\n" +\r
21163     "    </audio>\n" +\r
21164     "\n" +\r
21165     "    <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
21166     "       <i class=\"icoControls-pointer\" ng-show='!isPlayInProgress'></i>\n" +\r
21167     "       <i class=\"icoControls-pause\" ng-show='isPlayInProgress'></i>\n" +\r
21168     "    </div>\n" +\r
21169     "\n" +\r
21170     "    <div class=\"seek-bar-container-wrapper\">\n" +\r
21171     "       <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
21172     "       <div class=\"timing-container\">\n" +\r
21173     "           <span class=\"timing-container-left\">{{timeFormatter(audio.currentTime)}}</span>\n" +\r
21174     "           <span class=\"timing-container-right\">{{timeFormatter(audio.duration)}}</span>\n" +\r
21175     "           <div class=\"timing-container-spacer\"></div>\n" +\r
21176     "       </div>\n" +\r
21177     "    </div>\n" +\r
21178     "       \n" +\r
21179     "    <b2b-flyout>\n" +\r
21180     "       <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
21181     "           <i class=\"icoControls-mutespeakers\" ng-show=\"audio.currentVolume === 0\"></i>\n" +\r
21182     "           <i class=\"icoControls-volumedown\" ng-show=\"audio.currentVolume > 0 && audio.currentVolume <= 50\"></i>\n" +\r
21183     "           <i class=\"icoControls-volumeup\" ng-show=\"audio.currentVolume > 50\"></i>\n" +\r
21184     "       </div> \n" +\r
21185     "       \n" +\r
21186     "       <b2b-flyout-content horizontal-placement=\"center\" flyout-style=\"width:70px; height:190px;\" vertical-placement=\"above\">\n" +\r
21187     "           <div class=\"b2b-audio-popover text-center\">\n" +\r
21188     "               <span>Max</span>\n" +\r
21189     "               <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
21190     "               <div class=\"min-label\">Min</div>\n" +\r
21191     "           </div>\n" +\r
21192     "       </b2b-flyout-content>\n" +\r
21193     "   </b2b-flyout>\n" +\r
21194     "</div>");\r
21195 }]);\r
21196 \r
21197 angular.module("b2bTemplate/audioRecorder/audioRecorder.html", []).run(["$templateCache", function($templateCache) {\r
21198   $templateCache.put("b2bTemplate/audioRecorder/audioRecorder.html",\r
21199     "<div class=\"b2b-audio-recorder row\">\n" +\r
21200     "   <div class=\"b2b-elapsed-time span11\">\n" +\r
21201     "       <div ng-if=\"isRecording\">\n" +\r
21202     "           <span style=\"padding-right: 25px;\">{{config.whileRecordingMessage}}</span>\n" +\r
21203     "           <span>{{timeFormatter(elapsedTime)}}</span>\n" +\r
21204     "       </div>\n" +\r
21205     "       <span ng-if=\"!isRecording\">{{config.startRecordingMessage}}</span>\n" +\r
21206     "   </div>      \n" +\r
21207     "   <div class=\"b2b-controls\" title=\"{{isRecording ? 'Stop' : 'REC'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"toggleRecording()\" role=\"button\">\n" +\r
21208     "           <i ng-if=\"isRecording\" class=\"icoControls-stop\" ></i>\n" +\r
21209     "           <i ng-if=\"!isRecording\" class=\"icoControls-record\"></i>\n" +\r
21210     "    </div>\n" +\r
21211     "</div>");\r
21212 }]);\r
21213 \r
21214 angular.module("b2bTemplate/backToTop/backToTop.html", []).run(["$templateCache", function($templateCache) {\r
21215   $templateCache.put("b2bTemplate/backToTop/backToTop.html",\r
21216     "<button class=\"btn-arrow b2b-backtotop-button\" type=\"button\" aria-label=\"Back to top\">\n" +\r
21217     "    <div class=\"btn-secondary b2b-top-btn\">\n" +\r
21218     "        <i class=\"icoControls-upPRIMARY\" role=\"img\"></i>\n" +\r
21219     "    </div>\n" +\r
21220     "</button>\n" +\r
21221     "");\r
21222 }]);\r
21223 \r
21224 angular.module("b2bTemplate/boardstrip/b2bAddBoard.html", []).run(["$templateCache", function($templateCache) {\r
21225   $templateCache.put("b2bTemplate/boardstrip/b2bAddBoard.html",\r
21226     "<div tabindex=\"0\" role=\"menuitem\" b2b-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +\r
21227     "    <div class=\"centered\"><i aria-hidden=\"true\" class=\"icoControls-add-maximize\"></i> Add board</div>\n" +\r
21228     "</div> ");\r
21229 }]);\r
21230 \r
21231 angular.module("b2bTemplate/boardstrip/b2bBoard.html", []).run(["$templateCache", function($templateCache) {\r
21232   $templateCache.put("b2bTemplate/boardstrip/b2bBoard.html",\r
21233     "<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
21234     "    <div ng-transclude></div>\n" +\r
21235     "    <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +\r
21236     "        <div class=\"board-caret-indicator\"></div>\n" +\r
21237     "        <div class=\"board-caret-arrow-up\"></div>\n" +\r
21238     "    </div>\n" +\r
21239     "</li>");\r
21240 }]);\r
21241 \r
21242 angular.module("b2bTemplate/boardstrip/b2bBoardstrip.html", []).run(["$templateCache", function($templateCache) {\r
21243   $templateCache.put("b2bTemplate/boardstrip/b2bBoardstrip.html",\r
21244     "<div class=\"b2b-boardstrip\">\n" +\r
21245     "   <div class=\"boardstrip-reel\" role=\"menu\">\n" +\r
21246     "       <div class=\"prev-items\">\n" +\r
21247     "           <!-- <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
21248     "           <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" ng-disabled=\"!isPrevBoard()\">\n" +\r
21249     "               <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-left\"></i>\n" +\r
21250     "               </div>\n" +\r
21251     "               <span class=\"offscreen-text\">Previous boards</span>\n" +\r
21252     "           </button>\n" +\r
21253     "       </div>\n" +\r
21254     "       <div b2b-add-board on-add-board=\"onAddBoard()\"></div>\n" +\r
21255     "       <div class=\"board-viewport\"><ul role=\"menu\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +\r
21256     "       <div class=\"next-items\">\n" +\r
21257     "           <!-- <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
21258     "           <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" ng-disabled=\"!isNextBoard()\">\n" +\r
21259     "               <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-right\"></i>\n" +\r
21260     "               </div>\n" +\r
21261     "               <span class=\"offscreen-text\">Next boards</span>\n" +\r
21262     "           </button>\n" +\r
21263     "       </div>\n" +\r
21264     "   </div>\n" +\r
21265     "</div>\n" +\r
21266     "");\r
21267 }]);\r
21268 \r
21269 angular.module("b2bTemplate/calendar/datepicker-popup.html", []).run(["$templateCache", function($templateCache) {\r
21270   $templateCache.put("b2bTemplate/calendar/datepicker-popup.html",\r
21271     "<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
21272     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +\r
21273     "        <div ng-repeat=\"header in headers\" class=\"text-left\" style=\"width: 100%;\" b2b-append-element=\"header\"></div>\n" +\r
21274     "        <table class=\"table-condensed\">\n" +\r
21275     "            <thead>\n" +\r
21276     "                <tr>\n" +\r
21277     "                    <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
21278     "                    <th id=\"month\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +\r
21279     "                    <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
21280     "                </tr>\n" +\r
21281     "                <tr ng-show=\"labels.length > 0\">\n" +\r
21282     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +\r
21283     "                </tr>\n" +\r
21284     "            </thead>\n" +\r
21285     "            <tbody>\n" +\r
21286     "                <tr ng-repeat=\"row in rows\">\n" +\r
21287     "                    <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
21288     "                        <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
21289     "                </tr>\n" +\r
21290     "            </tbody>\n" +\r
21291     "            <tfoot>\n" +\r
21292     "                <tr ng-repeat=\"footer in footers\">\n" +\r
21293     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"footer\"></th>\n" +\r
21294     "                </tr>\n" +\r
21295     "            </tfoot>\n" +\r
21296     "        </table>\n" +\r
21297     "    </div>\n" +\r
21298     "</div>");\r
21299 }]);\r
21300 \r
21301 angular.module("b2bTemplate/calendar/datepicker.html", []).run(["$templateCache", function($templateCache) {\r
21302   $templateCache.put("b2bTemplate/calendar/datepicker.html",\r
21303     "<div>\n" +\r
21304     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +\r
21305     "</div>");\r
21306 }]);\r
21307 \r
21308 angular.module("b2bTemplate/coachmark/coachmark.html", []).run(["$templateCache", function($templateCache) {\r
21309   $templateCache.put("b2bTemplate/coachmark/coachmark.html",\r
21310     "<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
21311     "   <i class=\"b2b-coachmark-caret\"></i>\n" +\r
21312     "   <div class=\"b2b-coachmark-header\">\n" +\r
21313     "       <div class=\"b2b-coachmark-countlabel\"><span ng-if=\"coachmarkIndex !== 0\">{{coachmarkIndex}} of {{(coachmarks.length-1)}}<span></div>\n" +\r
21314     "       <div class=\"corner-button\">\n" +\r
21315     "           <button type=\"button\" ng-focus=\"closeButtonFocus()\" class=\"close\" title=\"close\" aria-label=\"Close\" ng-click=\"closeCoachmark()\"></button>\n" +\r
21316     "       </div>\n" +\r
21317     "   </div>\n" +\r
21318     "   <div class=\"b2b-coachmark-content\">   \n" +\r
21319     "       <i class=\"icon-misc-dimmer\"></i>\n" +\r
21320     "       <div class=\"b2b-coachmark-content-header\"><span class=\"offscreen-text\">{{currentCoachmark.offscreenText}}</span>{{currentCoachmark.contentHeader}}</div>\n" +\r
21321     "       <div class=\"b2b-coachmark-description\">{{currentCoachmark.content}}</div>\n" +\r
21322     "       <div class=\"b2b-coachmark-btn-group\">\n" +\r
21323     "           <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
21324     "           <button class=\"btn btn-alt\" ng-if=\"currentCoachmark.buttonLabel !== '' && currentCoachmark.buttonLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.buttonLabel)\">{{currentCoachmark.buttonLabel}}</button>\n" +\r
21325     "       </div>  \n" +\r
21326     "   </div>  \n" +\r
21327     "</div>");\r
21328 }]);\r
21329 \r
21330 angular.module("b2bTemplate/dropdowns/b2bDropdownDesktop.html", []).run(["$templateCache", function($templateCache) {\r
21331   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownDesktop.html",\r
21332     "<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
21333     "    <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
21334     "    <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
21335     "    <div ng-class=\"{'selectWrapper': (isInputDropdown), 'moduleWrapper': (!isInputDropdown)}\">\n" +\r
21336     "        <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
21337     "        <ul class=\"module-optinalcta\" ng-if=\"toggleFlag && optionalCta\" tabindex=\"-1\" aria-hidden=\"false\">\n" +\r
21338     "            <li class=\"module-list-item\" tabindex=\"-1\" role=\"menuitem\" value=\"\" aria-label=\"Optinal CTA\" aria-selected=\"true\">\n" +\r
21339     "                <span class=\"module-data\" b2b-append-element=\"optionalCta\"></span>\n" +\r
21340     "            </li>\n" +\r
21341     "        </ul>\n" +\r
21342     "</div>\n" +\r
21343     "<i class=\"icon-primary-down\" aria-hidden=\"true\"></i>\n" +\r
21344     "</span>    ");\r
21345 }]);\r
21346 \r
21347 angular.module("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html", []).run(["$templateCache", function($templateCache) {\r
21348   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html",\r
21349     "<li b2b-dropdown-group-desktop class=\"optgroup-wrapper\">{{groupHeader}}\n" +\r
21350     "    <ul class=\"optgroup\" role=\"group\" aria-label=\"{{groupHeader}}\"></ul>\n" +\r
21351     "</li>");\r
21352 }]);\r
21353 \r
21354 angular.module("b2bTemplate/dropdowns/b2bDropdownListDesktop.html", []).run(["$templateCache", function($templateCache) {\r
21355   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownListDesktop.html",\r
21356     "<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
21357 }]);\r
21358 \r
21359 angular.module("b2bTemplate/fileUpload/fileUpload.html", []).run(["$templateCache", function($templateCache) {\r
21360   $templateCache.put("b2bTemplate/fileUpload/fileUpload.html",\r
21361     "<label class=\"b2b-file-container\">\n" +\r
21362     "   <span class=\"b2b-upload-link\" ng-transclude></span>\n" +\r
21363     "   <input type=\"file\" b2b-file-change>\n" +\r
21364     "</label>");\r
21365 }]);\r
21366 \r
21367 angular.module("b2bTemplate/flyout/flyout.html", []).run(["$templateCache", function($templateCache) {\r
21368   $templateCache.put("b2bTemplate/flyout/flyout.html",\r
21369     "<span class=\"b2b-flyout\"  b2b-flyout-trap-focus-inside>\n" +\r
21370     "    <span ng-transclude></span>\n" +\r
21371     "</span>");\r
21372 }]);\r
21373 \r
21374 angular.module("b2bTemplate/flyout/flyoutContent.html", []).run(["$templateCache", function($templateCache) {\r
21375   $templateCache.put("b2bTemplate/flyout/flyoutContent.html",\r
21376     "<div class=\"b2b-flyout-container\" aria-live=\"polite\" aria-atomic=\"false\" ng-class=\"{'b2b-flyout-left':horizontalPlacement==='left',\n" +\r
21377     "                'b2b-flyout-center':horizontalPlacement==='center', \n" +\r
21378     "                'b2b-flyout-right':horizontalPlacement==='right',\n" +\r
21379     "                'b2b-flyout-centerLeft':horizontalPlacement==='centerLeft',\n" +\r
21380     "                'b2b-flyout-centerRight':horizontalPlacement==='centerRight',  \n" +\r
21381     "                'b2b-flyout-above':verticalPlacement==='above', \n" +\r
21382     "                'b2b-flyout-below':verticalPlacement==='below',\n" +\r
21383     "                'open-flyout': openFlyout,\n" +\r
21384     "                'b2b-close-flyout': !openFlyout}\">\n" +\r
21385     "    <i class=\"b2b-flyout-caret\" ng-class=\"{'open-flyout': openFlyout, \n" +\r
21386     "                                   'b2b-flyout-caret-above':verticalPlacement==='above',\n" +\r
21387     "                                   'b2b-flyout-caret-below':verticalPlacement==='below'}\"></i>\n" +\r
21388     "    <span ng-transclude></span>\n" +\r
21389     "</div>");\r
21390 }]);\r
21391 \r
21392 angular.module("b2bTemplate/footer/footer_column_switch_tpl.html", []).run(["$templateCache", function($templateCache) {\r
21393   $templateCache.put("b2bTemplate/footer/footer_column_switch_tpl.html",\r
21394     "<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
21395     "    <h3 class=\"b2b-footer-header\">{{item.categoryName}}</h3>\n" +\r
21396     "    <ul>\n" +\r
21397     "        <li ng-repeat=\"i in item.values\">\n" +\r
21398     "            <a href=\"{{i.href}}\" title=\"{{item.categoryName}} - {{i.displayLink}}\">{{i.displayLink}}</a>  \n" +\r
21399     "        </li>\n" +\r
21400     "    </ul>\n" +\r
21401     "\n" +\r
21402     "</div>\n" +\r
21403     "\n" +\r
21404     "<div ng-transclude></div>\n" +\r
21405     "");\r
21406 }]);\r
21407 \r
21408 angular.module("b2bTemplate/horizontalTable/horizontalTable.html", []).run(["$templateCache", function($templateCache) {\r
21409   $templateCache.put("b2bTemplate/horizontalTable/horizontalTable.html",\r
21410     "<div class=\"b2b-horizontal-table\">\n" +\r
21411     "    <div class=\"b2b-horizontal-table-arrows row span12\">\n" +\r
21412     "       <div class=\"span4\">\n" +\r
21413     "           <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
21414     "        </div>\n" +\r
21415     "        \n" +\r
21416     "        <span class=\"span5 b2b-horizontal-table-column-info\" aria-live=\"polite\" tabindex=\"-1\">\n" +\r
21417     "           Displaying {{getColumnSet()[0]}} - {{getColumnSet()[1]}} of {{numOfCols}} (total) columns\n" +\r
21418     "        </span>\n" +\r
21419     "        \n" +\r
21420     "        <div class=\"span3\">\n" +\r
21421     "           <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
21422     "       </div>\n" +\r
21423     "    </div>\n" +\r
21424     "    <div class=\"b2b-horizontal-table-inner-container\">\n" +\r
21425     "        <span ng-transclude></span>\n" +\r
21426     "    </div>\n" +\r
21427     "</div>\n" +\r
21428     "\n" +\r
21429     "");\r
21430 }]);\r
21431 \r
21432 angular.module("b2bTemplate/hourPicker/b2bHourpicker.html", []).run(["$templateCache", function($templateCache) {\r
21433   $templateCache.put("b2bTemplate/hourPicker/b2bHourpicker.html",\r
21434     "<div class=\"hp-container\">\n" +\r
21435     "    <div class=\"hp-selected\">\n" +\r
21436     "        <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
21437     "    </div>\n" +\r
21438     "    <div b2b-hourpicker-panel></div>\n" +\r
21439     "</div>");\r
21440 }]);\r
21441 \r
21442 angular.module("b2bTemplate/hourPicker/b2bHourpickerPanel.html", []).run(["$templateCache", function($templateCache) {\r
21443   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerPanel.html",\r
21444     "<form name=\"{{'hourpickerForm' + $id}}\">\n" +\r
21445     "    <div class=\"hp-checkbox\" role=\"group\">\n" +\r
21446     "        <label class=\"checkbox\" for=\"checkbox_{{dayOption.title}}_{{$id}}\" aria-label=\"{{dayOption.title}}\" ng-repeat=\"dayOption in hourpicker.dayOptions\">\n" +\r
21447     "            <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
21448     "        </label>\n" +\r
21449     "    </div>\n" +\r
21450     "    <div class=\"row hp-dropdowns\">\n" +\r
21451     "        <div class=\"span4\">\n" +\r
21452     "            <label for=\"{{'hourpickerStartTime' + $id}}\">From</label>\n" +\r
21453     "            <select id=\"{{'hourpickerStartTime' + $parent.$id}}\" b2b-dropdown type=\"\" ng-model=\"hourpickerPanelValue.startTime\">\n" +\r
21454     "                <option b2b-dropdown-list value=\"\">From</option>\n" +\r
21455     "                <option b2b-dropdown-list option-repeat=\"startTimeOption in hourpicker.startTimeOptions\" value=\"{{startTimeOption}}\">{{startTimeOption}}</option>\n" +\r
21456     "            </select>\n" +\r
21457     "        </div>\n" +\r
21458     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +\r
21459     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_AM_{{$id}}\">\n" +\r
21460     "                <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
21461     "            </label>\n" +\r
21462     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_PM_{{$id}}\">\n" +\r
21463     "                <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
21464     "            </label>\n" +\r
21465     "        </div>\n" +\r
21466     "    </div>\n" +\r
21467     "    <div class=\"row hp-dropdowns\">\n" +\r
21468     "        <div class=\"span4\">\n" +\r
21469     "            <label for=\"{{'hourpickerEndTime' + $id}}\">To</label>\n" +\r
21470     "            <select id=\"{{'hourpickerEndTime' + $parent.$id}}\" b2b-dropdown ng-model=\"hourpickerPanelValue.endTime\">\n" +\r
21471     "                <option b2b-dropdown-list value=\"\">To</option>\n" +\r
21472     "                <option b2b-dropdown-list option-repeat=\"endTimeOption in hourpicker.endTimeOptions\" value=\"{{endTimeOption}}\">{{endTimeOption}}</option>\n" +\r
21473     "            </select>\n" +\r
21474     "        </div>\n" +\r
21475     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +\r
21476     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_AM_{{$id}}\">\n" +\r
21477     "                <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
21478     "            </label>\n" +\r
21479     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_PM_{{$id}}\">\n" +\r
21480     "                <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
21481     "            </label>\n" +\r
21482     "        </div>\n" +\r
21483     "    </div>\n" +\r
21484     "    <div class=\"row hp-buttons\">\n" +\r
21485     "        <div class=\"span12\">\n" +\r
21486     "            <div style=\"float:right\">\n" +\r
21487     "                <button class=\"btn btn-secondary btn-small\" ng-click=\"resetHourpickerPanelValue()\">Clear</button>\n" +\r
21488     "                <button class=\"btn btn-alt btn-small\" ng-disabled = \"disableAddBtn\" ng-click=\"updateHourpickerValue()\">{{hourpicker.editMode > -1 ? 'Update' : 'Add'}}</button>\n" +\r
21489     "            </div>\n" +\r
21490     "        </div>\n" +\r
21491     "    </div>\n" +\r
21492     "</form>");\r
21493 }]);\r
21494 \r
21495 angular.module("b2bTemplate/hourPicker/b2bHourpickerValue.html", []).run(["$templateCache", function($templateCache) {\r
21496   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerValue.html",\r
21497     "<div class=\"selected-days\">\n" +\r
21498     "    <span class=\"day\">{{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}</span>\n" +\r
21499     "    <span style=\"float:right\">\n" +\r
21500     "        <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
21501     "        <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
21502     "    </span>\n" +\r
21503     "    <div style=\"clear:both\"></div>\n" +\r
21504     "</div>");\r
21505 }]);\r
21506 \r
21507 angular.module("b2bTemplate/leftNavigation/leftNavigation.html", []).run(["$templateCache", function($templateCache) {\r
21508   $templateCache.put("b2bTemplate/leftNavigation/leftNavigation.html",\r
21509   "<div class=\"b2b-nav-menu\" ng-init=\"(showmenu = true)\" ng-class=\"{false: 'left-menu-collapsed'}[showmenu]\">\n" +\r
21510     "    <div class=\"b2b-subnav-container\">\n" +\r
21511     "        <ul class=\"b2b-subnav-content\">\n" +\r
21512     "                    <li>" +\r
21513     "                           <div ng-class=\"{true: 'leftmenu-arrow-expand', false: 'leftmenu-arrow-collapse'}[showmenu]\">"+        \r
21514     "                                   <a ng-click=\"toggleDrawer(showmenu);(showmenu = !showmenu) \" class=\"text-right\">" +\r
21515     "                                   <i ng-class=\"{true: 'icon-controls-left', false: 'icon-controls-right'}[showmenu]\">&nbsp;</i></a>" +\r
21516     "                           </div>"+                        \r
21517     "                   </li>" +\r
21518     "            <li ng-repeat=\"menu in menuData\" ui-sref=\"{{menu.state}}\">" +\r
21519     "                           <span ng-class=\"{true: 'menu-icon', false: 'menu-icon-collapse'}[showmenu]\"><span class=\"{{menu.imageSrc}}\"></span>&nbsp;&nbsp;</span>" +\r
21520     "                           <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
21521     "                                   {{menu.name}}" +\r
21522     "                                   <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
21523     "                           </a>\n" +\r
21524     "                           <div role=\"region\" aria-hidden=\"{{(isOpen($index))?false:true;}}\">\n" +\r
21525     "                   <ul ng-class=\"{expand: idx==$index}\">\n" +\r
21526     "                     <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
21527     "                           </ul>\n" +\r
21528     "                           </div>\n" +\r
21529     "            </li>\n" +\r
21530     "        </ul>\n" +\r
21531     "    </div>\n" +\r
21532     "</div>");\r
21533 }]);\r
21534 \r
21535 angular.module("b2bTemplate/listbox/listbox.html", []).run(["$templateCache", function($templateCache) {\r
21536   $templateCache.put("b2bTemplate/listbox/listbox.html",\r
21537     "<div class=\"b2b-list-box\" tabindex=\"0\" role=\"listbox\" ng-transclude>\n" +\r
21538     "</div>");\r
21539 }]);\r
21540 \r
21541 angular.module("b2bTemplate/modalsAndAlerts/b2b-backdrop.html", []).run(["$templateCache", function($templateCache) {\r
21542   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-backdrop.html",\r
21543     "<div class=\"b2b-modal-backdrop fade in hidden-by-modal\" aria-hidden=\"true\" tabindex=\"-1\"></div>");\r
21544 }]);\r
21545 \r
21546 angular.module("b2bTemplate/modalsAndAlerts/b2b-window.html", []).run(["$templateCache", function($templateCache) {\r
21547   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-window.html",\r
21548     "<div class=\"modalwrapper active {{windowClass}}\" ng-class=\"{'modal-landscape': isModalLandscape}\" role=\"{{isNotifDialog?'alertdialog':'dialog'}}\" tabindex=\"-1\" aria-labelledby=\"{{title}}\" aria-describedby=\"{{content}}\">\n" +\r
21549     "    <div class=\"modal fade in {{sizeClass}}\" ng-transclude></div>\n" +\r
21550     "</div>");\r
21551 }]);\r
21552 \r
21553 angular.module("b2bTemplate/monthSelector/monthSelector-popup.html", []).run(["$templateCache", function($templateCache) {\r
21554   $templateCache.put("b2bTemplate/monthSelector/monthSelector-popup.html",\r
21555     "<div id=\"monthselector{{$id}}\" class=\"datepicker dropdown-menu monthselector\" \n" +\r
21556     "     ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" \n" +\r
21557     "     ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" \n" +\r
21558     "     style=\"display: block;\" aria-hidden=\"false\" role=\"dialog presentation\" tabindex=\"-1\">\n" +\r
21559     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +\r
21560     "        <span class=\"offscreen-text\" aria-live=\"polite\" aria-atomic=\"true\">{{title}} displaying</span>\n" +\r
21561     "        <table class=\"table-condensed\" role=\"grid\">\n" +\r
21562     "            <thead>\n" +\r
21563     "                <tr ng-repeat=\"header in headers\">\n" +\r
21564     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"header\"></th>\n" +\r
21565     "                </tr>\n" +\r
21566     "                <tr>\n" +\r
21567     "                    <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
21568     "                    <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
21569     "                    <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
21570     "                </tr>\n" +\r
21571     "                <tr ng-show=\"labels.length > 0\">\n" +\r
21572     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +\r
21573     "                </tr>\n" +\r
21574     "            </thead>\n" +\r
21575     "            <tbody b2b-key type=\"table\" columns=\"4\" >\n" +\r
21576     "                <tr ng-repeat=\"row in rows\">\n" +\r
21577     "                    <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
21578     "                        <div aria-hidden=\"true\"  tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label | limitTo: 3}}</div>\n" +\r
21579     "                    </td>\n" +\r
21580     "                </tr>\n" +\r
21581     "            </tbody>\n" +\r
21582     "            <tfoot>\n" +\r
21583     "                <tr ng-repeat=\"footer in footers\">\n" +\r
21584     "                    <th colspan=\"7\" class=\"text-left\" b2b-append-element=\"footer\"></th>\n" +\r
21585     "                </tr>\n" +\r
21586     "            </tfoot>\n" +\r
21587     "        </table>\n" +\r
21588     "    </div>\n" +\r
21589     "</div>");\r
21590 }]);\r
21591 \r
21592 angular.module("b2bTemplate/monthSelector/monthSelector.html", []).run(["$templateCache", function($templateCache) {\r
21593   $templateCache.put("b2bTemplate/monthSelector/monthSelector.html",\r
21594     "<div>\n" +\r
21595     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +\r
21596     "</div>");\r
21597 }]);\r
21598 \r
21599 angular.module("b2bTemplate/monthSelector/monthSelectorLink.html", []).run(["$templateCache", function($templateCache) {\r
21600   $templateCache.put("b2bTemplate/monthSelector/monthSelectorLink.html",\r
21601     "<div>\n" +\r
21602     "    <span class=\"span12\" ng-transclude></span>\n" +\r
21603     "</div>");\r
21604 }]);\r
21605 \r
21606 angular.module("b2bTemplate/pagination/b2b-pagination.html", []).run(["$templateCache", function($templateCache) {\r
21607   $templateCache.put("b2bTemplate/pagination/b2b-pagination.html",\r
21608     "<div class=\"b2b-pager\">\n" +\r
21609     "    <div ng-if=\"notMobile && totalPages > 1\">\n" +\r
21610     "        <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
21611     "            <i class=\"icon-primary-left\"></i>\n" +\r
21612     "        </a>\n" +\r
21613     "        <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
21614     "            1<span class=\"offscreen-text\" ng-if=\"currentPage === 1\"> is selected</span>\n" +\r
21615     "        </a>\n" +\r
21616     "        <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
21617     "\n" +\r
21618     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage > 6\">...</span>\n" +\r
21619     "\n" +\r
21620     "        <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
21621     "\n" +\r
21622     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage <= totalPages - 5\">...</span>\n" +\r
21623     "\n" +\r
21624     "        <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
21625     "\n" +\r
21626     "        <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
21627     "\n" +\r
21628     "        <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
21629     "            <i class=\"icon-primary-right\"></i>\n" +\r
21630     "        </a>\n" +\r
21631     "        \n" +\r
21632     "        <span class=\"fieldLabel\" ng-show=\"totalPages > 10 && showInput === true\">    \n" +\r
21633     "            <label for=\"{{inputId}}\">Go to Page:</label>\n" +\r
21634     "            <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
21635     "            <button class=\"btn-arrow\" ng-click=\"gotoBtnClick()\" ng-disabled=\"$parent.gotoPage !== 0 || $parent.gotoPage !== undefined\" aria-label=\"Go to\">\n" +\r
21636     "                <div class=\"btn btn-small btn-secondary\">\n" +\r
21637     "                    <i class=\"icon-primary-right\"></i>\n" +\r
21638     "                </div>\n" +\r
21639     "            </button>\n" +\r
21640     "        </span>\n" +\r
21641     "    </div>\n" +\r
21642     "    <div ng-if=\"isMobile && totalPages > 1\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\" ng-class=\"isMobile ? 'b2b-mobile-view': '' \">\n" +\r
21643     "        <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
21644     "    </div>\n" +\r
21645     "</div>\n" +\r
21646     "");\r
21647 }]);\r
21648 \r
21649 angular.module("b2bTemplate/paneSelector/paneSelector.html", []).run(["$templateCache", function($templateCache) {\r
21650   $templateCache.put("b2bTemplate/paneSelector/paneSelector.html",\r
21651     "<div class=\"panes\" ng-transclude></div>");\r
21652 }]);\r
21653 \r
21654 angular.module("b2bTemplate/paneSelector/paneSelectorPane.html", []).run(["$templateCache", function($templateCache) {\r
21655   $templateCache.put("b2bTemplate/paneSelector/paneSelectorPane.html",\r
21656     "<div class=\"pane-block\" ng-transclude></div>");\r
21657 }]);\r
21658 \r
21659 angular.module("b2bTemplate/profileCard/profileCard-addUser.html", []).run(["$templateCache", function($templateCache) {\r
21660   $templateCache.put("b2bTemplate/profileCard/profileCard-addUser.html",\r
21661     "<div  class=\"span3 b2b-profile-card b2b-add-user\">\n" +\r
21662     "    <div class=\"atcenter\">\n" +\r
21663     "        <div class=\"circle\"><i class=\"icon-primary-add-maximize\"></i></div>\n" +\r
21664     "        <div>Create new user</div>\n" +\r
21665     "    </div>\n" +\r
21666     "</div>");\r
21667 }]);\r
21668 \r
21669 angular.module("b2bTemplate/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {\r
21670   $templateCache.put("b2bTemplate/profileCard/profileCard.html",\r
21671     "<div class=\"span3 b2b-profile-card\">\n" +\r
21672     "    <div class=\"top-block\">\n" +\r
21673     "       <div class=\"profile-image\">\n" +\r
21674     "            <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +\r
21675     "            <span ng-if=\"!image\" class=\"default-img\">{{initials}}</span>\n" +\r
21676     "\n" +\r
21677     "            <h4 class=\"name\">{{profile.name}}</h4>\n" +\r
21678     "\n" +\r
21679     "            <p class=\"status\">\n" +\r
21680     "                <span class=\"status-icon\" ng-class=\"{'status-green':colorIcon==='green','status-red':colorIcon==='red','status-blue':colorIcon==='blue','status-yellow':colorIcon==='yellow'}\">   \n" +\r
21681     "                </span>\n" +\r
21682     "                <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +\r
21683     "            </p>\n" +\r
21684     "        </div>\n" +\r
21685     "    </div>\n" +\r
21686     "    <div class=\"bottom-block\">\n" +\r
21687     "         <div class=\"profile-details\">\n" +\r
21688     "            <label>Username</label>\n" +\r
21689     "            <div ng-if=\"shouldClip(profile.userName)\" ng-mouseover=\"showUserNameTooltip = true;\" ng-mouseleave=\"showUserNameTooltip = false;\">\n" +\r
21690     "                <div ng-if=\"shouldClip(profile.userName)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showUserNameTooltip\">\n" +\r
21691     "                    {{profile.userName.slice(0, 25)+'...'}}\n" +\r
21692     "                    <div class=\"arrow\"></div>\n" +\r
21693     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21694     "                        <div class=\"tooltip-size-control\">\n" +\r
21695     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21696     "                                {{profile.userName}}\n" +\r
21697     "                            </div>\n" +\r
21698     "                        </div>\n" +\r
21699     "                    </div>\n" +\r
21700     "                </div>\n" +\r
21701     "            </div>\n" +\r
21702     "            <div ng-if=\"!shouldClip(profile.userName)\">\n" +\r
21703     "                {{profile.userName}}\n" +\r
21704     "            </div>\n" +\r
21705     "            <label>Email</label>\n" +\r
21706     "            <div ng-if=\"shouldClip(profile.email)\" ng-mouseover=\"showEmailTooltip = true;\" ng-mouseleave=\"showEmailTooltip = false;\">\n" +\r
21707     "                <div ng-if=\"shouldClip(profile.email)\" class=\"tooltip\" data-placement=\"bottom\" b2b-tooltip show-tooltip=\"showEmailTooltip\">\n" +\r
21708     "                    {{profile.email.slice(0, 25)+'...'}}\n" +\r
21709     "                    <div class=\"arrow\"></div>\n" +\r
21710     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21711     "                        <div class=\"tooltip-size-control\">\n" +\r
21712     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21713     "                                {{profile.email}}\n" +\r
21714     "                            </div>\n" +\r
21715     "                        </div>\n" +\r
21716     "                    </div>\n" +\r
21717     "                </div>\n" +\r
21718     "            </div>\n" +\r
21719     "            <div ng-if=\"!shouldClip(profile.email)\">\n" +\r
21720     "                {{profile.email}}\n" +\r
21721     "            </div>\n" +\r
21722     "            <label>Role</label>\n" +\r
21723     "            <div ng-if=\"shouldClip(profile.role)\" ng-mouseover=\"showRoleTooltip = true;\" ng-mouseleave=\"showRoleTooltip = false;\">\n" +\r
21724     "                <div ng-if=\"shouldClip(profile.role)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showRoleTooltip\">\n" +\r
21725     "                    {{profile.role.slice(0, 25)+'...'}}\n" +\r
21726     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21727     "                        <div class=\"tooltip-size-control\">\n" +\r
21728     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21729     "                                {{profile.role}}\n" +\r
21730     "                            </div>\n" +\r
21731     "                        </div>\n" +\r
21732     "                    </div>\n" +\r
21733     "                </div>\n" +\r
21734     "            </div>\n" +\r
21735     "            <div ng-if=\"!shouldClip(profile.role)\">\n" +\r
21736     "                {{profile.role}}\n" +\r
21737     "            </div>\n" +\r
21738     "            <label>Last login</label>\n" +\r
21739     "            <div ng-if=\"shouldClip(profile.lastLogin)\" ng-mouseover=\"showLastLoginTooltip = true;\" ng-mouseleave=\"showLastLoginTooltip = false;\">\n" +\r
21740     "                <div ng-if=\"shouldClip(profile.lastLogin)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showLastLoginTooltip\">\n" +\r
21741     "                    {{profile.lastLogin.slice(0, 25)+'...'}}\n" +\r
21742     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +\r
21743     "                        <div class=\"tooltip-size-control\">\n" +\r
21744     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +\r
21745     "                                {{profile.lastLogin}}\n" +\r
21746     "                            </div>\n" +\r
21747     "                        </div>\n" +\r
21748     "                    </div>\n" +\r
21749     "                </div>\n" +\r
21750     "            </div>\n" +\r
21751     "            <div ng-if=\"!shouldClip(profile.lastLogin)\">\n" +\r
21752     "                {{profile.lastLogin}}\n" +\r
21753     "            </div>\n" +\r
21754     "         </div>\n" +\r
21755     "    </div>\n" +\r
21756     "</div>");\r
21757 }]);\r
21758 \r
21759 angular.module("b2bTemplate/searchField/searchField.html", []).run(["$templateCache", function($templateCache) {\r
21760   $templateCache.put("b2bTemplate/searchField/searchField.html",\r
21761     "<div class=\"search-bar\">\n" +\r
21762     "    <div class='input-container' ng-blur=\"blurInput()\">\n" +\r
21763     "        <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
21764     "            <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
21765     "    </div>\n" +\r
21766     "    <div class=\"search-suggestion-wrapper\" ng-if=\"filterList.length >=0\" ng-show=\"showListFlag\">\n" +\r
21767     "        <ul class=\"search-suggestion-list\" role=\"listbox\">      \n" +\r
21768     "            <li class=\"no-result\" ng-if=\"filterList.length == 0 && configObj.display\">{{configObj.resultText}}</li>\n" +\r
21769     "            <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
21770     "                {{item.title}}     \n" +\r
21771     "            </li>\n" +\r
21772     "        </ul>\n" +\r
21773     "    </div>\n" +\r
21774     "</div>");\r
21775 }]);\r
21776 \r
21777 angular.module("b2bTemplate/seekBar/seekBar.html", []).run(["$templateCache", function($templateCache) {\r
21778   $templateCache.put("b2bTemplate/seekBar/seekBar.html",\r
21779     "<div class=\"b2b-seek-bar-container\" ng-class=\"{vertical:verticalSeekBar}\">\n" +\r
21780     "    <div class=\"b2b-seek-bar-track-container\">\n" +\r
21781     "        <div class=\"b2b-seek-bar-track\"></div>\n" +\r
21782     "        <div class=\"b2b-seek-bar-track-fill\"></div>\n" +\r
21783     "    </div>\n" +\r
21784     "    <div class=\"b2b-seek-bar-knob-container\" role=\"menu\"  >\n" +\r
21785     "        <div class=\"b2b-seek-bar-knob\" tabindex=\"0\" role=\"menuitem\"></div>\n" +\r
21786     "    </div>\n" +\r
21787     "</div>");\r
21788 }]);\r
21789 \r
21790 angular.module("b2bTemplate/slider/slider.html", []).run(["$templateCache", function($templateCache) {\r
21791   $templateCache.put("b2bTemplate/slider/slider.html",\r
21792     "<div class=\"b2b-slider-container\" ng-class=\"{'vertical':verticalSlider}\">\n" +\r
21793     "    <div class=\"slider-track-container\">\n" +\r
21794     "        <div class=\"slider-track\"></div>\n" +\r
21795     "        <div class=\"slider-track-fill\" ng-style=\"{backgroundColor:trackFillColor}\"></div>\n" +\r
21796     "    </div>\n" +\r
21797     "    <div class=\"slider-knob-container\" ng-class=\"{'slider-knob-hidden':hideKnob}\">\n" +\r
21798     "        <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
21799     "    </div>\n" +\r
21800     "</div>");\r
21801 }]);\r
21802 \r
21803 angular.module("b2bTemplate/spinButton/spinButton.html", []).run(["$templateCache", function($templateCache) {\r
21804   $templateCache.put("b2bTemplate/spinButton/spinButton.html",\r
21805     "<div class=\"btn-group btn-spinbutton-toggle\" ng-class=\"{'disabled': disabledFlag}\">\n" +\r
21806     "    <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
21807     "    <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
21808     "    <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
21809     "</div>");\r
21810 }]);\r
21811 \r
21812 angular.module("b2bTemplate/statusTracker/statusTracker.html", []).run(["$templateCache", function($templateCache) {\r
21813   $templateCache.put("b2bTemplate/statusTracker/statusTracker.html",\r
21814     "<div class=\"b2b-status-tracker row\">\n" +\r
21815     "   <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
21816     "       <div class=\"btn btn-small btn-secondary\">\n" +\r
21817     "           <i class=\"icon-primary-left\"></i>\n" +\r
21818     "       </div>\n" +\r
21819     "   </button>\n" +\r
21820     "   <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
21821     "       <p class=\"b2b-status-tracker-heading\">{{status.heading}}</p>\n" +\r
21822     "       <div class=\"progress\">\n" +\r
21823     "           <div class=\"progress-bar\">\n" +\r
21824     "               <span class=\"hidden-spoken\">\n" +\r
21825     "                   {{status.complete ? 'Complete' : 'Incomplete'}}\n" +\r
21826     "               </span>\n" +\r
21827     "           </div>\n" +\r
21828     "       </div>\n" +\r
21829     "       <div class=\"b2b-status-tracker-estimate\">\n" +\r
21830     "           <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
21831     "           &nbsp;\n" +\r
21832     "       </div>\n" +\r
21833     "       \n" +\r
21834     "       <div class=\"b2b-status-tracker-description\">\n" +\r
21835     "           {{status.description}}\n" +\r
21836     "       </div>\n" +\r
21837     "   </div>\n" +\r
21838     "   <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
21839     "       <div class=\"btn btn-small btn-secondary\">\n" +\r
21840     "           <i class=\"icon-primary-right\"></i>\n" +\r
21841     "       </div>\n" +\r
21842     "   </button>\n" +\r
21843     "</div>");\r
21844 }]);\r
21845 \r
21846 angular.module("b2bTemplate/stepTracker/stepTracker.html", []).run(["$templateCache", function($templateCache) {\r
21847   $templateCache.put("b2bTemplate/stepTracker/stepTracker.html",\r
21848     "<div class=\"b2b-step-tracker\">\n" +\r
21849     "    <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
21850     "       <div class=\"btn btn-left btn-small btn-secondary\"><i class=\"icon-primary-left\"></i></div>\n" +\r
21851     "   </button>\n" +\r
21852     "    <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
21853     "       <div class=\"btn btn-small btn-right btn-secondary\"><i class=\"icon-primary-right\"></i></div>\n" +\r
21854     "   </button>\n" +\r
21855     "    <ul class=\"b2b-steps\">\n" +\r
21856     "        <li ng-class=\"{'b2b-step-done':$index < currentIndex - 1 ,'b2b-step-on':$index == currentIndex - 1}\" \n" +\r
21857     "            ng-repeat=\"stepsItem in stepsItemsObject\" ng-show=\"isInViewport($index)\">\n" +\r
21858     "           <p class=\"b2b-step-text\" data-sm-text=\"{{stepsItem.dataMobile}}\" data-large-text=\"{{stepsItem.dataDesktop}}\">{{stepsItem.text}}</p>\n" +\r
21859     "            <span class=\"hidden-spoken\">\n" +\r
21860     "                {{($index < currentIndex - 1)? 'Complete. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +\r
21861     "                {{($index == currentIndex - 1)? 'In Progress. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +\r
21862     "                {{($index > currentIndex - 1)? 'Incomplete. '+stepsItem.text+' '+stepsItem.dataMobile:''}}\n" +\r
21863     "            </span>\n" +\r
21864     "        </li>\n" +\r
21865     "    </ul>\n" +\r
21866     "</div>");\r
21867 }]);\r
21868 \r
21869 angular.module("b2bTemplate/switches/switches-spanish.html", []).run(["$templateCache", function($templateCache) {\r
21870   $templateCache.put("b2bTemplate/switches/switches-spanish.html",\r
21871     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +\r
21872     "    <span class=\"btn-slider-on\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"activo\">activo</i></span>\n" +\r
21873     "    <span class=\"switch-handle\"></span>\n" +\r
21874     "    <span class=\"btn-slider-off\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"inactivo\">inactivo</i></span>\n" +\r
21875     "</div>");\r
21876 }]);\r
21877 \r
21878 angular.module("b2bTemplate/switches/switches.html", []).run(["$templateCache", function($templateCache) {\r
21879   $templateCache.put("b2bTemplate/switches/switches.html",\r
21880     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +\r
21881     "    <span class=\"btn-slider-on\">On</span>\n" +\r
21882     "    <span class=\"switch-handle\"></span>\n" +\r
21883     "    <span class=\"btn-slider-off\">Off</span>\n" +\r
21884     "</div>");\r
21885 }]);\r
21886 \r
21887 angular.module("b2bTemplate/tableMessages/tableMessage.html", []).run(["$templateCache", function($templateCache) {\r
21888   $templateCache.put("b2bTemplate/tableMessages/tableMessage.html",\r
21889     "<div class=\"b2b-table-message\">\n" +\r
21890     "    <div class=\"b2b-message\" ng-if=\"msgType === 'noMatchingResults'\">\n" +\r
21891     "        <div class=\"b2b-magnify-glass\"></div>\n" +\r
21892     "        <div>\n" +\r
21893     "            <div ng-transclude></div>\n" +\r
21894     "        </div>\n" +\r
21895     "    </div>\n" +\r
21896     "    <div class=\"b2b-message\" ng-if=\"msgType == 'infoCouldNotLoad'\">\n" +\r
21897     "        <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
21898     "        <div>Oops!</div>\n" +\r
21899     "        <div>The information could not load at this time.</div>\n" +\r
21900     "        <div>Please <a href=\"javascript:void(0)\" title=\"Refresh the page\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +\r
21901     "        </div>\n" +\r
21902     "    </div>\n" +\r
21903     "    <div class=\"b2b-message\" ng-if=\"msgType == 'magnifySearch'\">\n" +\r
21904     "        <div class=\"b2b-magnify-glass\"></div>\n" +\r
21905     "        <div>\n" +\r
21906     "            <p class=\"b2b-message-title\">Please input values to\n" +\r
21907     "                <br/> begin your search.</p>\n" +\r
21908     "        </div>\n" +\r
21909     "    </div>\n" +\r
21910     "    <div class=\"b2b-message\" ng-if=\"msgType === 'loadingTable'\">\n" +\r
21911     "        <div class=\"icon-primary-spinner-ddh b2b-loading-dots\"></div>\n" +\r
21912     "        <div ng-transclude></div>\n" +\r
21913     "    </div>\n" +\r
21914     "</div>\n" +\r
21915     "");\r
21916 }]);\r
21917 \r
21918 angular.module("b2bTemplate/tableScrollbar/tableScrollbar.html", []).run(["$templateCache", function($templateCache) {\r
21919   $templateCache.put("b2bTemplate/tableScrollbar/tableScrollbar.html",\r
21920     "<div class=\"b2b-table-scrollbar\">\n" +\r
21921     "    <div class=\"b2b-scrollbar-arrows\">\n" +\r
21922     "        <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
21923     "        <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
21924     "    </div>\n" +\r
21925     "    <div class=\"b2b-table-inner-container\">\n" +\r
21926     "        <span ng-transclude></span>\n" +\r
21927     "    </div>\n" +\r
21928     "</div>");\r
21929 }]);\r
21930 \r
21931 angular.module("b2bTemplate/tables/b2bTable.html", []).run(["$templateCache", function($templateCache) {\r
21932   $templateCache.put("b2bTemplate/tables/b2bTable.html",\r
21933     "<table ng-class=\"{'striped': responsive, 'complex-table': responsive && active}\" ng-transclude></table>");\r
21934 }]);\r
21935 \r
21936 angular.module("b2bTemplate/tables/b2bTableBody.html", []).run(["$templateCache", function($templateCache) {\r
21937   $templateCache.put("b2bTemplate/tables/b2bTableBody.html",\r
21938     "<td ng-hide=\"isHidden()\" ng-transclude></td>");\r
21939 }]);\r
21940 \r
21941 angular.module("b2bTemplate/tables/b2bTableHeaderSortable.html", []).run(["$templateCache", function($templateCache) {\r
21942   $templateCache.put("b2bTemplate/tables/b2bTableHeaderSortable.html",\r
21943     "<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
21944     "    <span ng-transclude></span>\n" +\r
21945     "    <i ng-class=\"{'icon-primary-arrows-sort-arrow active': sortPattern === 'ascending', 'icon-primary-arrows-sort-arrow active down': sortPattern === 'descending'}\"></i>\n" +\r
21946     "</th>");\r
21947 }]);\r
21948 \r
21949 angular.module("b2bTemplate/tables/b2bTableHeaderUnsortable.html", []).run(["$templateCache", function($templateCache) {\r
21950   $templateCache.put("b2bTemplate/tables/b2bTableHeaderUnsortable.html",\r
21951     "<th scope=\"col\" ng-hide=\"isHidden()\" ng-transclude></th>");\r
21952 }]);\r
21953 \r
21954 angular.module("b2bTemplate/tabs/b2bTab.html", []).run(["$templateCache", function($templateCache) {\r
21955   $templateCache.put("b2bTemplate/tabs/b2bTab.html",\r
21956     "<li role=\"tab\" aria-selected=\"{{isTabActive()}}\" aria-controls=\"{{tabPanelId}}\" class=\"tab\" \n" +\r
21957     "    ng-class=\"{'active': isTabActive()}\" ng-click=\"clickTab()\" ng-hide=\"tabItem.disabled\">\n" +\r
21958     "    <a href=\"javascript:void(0)\"  tabindex=\"{{(isTabActive() && tabItem.disabled)?-1:0}}\"\n" +\r
21959     "       ng-disabled=\"tabItem.disabled\" aria-expanded=\"{{(isTabActive() && !tabItem.disabled)}}\" \n" +\r
21960     "       b2b-accessibility-click=\"13,32\" ng-transclude></a>\n" +\r
21961     "    <span class=\"hidden-spoken\" ng-if=\"isTabActive()\">Active tab</span>\n" +\r
21962     "</li>");\r
21963 }]);\r
21964 \r
21965 angular.module("b2bTemplate/tabs/b2bTabset.html", []).run(["$templateCache", function($templateCache) {\r
21966   $templateCache.put("b2bTemplate/tabs/b2bTabset.html",\r
21967     "<ul class=\"tabs promo-tabs\" role=\"tablist\" ng-transclude></ul>");\r
21968 }]);\r
21969 \r
21970 angular.module("b2bTemplate/treeNav/groupedTree.html", []).run(["$templateCache", function($templateCache) {\r
21971   $templateCache.put("b2bTemplate/treeNav/groupedTree.html",\r
21972     "<ul role=\"group\">\n" +\r
21973     "    <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
21974     "        <ul role=\"group\">\n" +\r
21975     "            <b2b-member ng-repeat='member in value.childArray' member='member' time-delay='{{timeDelay}}' group-it='groupIt'></b2b-member>\n" +\r
21976     "        </ul>\n" +\r
21977     "    </li>\n" +\r
21978     "</ul>");\r
21979 }]);\r
21980 \r
21981 angular.module("b2bTemplate/treeNav/treeMember.html", []).run(["$templateCache", function($templateCache) {\r
21982   $templateCache.put("b2bTemplate/treeNav/treeMember.html",\r
21983     "<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
21984     "    <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
21985     "        <span class=\"{{!member.child?'end':''}} b2b-tree-node-icon\">\n" +\r
21986     "            <i class=\"b2b-tree-expandCollapse-icon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +\r
21987     "        </span>\n" +\r
21988     "         <div id=\"description_{{$id}}\" class=\"offscreen-text\">\n" +\r
21989     "           {{member.descriptionText}}\n" +\r
21990     "        </div>\n" +\r
21991     "        <div class=\"b2b-tree-tooltip\" ng-if=\"member.showTooltip\">\n" +\r
21992     "           <span class=\"b2b-tree-arrow-left\"></span>\n" +\r
21993     "           <div class=\"b2b-tree-tooltip-content\">\n" +\r
21994     "               {{member.tooltipContent}}\n" +\r
21995     "           </div>  \n" +\r
21996     "        </div>\n" +\r
21997     "    </a>\n" +\r
21998     "</li>");\r
21999 }]);\r
22000 \r
22001 angular.module("b2bTemplate/treeNav/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {\r
22002   $templateCache.put("b2bTemplate/treeNav/ungroupedTree.html",\r
22003     "<ul role=\"{{setRole}}\"><b2b-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-member></ul>");\r
22004 }]);\r
22005 \r
22006 angular.module("b2bTemplate/treeNodeCheckbox/groupedTree.html", []).run(["$templateCache", function($templateCache) {\r
22007   $templateCache.put("b2bTemplate/treeNodeCheckbox/groupedTree.html",\r
22008     "<ul role=\"group\">\n" +\r
22009     "    <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
22010     "        <span class=\"ng-hide\">\n" +\r
22011     "            <label class=\"checkbox\">\n" +\r
22012     "                <input type=\"checkbox\" tabindex=\"-1\" class=\"treeCheckBox grpTreeCheckbox\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{(key)?key:''}}</span>\n" +\r
22013     "            </label>\n" +\r
22014     "        </span>\n" +\r
22015     "        <span>\n" +\r
22016     "            {{(key)?key:''}}    \n" +\r
22017     "        </span>\n" +\r
22018     "        <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
22019     "        <ul role=\"group\">\n" +\r
22020     "            <b2b-tree-member ng-repeat='member in value.childArray' member='member' group-it='groupIt'></b2b-tree-member>\n" +\r
22021     "        </ul>\n" +\r
22022     "    </li>\n" +\r
22023     "</ul>");\r
22024 }]);\r
22025 \r
22026 angular.module("b2bTemplate/treeNodeCheckbox/treeMember.html", []).run(["$templateCache", function($templateCache) {\r
22027   $templateCache.put("b2bTemplate/treeNodeCheckbox/treeMember.html",\r
22028     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.name}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-node-link>\n" +\r
22029     "    <a tabindex=\"-1\" title=\"{{member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active}\">\n" +\r
22030     "       <span ng-show=\"member.displayCheckbox\">\n" +\r
22031     "               <label class=\"checkbox\">\n" +\r
22032     "                <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
22033     "            </label>\n" +\r
22034     "        </span>\n" +\r
22035     "       <span ng-show=\"!member.displayCheckbox\">\n" +\r
22036     "           {{member.name}} \n" +\r
22037     "       </span>\n" +\r
22038     "        <span class=\"nodeIcon {{!member.child?'end':''}}\">\n" +\r
22039     "            <i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +\r
22040     "        </span>\n" +\r
22041     "    </a>\n" +\r
22042     "</li>");\r
22043 }]);\r
22044 \r
22045 angular.module("b2bTemplate/treeNodeCheckbox/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {\r
22046   $templateCache.put("b2bTemplate/treeNodeCheckbox/ungroupedTree.html",\r
22047     "<ul role=\"{{setRole}}\"><b2b-tree-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-tree-member></ul>");\r
22048 }]);\r