afa17ee97a8df1a49a8b5a17ba2f4033a8e20f6a
[portal.git] / ecomp-portal-FE-common / client / bower_components_external / b2b / js / b2b-angular / b2b-library.min.js
1 /*! b2b-angular-library - v1.0.5 - Last updated: 2017-05-24. Copyright (c) 2016 AT&T Services, Inc. */ 
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.bootstrapGridTemplate','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.headingsAndCopy','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.separators','b2b.att.slider','b2b.att.spinButton','b2b.att.staticRouteTemplate','b2b.att.statusTracker','b2b.att.stepTracker','b2b.att.switches','b2b.att.tableDragAndDrop','b2b.att.tableMessages','b2b.att.tables','b2b.att.tableScrollbar','b2b.att.tabs','b2b.att.tagBadges','b2b.att.textArea','b2b.att.timeInputField','b2b.att.tooltipsForForms','b2b.att.treeNav','b2b.att.treeNodeCheckbox','b2b.att.utilities']);/**
3  * @ngdoc directive
4  * @name Template.att:Address Input
5  *
6  * @description
7  *  <file src="src/addressInputTemplate/docs/readme.md" />
8  *
9  * @usage
10
11  *
12  * @example
13  *  <section id="code">   
14  <example module="b2b.att">
15  <file src="src/addressInputTemplate/docs/demo.html" />
16  <file src="src/addressInputTemplate/docs/demo.js" />
17  </example>
18  </section>
19  *
20  */
21 angular.module('b2b.att.addressInputTemplate', ['ngMessages']);
22 /**
23  * @ngdoc directive
24  * @name Buttons, links & UI controls.att:arrows
25  *
26  * @description
27  *  <file src="src/arrows/docs/readme.md" />
28  *
29  * @usage
30  *   Please refer demo.html tab in Example section below.
31  *
32  * @example
33  *  <section id="code">
34         <example module="b2b.att">
35             <file src="src/arrows/docs/demo.html" />
36             <file src="src/arrows/docs/demo.js" />
37        </example>
38     </section>
39  *
40  */
41 angular.module('b2b.att.arrows', []);
42 /**
43  * @ngdoc directive
44  * @name Videos, audio & animation.att:Audio Player
45  * @scope
46  * @param {string} audioSrcUrl - MP3 audio source URL or Blob URL
47  * @description
48  *  <file src="src/audioPlayer/docs/readme.md" />
49  *
50  * @usage
51  * 
52  <div b2b-audio audio-src-url='audioSrcUrl'></div>
53  *
54  * @example
55  *  <section id="code">
56         <example module="b2b.att">
57             <file src="src/audioPlayer/docs/demo.html" />
58             <file src="src/audioPlayer/docs/demo.js" />
59        </example>
60     </section>
61  *
62  */
63  
64 angular.module('b2b.att.audioPlayer', ['b2b.att.utilities', 'b2b.att.seekBar'])
65         .constant('AudioPlayerConfig', {
66                 'defaultVolume': 50,
67                 'timeShiftInSeconds': 5
68         })
69         .filter('trustedAudioUrl', ['$sce', function ($sce) {
70                 return function (audioFileFullPath) {
71                         return audioFileFullPath ? $sce.trustAsResourceUrl(audioFileFullPath) : 'undefined';
72                 };
73         }])
74         .directive('b2bAudio', ['$log', '$timeout', 'AudioPlayerConfig', '$compile', 'events', function ($log, $timeout, AudioPlayerConfig, $compile, events) {
75                 return {
76                         restrict: 'EA',
77                         replace: true,
78                         scope: {
79                                 audioSrcUrl: '='
80                         },
81                         templateUrl: 'b2bTemplate/audioPlayer/audioPlayer.html',
82                         controller: function ($scope) {
83
84                                 $scope.audio = {};
85
86                                 if (!angular.isDefined($scope.audioSrcUrl)) {
87                                         $log.warn('b2b-audio : audio-src-url undefined');
88                                         $scope.audioSrcUrl = undefined;
89                                         $scope.audio.mp3 = undefined;
90                                 }
91
92                         },
93                         link: function (scope, element) {
94                                 var audioElement = angular.element(element[0].querySelector('audio'))[0];
95                                 scope.audio.audioElement = audioElement;
96                                 
97                                 function setAttributes(element, attributes) {
98                                         Object.keys(attributes).forEach(function (name) {
99                                                 element.setAttribute(name, attributes[name]);
100                                         });
101                                 }
102
103                                 $timeout(function () {
104                                         // TODO: Replace with DDA Tooltip
105                                         var seekBarKnob = element[0].querySelector('.b2b-seek-bar-knob');
106                                         var tooltipObject = {
107                                                 'tooltip': '{{timeFormatter(audio.currentTime)}}',
108                                                 'tooltip-placement': 'above',
109                                                 'tooltip-style': 'blue',
110                                                 'tooltip-trigger': 'mousedown',
111                                                 'tooltip-append-to-body': 'false',
112                                                 'tooltip-offset': '-10',
113                                                 'refer-by': 'seek-bar-tooltip'
114                                         };
115                                         setAttributes(seekBarKnob, tooltipObject);
116                                         $compile(seekBarKnob)(scope);
117                                 });
118
119                                 if (angular.isDefined(scope.audioSrcUrl)) {
120                                         scope.audio.mp3 = scope.audioSrcUrl;
121                                 }
122
123                                 scope.audio.currentTime = 0;
124                                 scope.audio.currentVolume = AudioPlayerConfig.defaultVolume;
125                                 scope.audio.timeShiftInSeconds = AudioPlayerConfig.timeShiftInSeconds;
126                                 scope.isPlayInProgress = false;
127                                 scope.isReady = false;
128                                 scope.isAudioDragging = false;
129
130                                 $timeout(function () {
131                                         audioElement.load();
132                                         audioElement.volume = scope.audio.currentVolume / 100;
133                                 });
134
135                                 scope.$watch('audioSrcUrl', function (newVal, oldVal) {
136                                         if (newVal !== oldVal) {
137                                                 if (!newVal) {
138                                                         $log.warn('b2b-audio : audio-src-url undefined. Please provide a valid URL');
139                                                 }
140                                                 
141                                                 scope.audio.mp3 = newVal;
142                                                 $timeout(function () {
143                                                         audioElement.load();
144                                                 });
145                                         }
146                                 });
147
148                                 scope.playAudio = function () {
149                                         if (scope.isReady) {
150                                                 audioElement.play();
151                                         }
152                                 };
153
154                                 audioElement.onplay = function () {
155                                         scope.isPlayInProgress = true;
156                                         scope.$digest();
157                                 };
158
159                                 scope.pauseAudio = function () {
160                                         audioElement.pause();
161                                 };
162
163                                 audioElement.onpause = function () {
164                                         scope.isPlayInProgress = false;
165                                         scope.$digest();
166                                 };
167
168                                 scope.toggleAudio = function () {
169                                         if (audioElement.paused) {
170                                                 scope.playAudio();
171                                         } else {
172                                                 scope.pauseAudio();
173                                         }
174                                 };
175
176                                 scope.volumeUp = function (delta) {
177                                         if (!delta) {
178                                                 delta = 0.1;
179                                         } else {
180                                                 delta = delta / 100;
181                                         }
182                                         audioElement.muted = false;
183                                         if (audioElement.volume < 1) {
184                                                 audioElement.volume = Math.min((Math.round((audioElement.volume + delta) * 100) / 100), 1);
185                                         }
186                                         scope.audio.currentVolume = audioElement.volume * 100;
187                                         return audioElement.volume;
188                                 };
189
190                                 scope.volumeDown = function (delta) {
191                                         if (!delta) {
192                                                 delta = 0.1;
193                                         } else {
194                                                 delta = delta / 100;
195                                         }
196                                         audioElement.muted = false;
197                                         if (audioElement.volume > 0) {
198                                                 audioElement.volume = Math.max((Math.round((audioElement.volume - delta) * 100) / 100), 0);
199                                         }
200                                         scope.audio.currentVolume = audioElement.volume * 100;
201                                         return audioElement.volume;
202                                 };
203
204                                 var volumeHandler = function (e) {
205                                         events.preventDefault(e);
206                                         if ((e.wheelDelta && e.wheelDelta > 0) || (e.detail && e.detail < 0)) {
207                                                 scope.volumeUp();
208                                         } else {
209                                                 scope.volumeDown();
210                                         }
211                                         scope.$digest();
212                                 };
213
214                                 
215
216                                 scope.$watch('audio.currentVolume', function (newVal, oldVal) {
217                                         if (newVal !== oldVal) {
218                                                 audioElement.volume = newVal / 100;
219                                         }
220                                 });
221
222                                 scope.setCurrentTime = function (timeInSec) {
223                                         audioElement.currentTime = timeInSec;
224                                 };
225
226                                 scope.setAudioPosition = function (val) {
227                                         if (scope.isReady) {
228                                                 scope.setCurrentTime(val);
229                                                 scope.isAudioDragging = false;
230                                         }
231                                 };
232
233                                 function getTimestampArray(timestamp) {
234                                         var d = Math.abs(timestamp) / 1000; // delta
235                                         var r = {}; // result
236                                         var s = { // structure
237                                                 day: 86400,
238                                                 hour: 3600,
239                                                 minute: 60,
240                                                 second: 1
241                                         };
242
243                                         Object.keys(s).forEach(function (key) {
244                                                 r[key] = Math.floor(d / s[key]);
245                                                 d -= r[key] * s[key];
246                                         });
247
248                                         return r;
249                                 };
250
251                                 scope.timeFormatter = function (timeInSec) {
252                                         var formattedTime = '00:00';
253
254                                         if (!timeInSec || timeInSec < 1) {
255                                                 return formattedTime;
256                                         }
257
258                                         if (typeof timeInSec === 'string') {
259                                                 return timeInSec;
260                                         }
261
262                                         var dateArray = getTimestampArray(timeInSec * 1000);
263                                         Object.keys(dateArray).forEach(function (key) {
264                                                 if (dateArray[key] === 0) {
265                                                         dateArray[key] = '00';
266                                                 } else if (dateArray[key] < 10) {
267                                                         dateArray[key] = '0' + dateArray[key];
268                                                 }
269                                         });
270
271                                         formattedTime = dateArray['minute'] + ':' + dateArray['second'];
272
273                                         if (dateArray['hour'] !== '00') {
274                                                 formattedTime = dateArray['hour'] + ':' + formattedTime;
275                                         }
276
277                                         if (dateArray['day'] !== '00') {
278                                                 formattedTime = dateArray['day'] + ':' + formattedTime;
279                                         }
280
281                                         return formattedTime;
282                                 };
283
284                                 audioElement.onloadedmetadata = function () {
285                                         scope.audio.duration = audioElement.duration;
286                                         scope.$digest();
287                                 };
288
289                                 audioElement.ontimeupdate = function () {
290                                         if (!scope.isAudioDragging) {
291                                                 scope.audio.currentTime = audioElement.currentTime;
292                                                 scope.$digest();
293                                         }
294                                 };
295
296                                 audioElement.onended = function () {
297                                         scope.setCurrentTime(0);
298                                         scope.audio.currentTime = 0;
299                                         if (!audioElement.paused) {
300                                                 scope.pauseAudio();
301                                         }
302                                         scope.$digest();
303                                 };
304
305                                 audioElement.oncanplay = function () {
306                                         scope.isReady = true;
307                                         scope.isPlayInProgress = !audioElement.paused;
308                                         scope.$digest();
309                                 };
310
311                                 var onloadstart = function () {
312                                         scope.isReady = false;
313                                         scope.isPlayInProgress = !audioElement.paused;
314                                         scope.audio.currentTime = 0;
315                                         scope.audio.duration = 0;
316                                         scope.$digest();
317                                 };
318                                 audioElement.addEventListener("loadstart", onloadstart);
319                         }
320                 };
321         }]);
322 /**
323  * @ngdoc directive
324  * @name Videos, audio & animation.att:Audio Recorder
325  * @scope
326  * @param {function} callback - A callback to handle the WAV blob
327  * @param {object} config - A config object with properties startRecordingMessage & whileRecordingMessage
328  * @description
329  *  <file src="src/audioRecorder/docs/readme.md" />
330  *
331  *
332  * @example
333  *  <section id="code">
334         <example module="b2b.att">
335             <file src="src/audioRecorder/docs/demo.html" />
336             <file src="src/audioRecorder/docs/demo.js" />
337        </example>
338     </section>
339  *
340  */
341 angular.module('b2b.att.audioRecorder', ['b2b.att.utilities'])
342     .constant('AudioRecorderConfig', {
343         'startRecordingMessage': 'Click on REC icon to being recording',
344         'whileRecordingMessage': 'Recording...'
345     })
346     .directive('b2bAudioRecorder', ['$interval', 'AudioRecorderConfig', 'b2bUserAgent', 'b2bRecorder', function($interval, AudioRecorderConfig, b2bUserAgent, b2bRecorder) {
347         return {
348             restrict: 'EA',
349             replace: true,
350             scope: {
351                 callback: '&'
352             },
353             templateUrl: 'b2bTemplate/audioRecorder/audioRecorder.html',
354             controller: function($scope) {
355
356                 function hasGetUserMedia() {
357                     return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
358                         navigator.mozGetUserMedia || navigator.msGetUserMedia);
359                 }
360
361                 if (!hasGetUserMedia()) {
362                     throw new Error('Your broswer does not support MediaRecorder API');
363                 }
364
365                 if (!(b2bUserAgent.isFF() || b2bUserAgent.isChrome())) {
366                                         throw new Error('b2bAudioRecorder does not support this browser!');
367                                 }
368
369             },
370             link: function(scope, element) {
371                 scope.elapsedTime = 0;
372                 scope.isRecording = false;
373                 scope.config = {};
374                 scope.config.startRecordingMessage = AudioRecorderConfig.startRecordingMessage;
375                 scope.config.whileRecordingMessage = AudioRecorderConfig.whileRecordingMessage;
376                 
377
378                 var timer = undefined; // Interval promise
379                 navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
380                 var stream;
381                 var audio = angular.element(element[0].querySelector('audio'))[0];
382                 var recorder = undefined;
383
384                 function startRecording() {
385                     scope.isRecording = true;
386                     navigator.mediaDevices.getUserMedia({
387                         audio: true
388                     }).then(function(stream) {
389                         //create the MediaStreamAudioSourceNode
390                         context = new AudioContext();
391                         source = context.createMediaStreamSource(stream);
392                         recorder = new b2bRecorder(source);
393                         recorder.record();
394
395                         timer = $interval(function() {
396                             scope.elapsedTime += 1;
397                         }, 1000, 0);
398                     }).catch(function(err) {
399                         angular.noop();
400                     });
401
402                 };
403
404                 function stopRecording() {
405                     scope.isRecording = false;
406                     recorder.stop();
407                     var audio = {};
408                     recorder.exportWAV(function(s) {
409                         audio.src = window.URL.createObjectURL(s);
410                         context.close().then(function() {
411                                 if (timer) {
412                                         $interval.cancel(timer);
413                                     }
414                                     scope.elapsedTime = 0;
415                                     
416                                     recorder.clear();
417                                     recorder = undefined;
418                             });
419                             if (angular.isFunction(scope.callback)){
420                                                         scope.callback({'data': audio});        
421                                                 }
422                     });
423                     
424                     
425                 }
426
427                 scope.toggleRecording = function() {
428                     if (scope.isRecording) {
429                         stopRecording();
430                     } else {
431                         startRecording();
432                     }
433                 };
434
435
436
437                 //TODO: Move this into utilities
438                 function getTimestampArray(timestamp) {
439                     var d = Math.abs(timestamp) / 1000; // delta
440                     var r = {}; // result
441                     var s = { // structure
442                         day: 86400,
443                         hour: 3600,
444                         minute: 60,
445                         second: 1
446                     };
447
448                     Object.keys(s).forEach(function(key) {
449                         r[key] = Math.floor(d / s[key]);
450                         d -= r[key] * s[key];
451                     });
452
453                     return r;
454                 };
455                 scope.timeFormatter = function(timeInSec) {
456                     var formattedTime = '00:00';
457
458                     if (!timeInSec || timeInSec < 1) {
459                         return formattedTime;
460                     }
461
462                     if (typeof timeInSec === 'string') {
463                         return timeInSec;
464                     }
465
466                     var dateArray = getTimestampArray(timeInSec * 1000);
467                     Object.keys(dateArray).forEach(function(key) {
468                         if (dateArray[key] === 0) {
469                             dateArray[key] = '00';
470                         } else if (dateArray[key] < 10) {
471                             dateArray[key] = '0' + dateArray[key];
472                         }
473                     });
474
475                     formattedTime = dateArray['minute'] + ':' + dateArray['second'];
476
477                     if (dateArray['hour'] !== '00') {
478                         formattedTime = dateArray['hour'] + ':' + formattedTime;
479                     }
480
481                     if (dateArray['day'] !== '00') {
482                         formattedTime = dateArray['day'] + ':' + formattedTime;
483                     }
484
485                     return formattedTime;
486                 };
487
488                 scope.$on('$destroy', function() {
489                     if (timer) {
490                         $interval.cancel(timer);
491                     }
492                 });
493             }
494         };
495     }]);
496
497 /**
498  * @ngdoc directive
499  * @name Navigation.att:Back To Top
500  * @scope
501  * @description
502  *  <file src="src/backToTop/docs/readme.md" />
503  * @param {integer} scrollSpeed - Scroll speed in seconds, default is 1
504 *
505  * @usage
506  * 
507         <div ng-controller="backToTopController">
508                 <div b2b-backtotop></div>
509         </div>
510  * 
511  * @example
512  *  <section id="code">
513         <example module="b2b.att">
514             <file src="src/backToTop/docs/demo.html" />
515             <file src="src/backToTop/docs/demo.js" />
516        </example>
517     </section>
518  *
519  */
520  
521 angular.module('b2b.att.backToTop', ['b2b.att.utilities','b2b.att.position'])
522         .directive('b2bBacktotopButton', [function () {
523                 return {
524                         restrict: 'EA',
525                         replace: true,
526                         templateUrl: 'b2bTemplate/backToTop/backToTop.html',
527                         link: function (scope, elem, attr) {
528                                 elem.bind('click', function(evt) {
529                                         var scrollSpeed = parseInt(attr.scrollSpeed) || 1;
530                     TweenLite.to(window, scrollSpeed, {scrollTo:{x: 0, y: 0}});
531                 });
532                         }
533                 };
534         }]);
535 /**
536  * @ngdoc directive
537  * @name Messages, modals & alerts.att:badgesForAlerts
538  *
539  * @description
540  *  <file src="src/badgesForAlerts/docs/readme.md" />
541  * @example
542  *  <section id="code">
543         <example module="b2b.att">
544             <file src="src/badgesForAlerts/docs/demo.html" />
545             <file src="src/badgesForAlerts/docs/demo.js" />
546        </example>
547         </section>
548  *
549  */
550 angular.module('b2b.att.badgesForAlerts', []);
551 /**
552  * @ngdoc directive
553  * @name Misc.att:boardstrip
554  *
555  * @description
556  *  <file src="src/boardstrip/docs/readme.md" />
557  *
558  * @usage
559  * See demo section
560  * @example
561     <section id="code">
562         <b>HTML + AngularJS</b>
563         <example module="b2b.att">
564             <file src="src/boardstrip/docs/demo.html" />
565             <file src="src/boardstrip/docs/demo.js" />
566         </example>
567     </section>
568  */
569 angular.module('b2b.att.boardstrip', ['b2b.att.utilities'])
570         .constant('BoardStripConfig', {
571                 'maxVisibleBoards': 4,
572                 'boardsToScroll': 1,
573                 /* These parameters are non-configurable and remain unaltered, until there is a change in corresponding CSS */
574                 'boardLength': 140,
575                 'boardMargin': 15
576         })
577         .directive('b2bBoard', [function () {
578                 return {
579                         restrict: 'AE',
580                         replace: true,
581                         transclude: true,
582                         require: '^b2bBoardStrip',
583                         scope: {
584                                 boardIndex: '=',
585                                 boardLabel: '='
586                         },
587                         templateUrl: 'b2bTemplate/boardstrip/b2bBoard.html',
588                         link: function (scope, element, attrs, ctrls) {
589
590                                 var parentCtrl = ctrls;
591
592                                 scope.getCurrentIndex = function () {
593                                         return parentCtrl.getCurrentIndex();
594                                 };
595                                 scope.selectBoard = function (boardIndex) {
596                                         if (!isNaN(boardIndex)) {
597                                                 parentCtrl.setCurrentIndex(boardIndex);
598                                         }
599                                 };
600                         }
601                 };
602         }])
603         .directive('b2bBoardStrip', ['BoardStripConfig', '$timeout', function (BoardStripConfig, $timeout) {
604                 return {
605                         restrict: 'AE',
606                         replace: true,
607                         transclude: true,
608                         require: ['?ngModel', 'b2bBoardStrip'],
609                         scope: {
610                                 boardsMasterArray: '=',
611                                 onAddBoard: '&?'
612                         },
613                         templateUrl: 'b2bTemplate/boardstrip/b2bBoardstrip.html',
614                         controller: function ($scope) {
615                                 if (!angular.isDefined($scope.boardsMasterArray)) {
616                                         $scope.boardsMasterArray = [];
617                                 }
618
619                                 this.rectifyMaxVisibleBoards = function () {
620                                         if (this.maxVisibleIndex >= $scope.boardsMasterArray.length) {
621                                                 this.maxVisibleIndex = $scope.boardsMasterArray.length - 1;
622                                         }
623
624                                         if (this.maxVisibleIndex < 0) {
625                                                 this.maxVisibleIndex = 0;
626                                         }
627                                 };
628
629                                 this.resetBoardStrip = function () {
630                                         $scope.currentIndex = 0;
631
632                                         this.maxVisibleIndex = BoardStripConfig.maxVisibleBoards - 1;
633                                         this.minVisibleIndex = 0;
634
635                                         this.rectifyMaxVisibleBoards();
636                                 };
637
638                                 this.getCurrentIndex = function () {
639                                         return $scope.currentIndex;
640                                 };
641                                 this.setCurrentIndex = function (indx) {
642                                         $scope.currentIndex = indx;
643                                 };
644
645                                 this.getBoardsMasterArrayLength = function () {
646                                         return $scope.boardsMasterArray.length;
647                                 };
648
649                                 $scope.addBoardPressedFlag = false;
650                                 this.getAddBoardPressedFlag = function () {
651                                         return $scope.addBoardPressedFlag;
652                                 };
653                                 this.setAddBoardPressedFlag = function (booleanValue) {
654                                         $scope.addBoardPressedFlag = booleanValue;
655                                 };
656
657                         },
658                         link: function (scope, element, attrs, ctrls) {
659
660                                 var ngModelCtrl = ctrls[0];
661                                 var ctrl = ctrls[1];
662
663                                 var oldTimeout;
664                                 var animationTimeout = 1000;
665
666                                 var getBoardViewportWidth = function (numberOfVisibleBoards) {
667                                         return numberOfVisibleBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
668                                 };
669                                 if (element[0].querySelector(".board-viewport")) {
670                                         angular.element(element[0].querySelector(".board-viewport")).css({
671                                                 "width": getBoardViewportWidth(BoardStripConfig.maxVisibleBoards) + "px"
672                                         });
673                                 }
674
675                                 var getBoardstripContainerWidth = function (totalNumberOfBoards) {
676                                         return totalNumberOfBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
677                                 };
678                                 if (element[0].querySelector(".boardstrip-container")) {
679                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
680                                                 "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
681                                         });
682                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
683                                                 "left": "0px"
684                                         });
685                                 }
686
687                                 var calculateAndGetBoardstripContainerAdjustment = function () {
688
689                                         var calculatedAdjustmentValue;
690
691                                         if (ctrl.getBoardsMasterArrayLength() <= BoardStripConfig.maxVisibleBoards) {
692                                                 calculatedAdjustmentValue = 0;
693                                         } else {
694                                                 calculatedAdjustmentValue = (ctrl.minVisibleIndex * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin)) * -1;
695                                         }
696
697                                         return calculatedAdjustmentValue;
698                                 };
699
700                                 var animateBoardstripContainerAdjustment = function (elementToFocusAfterAnimation) {
701                                         var oldContainerAdjustment = angular.element(element[0].querySelector(".boardstrip-container"))[0].style.left;
702                                         var containerAdjustment = calculateAndGetBoardstripContainerAdjustment();
703                                         if (oldContainerAdjustment !== containerAdjustment + 'px') {
704                                                 angular.element(element[0].querySelector(".boardstrip-container")).css({
705                                                         "left": containerAdjustment + "px"
706                                                 });
707
708                                                 $timeout.cancel(oldTimeout);
709                                                 oldTimeout = $timeout(function () {
710                                                         elementToFocusAfterAnimation.focus();
711                                                 }, animationTimeout);
712                                         } else {
713                                                 elementToFocusAfterAnimation.focus();
714                                         }
715                                 };
716
717                                 var updateBoardsTabIndex = function (boardArray, minViewIndex, maxViewIndex) {
718                                         for (var i = 0; i < boardArray.length; i++) {
719                                                 angular.element(boardArray[i]).attr('tabindex', '-1');
720                                         }
721                                         for (var j = minViewIndex; j <= maxViewIndex; j++) {
722                                                 angular.element(boardArray[j]).attr('tabindex', '0');
723                                         }
724                                 };
725
726                                 $timeout(function () {
727                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
728                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
729                                 });
730
731                                 scope.$watchCollection('boardsMasterArray', function (newVal, oldVal) {
732                                         if (newVal !== oldVal) {
733                                                 /* When a board is removed */
734                                                 if (newVal.length < oldVal.length) {
735                                                         ctrl.resetBoardStrip();
736                                                         $timeout(function () {
737
738                                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
739                                                                 if (currentBoardArray.length !== 0) {
740                                                                         animateBoardstripContainerAdjustment(currentBoardArray[0]);
741                                                                 } else {
742                                                                         element[0].querySelector('div.boardstrip-item--add').focus();
743                                                                 }
744
745                                                                 angular.element(element[0].querySelector(".boardstrip-container")).css({
746                                                                         "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
747                                                                 });
748                                                                 /* Update tabindecies to ensure keyboard navigation behaves correctly */
749                                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
750                                                         });
751                                                 }
752                                                 /* When a board is added */
753                                                 else {
754                                                         if (ctrl.getAddBoardPressedFlag()) {
755                                                                 ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;
756                                                                 ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
757
758                                                                 ctrl.setCurrentIndex(ctrl.maxVisibleIndex);
759
760                                                                 $timeout(function () {
761                                                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
762                                                                                 "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
763                                                                         });
764
765                                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
766                                                                         animateBoardstripContainerAdjustment(currentBoardArray[currentBoardArray.length - 1]);
767                                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
768                                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
769                                                                 });
770                                                         } else {
771                                                                 if (ctrl.minVisibleIndex === 0 && ctrl.getBoardsMasterArrayLength() < BoardStripConfig.maxVisibleBoards + 1) {
772                                                                         ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;
773                                                                         ctrl.rectifyMaxVisibleBoards();
774                                                                 }
775
776                                                                 $timeout(function () {
777                                                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
778                                                                                 "width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"
779                                                                         });
780
781                                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
782                                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
783                                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
784                                                                 });
785                                                         }
786
787                                                         ctrl.setAddBoardPressedFlag(false);
788                                                 }
789                                         }
790                                 });
791
792                                 scope.nextBoard = function () {
793                                         ctrl.maxVisibleIndex += BoardStripConfig.boardsToScroll;
794                                         ctrl.rectifyMaxVisibleBoards();
795                                         ctrl.minVisibleIndex = ctrl.maxVisibleIndex - (BoardStripConfig.maxVisibleBoards - 1);
796
797                                         $timeout.cancel(oldTimeout);
798                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
799                                                 "left": calculateAndGetBoardstripContainerAdjustment() + "px"
800                                         });
801
802                                         $timeout(function () {
803                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
804
805                                                 /* Remove tabindex from non-visible boards */
806                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
807
808                                                 if (!(scope.isNextBoard())) {
809                                                         try {
810                                                                 currentBoardArray[currentBoardArray.length - 1].focus();
811                                                         } catch (e) { /* IE8 may throw exception */ }
812                                                 }
813                                         }, animationTimeout);
814                                 };
815                                 scope.prevBoard = function () {
816
817                                         ctrl.minVisibleIndex -= BoardStripConfig.boardsToScroll;
818                                         if (ctrl.minVisibleIndex < 0) {
819                                                 ctrl.minVisibleIndex = 0;
820                                         }
821
822                                         ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards - 1;
823                                         ctrl.rectifyMaxVisibleBoards();
824
825                                         $timeout.cancel(oldTimeout);
826                                         angular.element(element[0].querySelector(".boardstrip-container")).css({
827                                                 "left": calculateAndGetBoardstripContainerAdjustment() + "px"
828                                         });
829
830                                         $timeout(function () {
831                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
832
833                                                 /* Remove tabindex from non-visible boards */
834                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
835
836                                                 if (ctrl.minVisibleIndex === 0) {
837                                                         try {
838                                                                 element[0].querySelector('div.boardstrip-item--add').focus();
839                                                         } catch (e) { /* IE8 may throw exception */ }
840                                                 }
841                                         });
842                                 };
843
844                                 scope.isPrevBoard = function () {
845                                         return (ctrl.minVisibleIndex > 0);
846                                 };
847                                 scope.isNextBoard = function () {
848                                         return (ctrl.getBoardsMasterArrayLength() - 1 > ctrl.maxVisibleIndex);
849                                 };
850
851                                 ngModelCtrl.$render = function () {
852                                         if (ngModelCtrl.$viewValue || ngModelCtrl.$viewValue === 0) {
853                                                 var newCurrentIndex = ngModelCtrl.$viewValue;
854
855                                                 if (!(newCurrentIndex = parseInt(newCurrentIndex, 10))) {
856                                                         newCurrentIndex = 0;
857                                                 }
858
859                                                 if (newCurrentIndex <= 0) {
860                                                         ctrl.resetBoardStrip();
861                                                         newCurrentIndex = 0;
862
863                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
864                                                         if (currentBoardArray.length !== 0) {
865                                                                 animateBoardstripContainerAdjustment(currentBoardArray[0]);
866                                                         } else {
867                                                                 element[0].querySelector('div.boardstrip-item--add').focus();
868                                                         }
869                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
870                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
871                                                 } else if (newCurrentIndex >= ctrl.getBoardsMasterArrayLength()) {
872                                                         ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength() - 1;
873                                                         ctrl.rectifyMaxVisibleBoards();
874                                                         ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
875
876                                                         newCurrentIndex = ctrl.maxVisibleIndex;
877
878                                                         $timeout(function () {
879                                                                 var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
880                                                                 animateBoardstripContainerAdjustment(currentBoardArray[newCurrentIndex]);
881                                                                 /* Update tabindecies to ensure keyboard navigation behaves correctly */
882                                                                 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
883                                                         });
884                                                 } else {
885
886                                                         if (!(newCurrentIndex >= ctrl.minVisibleIndex && newCurrentIndex <= ctrl.maxVisibleIndex)) {
887                                                                 ctrl.minVisibleIndex = newCurrentIndex;
888                                                                 ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards - 1;
889                                                                 ctrl.rectifyMaxVisibleBoards();
890
891                                                                 if (ctrl.getBoardsMasterArrayLength() < BoardStripConfig.maxVisibleBoards) {
892                                                                         ctrl.minVisibleIndex = 0;
893                                                                 } else {
894                                                                         ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
895                                                                 }
896
897                                                                 $timeout(function () {
898                                                                         var currentBoardArray = element[0].querySelectorAll('[b2b-board]');
899                                                                         animateBoardstripContainerAdjustment(currentBoardArray[newCurrentIndex]);
900                                                                         /* Update tabindecies to ensure keyboard navigation behaves correctly */
901                                                                         updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
902                                                                 });
903                                                         }
904                                                 }
905                                                 scope.currentIndex = newCurrentIndex;
906                                                 ngModelCtrl.$setViewValue(newCurrentIndex);
907                                         } else {
908                                                 ctrl.resetBoardStrip();
909                                                 ngModelCtrl.$setViewValue(0);
910                                         }
911                                 };
912
913                                 scope.$watch('currentIndex', function (newVal, oldVal) {
914                                         if (newVal !== oldVal && ngModelCtrl && ngModelCtrl.$viewValue !== newVal) {
915                                                 ngModelCtrl.$setViewValue(newVal);
916                                         }
917                                 });
918                         }
919                 };
920         }])
921         .directive('b2bAddBoard', ['BoardStripConfig', '$parse', function (BoardStripConfig, $parse) {
922                 return {
923                         restrict: 'AE',
924                         replace: true,
925                         require: '^b2bBoardStrip',
926                         scope: {
927                                 onAddBoard: '&?'
928                         },
929                         templateUrl: 'b2bTemplate/boardstrip/b2bAddBoard.html',
930                         link: function (scope, element, attrs, ctrl) {
931                                 scope.addBoard = function () {
932                                         if (attrs['onAddBoard']) {
933                                                 scope.onAddBoard = $parse(scope.onAddBoard);
934                                                 scope.onAddBoard();
935                                                 ctrl.setAddBoardPressedFlag(true);
936                                         }
937                                 };
938                         }
939                 };
940         }])
941         .directive('b2bBoardNavigation', ['keymap', 'events', function (keymap, events) {
942                 return {
943                         restrict: 'AE',
944                         link: function (scope, elem) {
945
946                                 var prevElem = keymap.KEY.LEFT;
947                                 var nextElem = keymap.KEY.RIGHT;
948
949                                 elem.bind('keydown', function (ev) {
950
951                                         if (!(ev.keyCode)) {
952                                                 ev.keyCode = ev.which;
953                                         }
954
955                                         switch (ev.keyCode) {
956                                         case nextElem:
957                                                 events.preventDefault(ev);
958                                                 events.stopPropagation(ev);
959
960                                                 if (elem[0].nextElementSibling && parseInt(angular.element(elem[0].nextElementSibling).attr('tabindex')) >= 0) {
961                                                         angular.element(elem[0])[0].nextElementSibling.focus();
962                                                 } else {
963                                                         /* IE8 fix */
964                                                         var el = angular.element(elem[0])[0];
965                                                         do {
966                                                                 if (el.nextSibling) {
967                                                                         el = el.nextSibling;
968                                                                 } else {
969                                                                         break;
970                                                                 }
971                                                         } while (el && el.tagName !== 'LI');
972
973                                                         if (el.tagName && el.tagName === 'LI' && parseInt(angular.element(el).attr('tabindex')) >= 0) {
974                                                                 el.focus();
975                                                         }
976                                                 }
977
978                                                 break;
979                                         case prevElem:
980                                                 events.preventDefault(ev);
981                                                 events.stopPropagation(ev);
982
983                                                 if (elem[0].previousElementSibling && parseInt(angular.element(elem[0].previousElementSibling).attr('tabindex')) >= 0) {
984                                                         angular.element(elem[0])[0].previousElementSibling.focus();
985                                                 } else {
986                                                         /* IE8 fix */
987                                                         var el1 = angular.element(elem[0])[0];
988                                                         do {
989                                                                 if (el1.previousSibling) {
990                                                                         el1 = el1.previousSibling;
991                                                                 } else {
992                                                                         break;
993                                                                 }
994                                                         } while (el1 && el1.tagName !== 'LI');
995
996                                                         if (el1.tagName && el1.tagName === 'LI' && parseInt(angular.element(el1).attr('tabindex')) >= 0) {
997                                                                 el1.focus();
998                                                         }
999                                                 }
1000                                                 break;
1001                                         default:
1002                                                 break;
1003                                         }
1004                                 });
1005                         }
1006                 };
1007         }]);
1008 /** 
1009  * @ngdoc directive 
1010  * @name Template.att:Bootstrap Grid Template
1011  * 
1012  * @description 
1013  *  <file src="src/bootstrapGridTemplate/docs/readme.md" /> 
1014  * 
1015  * @example 
1016  *  <section id="code">
1017         <example module="b2b.att"> 
1018             <file src="src/bootstrapGridTemplate/docs/demo.html" /> 
1019             <file src="src/bootstrapGridTemplate/docs/demo.js" /> 
1020        </example> 
1021     </section>    
1022  * 
1023  */
1024 angular.module('b2b.att.bootstrapGridTemplate', [])
1025   
1026 /**
1027  * @ngdoc directive
1028  * @name Navigation.att:breadcrumbs
1029  *
1030  * @description
1031  *  <file src="src/breadcrumbs/docs/readme.md" />
1032  * @usage
1033     <ul class="breadcrumb">
1034         <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>
1035     </ul>
1036  * @example
1037  <example module="b2b.att">
1038  <file src="src/breadcrumbs/docs/demo.html" />
1039  <file src="src/breadcrumbs/docs/demo.js" />
1040  </example>
1041  */
1042 angular.module('b2b.att.breadcrumbs',[])
1043 /**
1044  * @ngdoc directive
1045  * @name Buttons, links & UI controls.att:buttonGroups
1046  *
1047  * @description
1048  *  <file src="src/buttonGroups/docs/readme.md" />
1049  *
1050  * @usage
1051 <h2>Radio Aproach</h2>
1052 <div class="btn-group" b2b-key prev="37,38" next="39,40" circular-traversal role="radiogroup">
1053     <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>
1054     <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>
1055     <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>
1056 </div>
1057
1058 <h2>Checkbox Aproach</h2>
1059 <span b2b-button-group class="btn-group btn-fullwidth" role="group" max-select="3" ng-model="checkModel1">
1060     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button1" b2b-btn-checkbox>Button1</button>
1061     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button2" b2b-btn-checkbox>Button2</button>
1062     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button3" b2b-btn-checkbox>Button3</button>
1063     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button4" b2b-btn-checkbox>Button4</button>
1064     <button type="button" class="btn btn-secondary" ng-model="checkModel1.Button5" b2b-btn-checkbox>Button5</button>
1065 </span>
1066  *
1067  * @example
1068  *  <section id="code">
1069         <example module="b2b.att">
1070             <file src="src/buttonGroups/docs/demo.html" />
1071             <file src="src/buttonGroups/docs/demo.js" />
1072        </example>
1073         </section>
1074  *
1075  */
1076 angular.module('b2b.att.buttonGroups', ['b2b.att.utilities'])
1077     .constant('buttonConfig', {
1078         activeClass: 'active',
1079         toggleEvent: 'click'
1080     })
1081     .directive('b2bBtnRadio', ['buttonConfig', function (buttonConfig) {
1082         var activeClass = buttonConfig.activeClass || 'active';
1083         var toggleEvent = buttonConfig.toggleEvent || 'click';
1084
1085         return {
1086             require: 'ngModel',
1087             link: function (scope, element, attrs, ngModelCtrl) {
1088                 var notMobile = !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
1089
1090                 if (notMobile) {
1091                     element.bind('focus', function () {
1092                         scope.$apply(function () {
1093                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));
1094                             ngModelCtrl.$render();
1095                         });
1096                     });
1097                 }
1098
1099                 element.attr('role', 'radio');
1100
1101                 //model -> UI
1102                 ngModelCtrl.$render = function () {
1103                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio)));
1104                     if (angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.b2bBtnRadio))) {
1105                         element.attr("aria-checked", true);
1106                     } else {
1107                         element.attr("aria-checked", false);
1108                     }
1109                 };
1110
1111                 //ui->model
1112                 element.bind(toggleEvent, function () {
1113                     if (!element.hasClass(activeClass)) {
1114                         scope.$apply(function () {
1115                             ngModelCtrl.$setViewValue(scope.$eval(attrs.b2bBtnRadio));
1116                             ngModelCtrl.$render();
1117                         });
1118                     }
1119                 });
1120             }
1121         };
1122     }])
1123     .directive('b2bBtnCheckbox', ['buttonConfig', function (buttonConfig) {
1124         var activeClass = buttonConfig.activeClass || 'active';
1125         var toggleEvent = buttonConfig.toggleEvent || 'click';
1126
1127         return {
1128             require: ['ngModel', '^^b2bButtonGroup'],
1129             link: function (scope, element, attrs, ctrls) {
1130
1131                 var ngModelCtrl = ctrls[0];
1132                 var parentCtrl = ctrls[1];
1133
1134                 element.attr('role', 'checkbox');
1135                 element.attr('aria-describedby', parentCtrl.getStateDescriptionElemId());
1136
1137                 function getTrueValue() {
1138                     var trueValue = scope.$eval(attrs.b2bBtnCheckboxTrue);
1139                     return angular.isDefined(trueValue) ? trueValue : true;
1140                 }
1141
1142                 function getFalseValue() {
1143                     var falseValue = scope.$eval(attrs.b2bBtnCheckboxFalse);
1144                     return angular.isDefined(falseValue) ? falseValue : false;
1145                 }
1146
1147                 //model -> UI
1148                 ngModelCtrl.$render = function () {
1149                     element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
1150                     if ((angular.equals(ngModelCtrl.$modelValue, getTrueValue()))) {
1151                         element.attr("aria-checked", true);
1152                     } else {
1153                         element.attr("aria-checked", false);
1154                     }
1155                 };
1156
1157                 //ui->model
1158                 element.bind(toggleEvent, function () {
1159                     scope.$apply(function () {
1160                         ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? getFalseValue() : getTrueValue());
1161                         ngModelCtrl.$render();
1162                     });
1163                 });
1164             }
1165         };
1166     }])
1167     .directive('b2bButtonGroup', ['$timeout', '$compile', function ($timeout, $compile) {
1168         return {
1169             restrict: 'A',
1170             scope: {
1171                 maxSelect: "=",
1172                 ngModelButtonState: '=ngModel'
1173             },
1174             controller: ['$scope', '$element', function ($scope, $element) {
1175                 $scope.nSel = 0;
1176
1177                 var stateDescriptionElem = angular.element('<span id="b2b_button_group_' + $scope.$id + '" class="hide" aria-hidden="true">{{nSel}} of {{maxSelect}} options selected.</span>');
1178                 $compile(stateDescriptionElem)($scope);
1179                 $element.after(stateDescriptionElem);
1180
1181                 this.getStateDescriptionElemId = function () {
1182                     return stateDescriptionElem.attr('id');
1183                 };
1184             }],
1185             link: function (scope, element) {
1186
1187
1188                 var executeFxn = function () {
1189                     scope.nSel = 0;
1190                     angular.forEach(scope.ngModelButtonState, function (value, key) {
1191                         if (value === true) {
1192                             scope.nSel += 1;
1193                         }
1194                     });
1195
1196                     if (scope.nSel >= scope.maxSelect) {
1197                         angular.forEach(element.children(), function (chd) {
1198                             if (chd.className.indexOf('active') < 0) {
1199                                 chd.disabled = true;
1200                                 chd.setAttribute('aria-disabled', true);
1201                             }
1202                         });
1203                     } else {
1204                         angular.forEach(element.children(), function (chd) {
1205                             chd.disabled = false;
1206                             chd.setAttribute('aria-disabled', false);
1207                         });
1208                     }
1209                     scope.$digest();
1210                 };
1211
1212                 $timeout(function () {
1213                     executeFxn();
1214                 });
1215                 element.bind('click', executeFxn);
1216             }
1217         };
1218     }]);
1219 /**
1220  * @ngdoc directive
1221  * @name Buttons, links & UI controls.att:buttons
1222  * @element input
1223  * @function
1224  *
1225  * @description
1226  *  <file src="src/buttons/docs/readme.md" />
1227  * @usage
1228  *
1229 Button shape
1230 <button class="btn" type="button">Button</button> button.btn (button shape only)
1231 <button aria-label="Custom aria label" class="btn" type="button">Button</button> button.btn (button shape only) with custom aria label
1232 <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
1233 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn" role="button">Button</a> a.btn (button shape only)
1234 <button class="btn btn-primary">Button</button> .btn-primary
1235 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-primary" role="button">Button</a> a.btn-primary
1236
1237 5 Button colors
1238 <button class="btn btn-secondary">Button</button> .btn-secondary
1239 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-secondary" role="button">Button</a> a.btn-secondary
1240 <button class="btn btn-alt">Button</button> .btn-alt
1241 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-alt" role="button">Button</a> a.btn-alt
1242 <button class="btn btn-specialty">Button</button> .btn-specialty
1243 <a b2b-keyup-click="32" href="javascript:void(0)" class="btn btn-specialty" role="button">Button</a> a.btn-specialty
1244 <button class="btn btn-specialty" disabled="">Button</button> disabled="disabled"
1245 <a b2b-keyup-click="32" aria-disabled="true" href="javascript:void(0)" class="btn btn-primary disabled" role="button">Button</a> a.disabled
1246
1247 3 button heights
1248 <button class="btn btn-secondary">Button</button> .btn is default and 46px height
1249 <button class="btn btn-secondary btn-medium">Button</button> .btn-medium is 42px
1250 <button class="btn btn-secondary btn-small">Button</button> .btn-small is 36px
1251
1252 .row-nowrap 2 up buttons
1253 <div class="row-nowrap">
1254     <button class="btn btn-secondary btn-fullwidth" type="button">Cancel</button>
1255     <button class="btn btn-primary btn-fullwidth" type="button">Continue</button>
1256 </div>
1257
1258 .row 2 up buttons (desktop) stacked (mobile) (different order)
1259 <div class="row cta-button-group">
1260     <button class="span btn btn-secondary btn-fullwidth hidden-phone" type="button">Cancel</button>
1261     <button class="span btn btn-primary btn-fullwidth" type="button">Continue</button>
1262     <button class="span btn btn-secondary btn-fullwidth visible-phone" type="button">Cancel</button>
1263 </div>
1264
1265  * @example
1266  *  <section id="code">
1267                <b>HTML + AngularJS</b>
1268  *              <example module="b2b.att">
1269  *              <file src="src/buttons/docs/demo.html" />
1270                  <file src="src/buttons/docs/demo.js" />
1271  *              </example>
1272             </section>
1273  *
1274  */
1275 angular.module('b2b.att.buttons', ['b2b.att.utilities']);
1276 /**
1277  * @ngdoc directive
1278  * @name Forms.att:calendar
1279  *
1280  * @description
1281  *  <file src="src/calendar/docs/readme.md" />
1282  * @usage
1283  *  <input type="text" ng-model="dt" b2b-datepicker>
1284  *
1285  * @example
1286    <section id="code">
1287     <b>HTML + AngularJS</b>
1288     <example module="b2b.att">
1289      <file src="src/calendar/docs/demo.html" />
1290      <file src="src/calendar/docs/demo.js" />
1291     </example>
1292    </section>
1293  */
1294 angular.module('b2b.att.calendar', ['b2b.att.position', 'b2b.att.utilities'])
1295
1296 .constant('b2bDatepickerConfig', {
1297     dateFormat: 'MM/dd/yyyy',
1298     dayFormat: 'd',
1299     monthFormat: 'MMMM',
1300     yearFormat: 'yyyy',
1301     dayHeaderFormat: 'EEEE',
1302     dayTitleFormat: 'MMMM yyyy',
1303     disableWeekend: false,
1304     disableSunday: false,
1305     disableDates: null,
1306     onSelectClose: null,
1307     startingDay: 0,
1308     minDate: null,
1309     maxDate: null,
1310     dueDate: null,
1311     fromDate: null,
1312     legendIcon: null,
1313     legendMessage: null,
1314     calendarDisabled: false,
1315     collapseWait: 0,
1316     orientation: 'right',
1317     inline: false,
1318     helperText: 'The date you selected is $date. In case of mobile double tap to open calendar. Select a date to close the calendar.',
1319     datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation'],
1320     datepickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],
1321     datepickerFunctionAttributes: ['disableDates', 'onSelectClose']
1322 })
1323
1324 .factory('b2bDatepickerService', ['b2bDatepickerConfig', 'dateFilter', function (b2bDatepickerConfig, dateFilter) {
1325     var setAttributes = function (attr, elem) {
1326         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
1327             var attributes = b2bDatepickerConfig.datepickerEvalAttributes.concat(b2bDatepickerConfig.datepickerWatchAttributes, b2bDatepickerConfig.datepickerFunctionAttributes);
1328             for (var key in attr) {
1329                 var val = attr[key];
1330                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1331                     elem.attr(key.toSnakeCase(), key);
1332                 }
1333             }
1334         }
1335     };
1336
1337     var bindScope = function (attr, scope) {
1338         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
1339             var evalFunction = function (key, val) {
1340                 scope[key] = scope.$parent.$eval(val);
1341             };
1342
1343             var watchFunction = function (key, val) {
1344                 scope.$parent.$watch(val, function (value) {
1345                     scope[key] = value;
1346                 });
1347                 scope.$watch(key, function (value) {
1348                     scope.$parent[val] = value;
1349                 });
1350             };
1351
1352             var evalAttributes = b2bDatepickerConfig.datepickerEvalAttributes;
1353             var watchAttributes = b2bDatepickerConfig.datepickerWatchAttributes;
1354             for (var key in attr) {
1355                 var val = attr[key];
1356                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1357                     evalFunction(key, val);
1358                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
1359                     watchFunction(key, val);
1360                 }
1361             }
1362         }
1363     };
1364
1365     return {
1366         setAttributes: setAttributes,
1367         bindScope: bindScope
1368     };
1369 }])
1370
1371 .controller('b2bDatepickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bDatepickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {
1372     var format = {
1373             date: getValue($attrs.dateFormat, dtConfig.dateFormat),
1374             day: getValue($attrs.dayFormat, dtConfig.dayFormat),
1375             month: getValue($attrs.monthFormat, dtConfig.monthFormat),
1376             year: getValue($attrs.yearFormat, dtConfig.yearFormat),
1377             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
1378             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
1379             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
1380             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday)
1381         },
1382         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
1383
1384     if($attrs.disableDates !== undefined) {
1385         format.disableDates = $attrs.disableDates;
1386     } else {
1387        format.disableDates =  dtConfig.disableDates;     
1388     }
1389     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
1390     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
1391     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;
1392     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;
1393     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;
1394     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;
1395     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;
1396     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);
1397     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);
1398     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);
1399
1400     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;
1401
1402     function getValue(value, defaultValue) {
1403         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
1404     }
1405
1406     function getDaysInMonth(year, month) {
1407         return new Date(year, month, 0).getDate();
1408     }
1409
1410     function getDates(startDate, n) {
1411         var dates = new Array(n);
1412         var current = startDate,
1413             i = 0;
1414         while (i < n) {
1415             dates[i++] = new Date(current);
1416             current.setDate(current.getDate() + 1);
1417         }
1418         return dates;
1419     }
1420
1421     this.updatePosition = function (b2bDatepickerPopupTemplate) {
1422         $scope.position = $position.offset($element);
1423         $scope.position.top = $scope.position.top + $element.prop('offsetHeight');
1424         $scope.position.left = $scope.position.left - (((b2bDatepickerPopupTemplate && b2bDatepickerPopupTemplate.prop('offsetWidth')) || 290) - $element.prop('offsetWidth'));
1425     };
1426
1427     this.isDateInRange = function(date) {
1428         if ((compare(date, $scope.minDate) >= 0) && (compare(date, $scope.maxDate) <= 0)) {
1429             return true;
1430         } else  {
1431             return false;
1432         }
1433         return false;
1434     }
1435
1436     this.isDisbaledDate = function(date) {
1437         if ($attrs.from && !angular.isDate($scope.fromDate)) {
1438             return true;
1439         }
1440         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
1441             return true;
1442         }
1443         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
1444             return true;
1445         }
1446     
1447         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || ($scope.datesCallBack({
1448             date: date
1449         })));
1450
1451     }
1452     function isSelected(dt) {
1453         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
1454             return true;
1455         }
1456         return false;
1457     }
1458
1459     function isFromDate(dt) {
1460         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
1461             return true;
1462         }
1463         return false;
1464     }
1465
1466     function isDateRange(dt) {
1467         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
1468             return true;
1469         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {
1470             return true;
1471         }
1472         return false;
1473     }
1474
1475     function isOld(date, currentMonthDate) {
1476         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())) {
1477             return true;
1478         } else {
1479             return false;
1480         }
1481     }
1482
1483     function isNew(date, currentMonthDate) {
1484         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())) {
1485             return true;
1486         } else {
1487             return false;
1488         }
1489     }
1490
1491     function isPastDue(dt) {
1492         if ($scope.dueDate) {
1493             return (dt > $scope.dueDate);
1494         }
1495         return false;
1496     }
1497
1498     function isDueDate(dt) {
1499         if ($scope.dueDate) {
1500             return (dt.getTime() === $scope.dueDate.getTime());
1501         }
1502         return false;
1503     }
1504
1505     var isDisabled = function (date, currentMonthDate) {
1506         if ($attrs.from && !angular.isDate($scope.fromDate)) {
1507             return true;
1508         }
1509         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
1510             return true;
1511         }
1512         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
1513             return true;
1514         }
1515         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {
1516             return true;
1517         }
1518         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || ($scope.datesCallBack({
1519             date: date
1520         })));
1521     };
1522
1523     var compare = function (date1, date2) {
1524         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
1525     };
1526
1527     function isMinDateAvailable(startDate, endDate) {
1528         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
1529             $scope.disablePrev = true;
1530             $scope.visibilityPrev = "hidden";
1531         } else {
1532             $scope.disablePrev = false;
1533             $scope.visibilityPrev = "visible";
1534         }
1535     }
1536
1537     function isMaxDateAvailable(startDate, endDate) {
1538         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
1539             $scope.disableNext = true;
1540             $scope.visibilityNext = "hidden";
1541         } else {
1542             $scope.disableNext = false;
1543             $scope.visibilityNext = "visible";
1544         }
1545     }
1546
1547     function getLabel(label) {
1548         if (label) {
1549             var labelObj = {
1550                 pre: label.substr(0, 1).toUpperCase(),
1551                 post: label
1552             };
1553             return labelObj;
1554         }
1555         return;
1556     }
1557
1558     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {
1559         return {
1560             date: date,
1561             label: dateFilter(date, dayFormat),
1562             header: dateFilter(date, dayHeaderFormat),
1563             selected: !!isSelected,
1564             fromDate: !!isFromDate,
1565             dateRange: !!isDateRange,
1566             oldMonth: !!isOld,
1567             nextMonth: !!isNew,
1568             disabled: !!isDisabled,
1569             dueDate: !!dueDate,
1570             pastDue: !!pastDue,
1571             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))
1572         };
1573     }
1574
1575     this.modes = [
1576         {
1577             name: 'day',
1578             getVisibleDates: function (date) {
1579                 var year = date.getFullYear(),
1580                     month = date.getMonth(),
1581                     firstDayOfMonth = new Date(year, month, 1),
1582                     lastDayOfMonth = new Date(year, month + 1, 0);
1583                 var difference = startingDay - firstDayOfMonth.getDay(),
1584                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
1585                     firstDate = new Date(firstDayOfMonth),
1586                     numDates = 0;
1587
1588                 if (numDisplayedFromPreviousMonth > 0) {
1589                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
1590                     numDates += numDisplayedFromPreviousMonth; // Previous
1591                 }
1592                 numDates += getDaysInMonth(year, month + 1); // Current
1593                 numDates += (7 - numDates % 7) % 7; // Next
1594
1595                 var days = getDates(firstDate, numDates),
1596                     labels = new Array(7);
1597                 for (var i = 0; i < numDates; i++) {
1598                     var dt = new Date(days[i]);
1599                     days[i] = makeDate(dt,
1600                         format.day,
1601                         format.dayHeader,
1602                         isSelected(dt),
1603                         isFromDate(dt),
1604                         isDateRange(dt),
1605                         isOld(dt, date),
1606                         isNew(dt, date),
1607                         isDisabled(dt, date),
1608                         isDueDate(dt),
1609                         isPastDue(dt));
1610                 }
1611                 for (var j = 0; j < 7; j++) {
1612                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
1613                 }
1614                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
1615                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
1616                 return {
1617                     objects: days,
1618                     title: dateFilter(date, format.dayTitle),
1619                     labels: labels
1620                 };
1621             },
1622             split: 7,
1623             step: {
1624                 months: 1
1625             }
1626         }
1627     ];
1628 }])
1629
1630 .directive('b2bDatepicker', ['$parse', '$log', '$timeout', '$document', '$documentBind', '$isElement', '$templateCache', '$compile', 'trapFocusInElement', '$position', '$window', '$filter', 'b2bDatepickerConfig', function ($parse, $log, $timeout, $document, $documentBind, $isElement, $templateCache, $compile, trapFocusInElement, $position, $window, $filter, b2bDatepickerConfig) {
1631     return {
1632         restrict: 'EA',
1633         scope: { 
1634             model: '=ngModel',
1635             datesCallBack: '&disableDates',
1636             onSelectClose: '&',
1637             disabledInput: '=?ngDisabled'
1638         },
1639         require: ['b2bDatepicker', 'ngModel', '?^b2bDatepickerGroup'],
1640         controller: 'b2bDatepickerController',
1641         link: function (scope, element, attrs, ctrls) {
1642             var datepickerCtrl = ctrls[0],
1643                 ngModel = ctrls[1],
1644                 b2bDatepickerGroupCtrl = ctrls[2];
1645             var b2bDatepickerPopupTemplate;
1646             var isCalendarOpened = false;
1647             if(scope.disabledInput === undefined || scope.disabledInput === '') {
1648                 scope.disabledInput = false;
1649             } 
1650             if(attrs.inline == 'true'){     
1651                 element.after($compile($templateCache.get('b2bTemplate/calendar/datepicker-popup.html'))(scope));
1652                 var temp = element.after();
1653                 element.remove();
1654                 element = temp; 
1655             } else {
1656                 var buttonTabIndex =  scope.disabledInput===true ? -1 : 0; 
1657
1658                 element.after($compile('<button class="btn-calendar-icon" ng-disabled='+scope.disabledInput+' ><i class="icon-primary-calendar b2b-calendar-icon" aria-haspopup="true" aria-expanded="false" ng-class=\"{\'disabled\': '+scope.disabledInput+'}\" ></i></button>')(scope));
1659                 element.attr('placeholder', 'MM/dd/yyyy');
1660                 element.attr('b2b-format-date', b2bDatepickerConfig.dateFormat); 
1661             }
1662             scope.$watch('model', function(val) {
1663
1664                 if(val !== undefined && val !== '') {
1665                     var date_regex = /^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/ ;
1666
1667                     if(!date_regex.test(element[0].value)) {
1668                         ngModel.$setValidity('datePattern', false);
1669                     } else {    
1670                         ngModel.$setValidity('datePattern', true);
1671                     }
1672                     
1673                 } else {
1674                     ngModel.$setValidity('datePattern', true);
1675                 }
1676                 
1677             });
1678
1679             if (!ngModel) {
1680                 $log.error("ng-model is required.");
1681                 return; // do nothing if no ng-model
1682             }
1683
1684             if(scope.model !== undefined && scope.model !== '') {
1685                 element[0].value = $filter('date')(scope.model, "MM/dd/yyyy");
1686             }
1687
1688             // Configuration parameters
1689             var mode = 0,
1690                 selected;
1691             scope.isOpen = false;
1692             var isValidDate = false;
1693
1694             scope.headers = [];
1695             scope.footers = [];
1696
1697             if (b2bDatepickerGroupCtrl) {
1698                 b2bDatepickerGroupCtrl.registerDatepickerScope(scope);
1699             }
1700
1701              var calendarButton = angular.element(element[0].nextElementSibling);
1702
1703             calendarButton.bind('click',function(){
1704                 openCalendarPopup = false;
1705                 if (!scope.ngDisabled) {
1706                     scope.isOpen = !scope.isOpen;
1707                     toggleCalendar(scope.isOpen);
1708                     scope.$apply();
1709                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1710                     $timeout(function () { 
1711                        // angular.element(element[0].querySelector('.datepicker-input')).scrollTop=0;
1712                     },10);
1713                 }
1714             })
1715             var openCalendarPopup = false;
1716
1717             element.bind('blur', function() {
1718                 if(scope.model !== undefined && scope.model !== '') {
1719                     var dateEntered = scope.model;
1720
1721                       var date_regex = /^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/ ;
1722
1723                     if(date_regex.test(dateEntered)) {       
1724                         var parts = dateEntered.split('/');
1725                         var enteredDate = new Date(parts[2],parts[0]-1,parts[1]);                           
1726
1727                         if(datepickerCtrl.isDateInRange(enteredDate)) {
1728                             isValidDate -= 1;
1729                             ngModel.$setValidity('outOfRange', true);
1730                             $timeout(function(){
1731                                 ngModel.$setValidity('outOfRange', true);
1732                             },10);
1733                             isValidDate = true;
1734                             if(!datepickerCtrl.isDisbaledDate(enteredDate)) {  
1735                                $timeout(function(){
1736                                     ngModel.$setValidity('disabledDate', true);
1737                                },10);   
1738                                 scope.select(enteredDate); 
1739                                 openCalendarPopup = true;
1740                             } else {
1741                                 $timeout(function(){
1742                                     ngModel.$setValidity('disabledDate', false);
1743                                 },10);
1744                                 isValidDate = false;
1745                                 openCalendarPopup = false;
1746                             }
1747   
1748                         } else {
1749                             isValidDate += 1;
1750                             $timeout(function(){
1751                                 ngModel.$setValidity('outOfRange', false);
1752                             },10);
1753                             isValidDate = false;
1754                             openCalendarPopup = false;
1755                         }
1756
1757                     }
1758                 }
1759             });   
1760
1761             var toggleCalendar = function (flag) {
1762                 if (!scope.inline) {
1763                     if (flag) {
1764                         b2bDatepickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/calendar/datepicker-popup.html'));
1765                         b2bDatepickerPopupTemplate = $compile(b2bDatepickerPopupTemplate)(scope);
1766                         $document.find('body').append(b2bDatepickerPopupTemplate);
1767                         b2bDatepickerPopupTemplate.bind('keydown', keyPress);
1768                         $timeout(function () {
1769                             scope.getFocus = true;
1770                             trapFocusInElement(flag, b2bDatepickerPopupTemplate);
1771                             scope.$apply();
1772                             $timeout(function () {
1773                                 scope.getFocus = false; 
1774                                 scope.$apply();
1775                             }, 100);
1776                             handleTabEvent();
1777                         });
1778                         angular.element(document.querySelector('.b2b-calendar-icon')).attr('aria-expanded','true');
1779                     } else {
1780                         if(!openCalendarPopup) {
1781                             b2bDatepickerPopupTemplate.unbind('keydown', keyPress);
1782                             b2bDatepickerPopupTemplate.remove();
1783                         }
1784                         element[0].focus();
1785                         scope.getFocus = false;
1786                         angular.element(document.querySelector('.b2b-calendar-icon')).attr('aria-expanded','false');
1787                         trapFocusInElement(flag, b2bDatepickerPopupTemplate);
1788                     }
1789                 }
1790             };
1791
1792             var handleTabEvent = function(){
1793                 b2bDatepickerPopupTemplate.find('td').on('keydown', function (e) {
1794                     if (e.keyCode == '9') {
1795                         if(e.shiftKey){
1796                             if(b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.next')){
1797                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.next').focus();
1798                             }else{
1799                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.datepicker-switch').focus()
1800                             }        
1801                         }else{
1802                             if(b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.prev')){
1803                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.prev').focus();
1804                             }else{
1805                                 b2bDatepickerPopupTemplate.find('tr')[0].querySelector('th.datepicker-switch').focus()
1806                             }
1807                         }
1808                         
1809                         e.preventDefault();
1810                         e.stopPropagation();
1811                     }
1812                 });
1813             }
1814
1815             var outsideClick = function (e) {
1816                 var isElement = $isElement(angular.element(e.target), element, $document);
1817                 var isb2bDatepickerPopupTemplate = $isElement(angular.element(e.target), b2bDatepickerPopupTemplate, $document);
1818                 if (!(isElement || isb2bDatepickerPopupTemplate)) {
1819                     scope.isOpen = false;
1820                     toggleCalendar(scope.isOpen);
1821                     scope.$apply();
1822                 }
1823             };
1824
1825             var keyPress = function (ev) {
1826                 if (!ev.keyCode) {
1827                     if (ev.which) {
1828                         ev.keyCode = ev.which;
1829                     } else if (ev.charCode) {
1830                         ev.keyCode = ev.charCode;
1831                     }
1832                 }
1833                 if (ev.keyCode) {
1834                     if (ev.keyCode === 27) {
1835                         scope.isOpen = false;
1836                         toggleCalendar(scope.isOpen);
1837                         ev.preventDefault();
1838                         ev.stopPropagation();
1839                     } else if (ev.keyCode === 33) {
1840                         !scope.disablePrev && scope.move(-1);
1841                         $timeout(function () {
1842                             scope.getFocus = true;
1843                             scope.$apply();
1844                             $timeout(function () {
1845                                 scope.getFocus = false;
1846                                 scope.$apply();
1847                             }, 100);
1848                         });
1849                         ev.preventDefault();
1850                         ev.stopPropagation();
1851                     } else if (ev.keyCode === 34) {
1852                         !scope.disableNext && scope.move(1);
1853                         $timeout(function () {
1854                             scope.getFocus = true;
1855                             scope.$apply();
1856                             $timeout(function () {
1857                                 scope.getFocus = false;
1858                                 scope.$apply();
1859                             }, 100);
1860                         });
1861                         ev.preventDefault();
1862                         ev.stopPropagation();
1863                     }
1864                     scope.$apply();
1865                 }
1866             };
1867
1868             $documentBind.click('isOpen', outsideClick, scope);
1869
1870             var modalContainer = angular.element(document.querySelector('.modalwrapper'));
1871             var modalBodyContainer = angular.element(document.querySelector('.modal-body'));
1872             if (modalContainer) {
1873                 modalContainer.bind('scroll', function () {
1874                     if (b2bDatepickerPopupTemplate) {
1875                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1876                         scope.$apply();
1877                     }
1878                 });
1879             }
1880             if (modalBodyContainer) {
1881                 modalBodyContainer.bind('scroll', function () {
1882                     if (b2bDatepickerPopupTemplate) {
1883                         datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1884                         var datepickerTextfield = $position.offset(element.find('input'));
1885                         var modalBodyPosition = $position.offset(modalBodyContainer);
1886
1887                         if (((datepickerTextfield.top + datepickerTextfield.height) < modalBodyPosition.top || datepickerTextfield.top > (modalBodyPosition.top + modalBodyPosition.height)) && scope.isOpen) {
1888                             scope.isOpen = false;
1889                             toggleCalendar(scope.isOpen);
1890                         }
1891                         scope.$apply();
1892                     }
1893                 });
1894             }
1895             var window = angular.element($window);
1896             window.bind('resize', function () {
1897                 if (b2bDatepickerPopupTemplate) {
1898                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
1899                     scope.$apply();
1900                 }
1901             });
1902
1903             scope.$on('$destroy', function () {
1904                 if (scope.isOpen) {
1905                     scope.isOpen = false;
1906                     toggleCalendar(scope.isOpen);
1907                 }
1908             });
1909
1910             scope.resetTime = function (date) {
1911                 if (typeof date === 'string') {
1912                     date = date + 'T12:00:00';
1913                 }
1914                 var dt;
1915                 if (!isNaN(new Date(date))) {
1916                     dt = new Date(date);
1917                 } else {
1918                     return null;
1919                 }
1920                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
1921             };
1922
1923             if (attrs.min) {
1924                 scope.$parent.$watch($parse(attrs.min), function (value) {
1925                     scope.minDate = value ? scope.resetTime(value) : null;
1926                     refill();
1927                 });
1928             }
1929             if (attrs.max) {
1930                 scope.$parent.$watch($parse(attrs.max), function (value) {
1931                     scope.maxDate = value ? scope.resetTime(value) : null;
1932                     refill();
1933                 });
1934             }
1935             if (attrs.due) {
1936                 scope.$parent.$watch($parse(attrs.due), function (value) {
1937                     scope.dueDate = value ? scope.resetTime(value) : null;
1938                     refill();
1939                 });
1940             }
1941             if (attrs.from) {
1942                 scope.$parent.$watch($parse(attrs.from), function (value) {
1943                     scope.fromDate = value ? scope.resetTime(value) : null;
1944                     refill();
1945                 });
1946             }
1947
1948             if (attrs.legendIcon) {
1949                 scope.$parent.$watch(attrs.legendIcon, function (value) {
1950                     scope.legendIcon = value ? value : null;
1951                     refill();
1952                 });
1953             }
1954             if (attrs.legendMessage) {
1955                 scope.$parent.$watch(attrs.legendMessage, function (value) {
1956                     scope.legendMessage = value ? value : null;
1957                     refill();
1958                 });
1959             }
1960             if (attrs.ngDisabled) {
1961                 scope.$parent.$watch(attrs.ngDisabled, function (value) {
1962                     scope.ngDisabled = value ? value : null;
1963                 });
1964             }
1965
1966             // Split array into smaller arrays
1967             function split(arr, size) {
1968                 var arrays = [];
1969                 while (arr.length > 0) {
1970                     arrays.push(arr.splice(0, size));
1971                 }
1972                 return arrays;
1973             }
1974
1975             function refill(date) {
1976                 if (angular.isDate(date) && !isNaN(date)) {
1977                     selected = new Date(date);
1978                 } else {
1979                     if (!selected) {
1980                         selected = new Date();
1981                     }
1982                 }
1983
1984                 if (selected) {
1985                     var currentMode = datepickerCtrl.modes[mode],
1986                         data = currentMode.getVisibleDates(selected);
1987                     scope.rows = split(data.objects, currentMode.split);
1988                     var flag = false;
1989                     var startFlag = false;
1990                     var firstSelected = false;
1991                     for (var i = 0; i < scope.rows.length; i++) {
1992                         for (var j = 0; j < scope.rows[i].length; j++) {
1993
1994                             if (scope.rows[i][j].label === "1" && !firstSelected) {
1995                                 firstSelected = true;
1996                                 var firstDay = scope.rows[i][j];
1997                             }
1998
1999                             if (scope.rows[i][j].selected === true) {
2000                                 flag = true;
2001                                 break;
2002                             }
2003                         }
2004                         if (flag) {
2005                             break;
2006                         }
2007                     }
2008                     if (!flag) {
2009                         firstDay.firstFocus = true;
2010                     }
2011
2012                     scope.labels = data.labels || [];
2013                     scope.title = data.title;
2014
2015                     datepickerCtrl.updatePosition(b2bDatepickerPopupTemplate);
2016                 }
2017             }
2018
2019             scope.select = function (date) {
2020                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
2021                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({
2022                         date: dt
2023                     }) !== false)) {
2024                     scope.currentDate = dt;
2025                     element[0].value = $filter('date')(dt, "MM/dd/yyyy");
2026                     ngModel.$setValidity('outOfRange', true);
2027                     if (angular.isNumber(scope.collapseWait)) {
2028                         $timeout(function () {
2029                             scope.isOpen = false;
2030                             toggleCalendar(scope.isOpen);
2031                         }, scope.collapseWait);
2032                     } else {
2033                         scope.isOpen = false;
2034                         toggleCalendar(scope.isOpen);
2035                     }
2036                 }
2037             };
2038
2039             scope.move = function (direction,$event) {
2040                 var step = datepickerCtrl.modes[mode].step;
2041                 selected.setDate(1);
2042                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));
2043                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));
2044                 refill();
2045
2046                 $timeout(function () {
2047                     trapFocusInElement();
2048                     handleTabEvent();
2049                 }, 100);
2050
2051                 $event.preventDefault();
2052                 $event.stopPropagation();
2053             };
2054
2055             scope.trapFocus = function () {
2056                 $timeout(function () {
2057                     trapFocusInElement();
2058                 }, 100);
2059             };
2060
2061             scope.$watch('currentDate', function (value) {
2062                 if (angular.isDefined(value) && value !== null) {
2063                     refill(value);
2064                 } else {
2065                     refill();
2066                 }
2067                 ngModel.$setViewValue(value);
2068             });
2069
2070             ngModel.$render = function () {
2071                 scope.currentDate = ngModel.$viewValue;
2072             };
2073
2074             var stringToDate = function (value) {
2075                 if (!isNaN(new Date(value))) {
2076                     value = new Date(value);
2077                 }
2078                 return value;
2079             };
2080             ngModel.$formatters.unshift(stringToDate);
2081         }
2082     };
2083 }])
2084
2085
2086 .directive('b2bDatepickerGroup', [function () {
2087     return {
2088         restrict: 'EA',
2089         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2090             this.$$headers = [];
2091             this.$$footers = [];
2092             this.registerDatepickerScope = function (datepickerScope) {
2093                 datepickerScope.headers = this.$$headers;
2094                 datepickerScope.footers = this.$$footers;
2095             };
2096         }],
2097         link: function (scope, elem, attr, ctrl) {}
2098     };
2099 }])
2100
2101 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {
2102     return {
2103         restrict: 'A',
2104         require: 'ngModel',
2105         link: function (scope, elem, attr, ctrl) {
2106             var b2bFormatDate = "";
2107             attr.$observe('b2bFormatDate', function (value) {
2108                 b2bFormatDate = value;
2109             });
2110             var dateToString = function (value) {
2111                 if (!isNaN(new Date(value))) {
2112                     return dateFilter(new Date(value), b2bFormatDate);
2113                 }
2114                 return value;
2115             };
2116             ctrl.$formatters.unshift(dateToString);
2117         }
2118     };
2119 }])
2120
2121 .directive('b2bDatepickerHeader', [function () {
2122     return {
2123         restrict: 'EA',
2124         require: '^b2bDatepickerGroup',
2125         transclude: true,
2126         replace: true,
2127         template: '',
2128         compile: function (elem, attr, transclude) {
2129             return function link(scope, elem, attr, ctrl) {
2130                 if (ctrl) {
2131                     ctrl.$$headers.push(transclude(scope, function () {}));
2132                 }
2133                 elem.remove();
2134             };
2135         }
2136     };
2137 }])
2138
2139 .directive('b2bDatepickerFooter', [function () {
2140     return {
2141         restrict: 'EA',
2142         require: '^b2bDatepickerGroup',
2143         transclude: true,
2144         replace: true,
2145         template: '',
2146         compile: function (elem, attr, transclude) {
2147             return function link(scope, elem, attr, ctrl) {
2148                 if (ctrl) {
2149                     ctrl.$$footers.push(transclude(scope, function () {}));
2150                 }
2151                 elem.remove();
2152             };
2153         }
2154     };
2155 }]);
2156 /**
2157  * @ngdoc directive
2158  * @name Forms.att:checkboxes
2159  *
2160  * @description
2161  *  <file src="src/checkboxes/docs/readme.md" />
2162  * @usage
2163  * See demo section
2164  * @example
2165  <example module="b2b.att">
2166  <file src="src/checkboxes/docs/demo.html" />
2167  <file src="src/checkboxes/docs/demo.js" />
2168  </example>
2169  */
2170 angular.module('b2b.att.checkboxes', ['b2b.att.utilities'])
2171 .directive('b2bSelectGroup', [function (){
2172         return {
2173             restrict: 'A',
2174             require: 'ngModel',
2175             scope: {
2176                 checkboxes: "="
2177             },
2178             link: function (scope, elem, attr, ctrl) {
2179                 elem.bind('change', function () {
2180                     var isChecked = elem.prop('checked');
2181                     angular.forEach(scope.checkboxes, function (item) {
2182                         item.isSelected = isChecked;
2183                     });
2184                     scope.$apply();
2185                 });
2186                 scope.$watch('checkboxes', function () {
2187                     var setBoxes = 0;
2188                     if(scope.checkboxes === undefined) {
2189                         return;
2190                     }
2191                     angular.forEach(scope.checkboxes, function (item) {
2192                         if (item.isSelected) {
2193                             setBoxes++; 
2194                         } 
2195                     });
2196                     elem.prop('indeterminate', false);
2197                     if ( scope.checkboxes !==undefined && setBoxes === scope.checkboxes.length && scope.checkboxes.length > 0) { 
2198                         ctrl.$setViewValue(true); 
2199                         elem.removeClass('indeterminate');
2200                     } else if (setBoxes === 0) { 
2201                        ctrl.$setViewValue(false); 
2202                        elem.removeClass('indeterminate');
2203                     } else { 
2204                         ctrl.$setViewValue(false); 
2205                         elem.addClass('indeterminate');
2206                         elem.prop('indeterminate', true); 
2207                     }
2208                     ctrl.$render();
2209                 }, true);
2210             }
2211         };
2212     }]);
2213 /**
2214  * @ngdoc directive
2215  * @name Misc.att:coachmark
2216  *
2217  * @description
2218  * <file src="src/coachmark/docs/readme.md" />
2219  *
2220  * @usage
2221  *
2222 <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>
2223
2224  * @example
2225     <section id="code">   
2226         <b>HTML + AngularJS</b>
2227         <example module="b2b.att">
2228             <file src="src/coachmark/docs/demo.html" />
2229             <file src="src/coachmark/docs/demo.js" />
2230         </example>
2231     </section>
2232  */
2233
2234 angular.module('b2b.att.coachmark', ['b2b.att.utilities','b2b.att.position'])
2235         
2236         .directive('b2bCoachmark', ['$document', '$compile', '$position', '$timeout', 'b2bViewport', 'keymap', function($document, $compile, $position, $timeout, b2bViewport, keymap) {
2237         return {
2238             restrict: 'A',
2239                          scope: {
2240                                 coachmarks: '=',
2241                                 coachmarkIndex: '=',
2242                                 startCoachmarkCallback: '&',
2243                                 endCoachmarkCallback: '&',
2244                                 actionCoachmarkCallback: '&'
2245                         },
2246             link: function (scope, element, attrs, ctrl) {
2247                                 var coachmarkItems = scope.coachmarks;
2248                                 var body = $document.find('body').eq(0);
2249                                 var coackmarkJqContainer;
2250                                 var coackmarkContainer;
2251                                 var coachMarkElement;
2252                                 var backdropjqLiteEl;
2253                                 var coachmarkHighlight;
2254                                 var initaitedCoachmark = false;
2255                                 scope.coackmarkElPos ={
2256                                         'top':'',
2257                                         'left':''
2258                                 };
2259                                 
2260                                 scope.currentCoachmark = {};
2261                                 
2262                                 
2263                 var coachmarkBackdrop = function(){
2264                                         backdropjqLiteEl = angular.element('<div class="b2b-modal-backdrop fade in hidden-by-modal"></div>');
2265                                         body.append(backdropjqLiteEl);
2266
2267                                         backdropjqLiteEl.bind('click', function() {
2268                                                 scope.closeCoachmark();
2269                                                 scope.$apply();
2270                                         });
2271                                 };
2272                                 
2273                                 
2274                                 scope.closeButtonFocus = function(){
2275                                         if(document.getElementsByClassName('b2b-coachmark-header').length >0){
2276                                                 document.getElementsByClassName('b2b-coachmark-header')[0].scrollLeft = 0;
2277                                                 document.getElementsByClassName('b2b-coachmark-header')[0].scrollTop = 0;
2278                                         }
2279                                 }
2280
2281                                 scope.actionCoachmark = function(action){
2282                                         scope.actionCoachmarkCallback({
2283                                                 'action':action
2284                                         })
2285                                 };
2286                                 
2287                                 scope.closeCoachmark = function(){
2288                                         initaitedCoachmark = false;
2289                                         backdropjqLiteEl.remove();      
2290                                         coackmarkContainer.remove();
2291                                         coachmarkHighlight.remove();
2292                                         if(coachMarkElement !== undefined && coachMarkElement !==""){
2293                                                 coachMarkElement.removeClass('b2b-coachmark-label')
2294                                         }
2295                                         if (angular.isFunction(scope.endCoachmarkCallback)){
2296                                                 scope.endCoachmarkCallback();   
2297                                         }
2298                                         element[0].focus();
2299                                 }
2300
2301                                 var realStyle = function(_elem, _style) {
2302                                     var computedStyle;
2303                                     if ( typeof _elem.currentStyle != 'undefined' ) {
2304                                         computedStyle = _elem.currentStyle;
2305                                     } else {
2306                                         computedStyle = document.defaultView.getComputedStyle(_elem, null);
2307                                     }
2308
2309                                     return _style ? computedStyle[_style] : computedStyle;
2310                                 };
2311
2312                                 var copyComputedStyle = function(src, dest) {
2313                                     var s = realStyle(src);
2314                                     for ( var i in s ) {
2315                                         // Do not use `hasOwnProperty`, nothing will get copied
2316                                         if ( typeof i == "string" && i != "cssText" && !/\d/.test(i) && i.indexOf('webkit') !== 0 ) {
2317                                             // The try is for setter only properties
2318                                             try {
2319                                                 dest.style[i] = s[i];
2320                                                 // `fontSize` comes before `font` If `font` is empty, `fontSize` gets
2321                                                 // overwritten.  So make sure to reset this property. (hackyhackhack)
2322                                                 // Other properties may need similar treatment
2323                                                 if ( i == "font" ) {
2324                                                     dest.style.fontSize = s.fontSize;
2325                                                 }
2326                                             } catch (e) {}
2327                                         }
2328                                     }
2329                                 };
2330                                 
2331                                 function showCoachmark(targetElement) {
2332
2333                                         scope.currentCoachmark = targetElement;
2334                                         if(coachMarkElement !== undefined && coachMarkElement !==""){
2335                                                 coachMarkElement.removeClass('b2b-coachmark-label')
2336                                                 coackmarkContainer.remove();
2337                                                 coachmarkHighlight.remove();
2338                                         }
2339                                         coachMarkElement = angular.element(document.querySelector(targetElement.elementId));
2340                                         
2341                                         var     elementPosition = $position.offset(coachMarkElement);
2342                                         
2343                                         coachmarkHighlight = angular.element('<div class="b2b-coachmark-highlight"></div><div class="b2b-coachmark-highlight b2b-coachmark-highlight-mask"></div>');
2344                                         coachmarkHighlight.css({
2345                                                 'width': (elementPosition.width + 25) +'px',
2346                                                 'top': (elementPosition.top -10) + 'px',
2347                                                 'left': (elementPosition.left - 10) + 'px',
2348                                                 'height': (elementPosition.height + 20) +'px'
2349                                         });
2350                                         if(targetElement.cloneHtml){
2351                                                 var copy = coachMarkElement[0].cloneNode(true);
2352                                                 copy.id = "b2b-unique-"+targetElement.elementId.slice(1);
2353                                                 copyComputedStyle(coachMarkElement[0],copy);
2354                                                 var copychildNodes = copy.childNodes;
2355                                                 var coachmarkChildNodes = coachMarkElement[0].childNodes;
2356                                                 for(i=0;i<copychildNodes.length;i++){
2357                                                         if(copychildNodes[i].nodeType === '3'){
2358                                                                 copyComputedStyle(coachmarkChildNodes[i],copychildNodes[i])
2359                                                         }
2360                                                 }
2361                                                 coachmarkHighlight[0].appendChild(copy); // IE11 only supports appendChild, not append
2362                                         }else{
2363                                                 coachMarkElement.addClass('b2b-coachmark-label');
2364                                         }
2365                                         
2366                                         body.append(coachmarkHighlight);
2367                                         
2368                                         scope.coackmarkElPos.top = (elementPosition.top + elementPosition.height + 32) + 'px';
2369                                         scope.coackmarkElPos.left = (elementPosition.left - 158 + elementPosition.width / 2 ) + 'px';
2370                                         coackmarkJqContainer = angular.element('<div b2b-coachmark-container b2b-trap-focus-inside-element="true"></div>');
2371                                         coackmarkContainer = $compile(coackmarkJqContainer)(scope);
2372                                         body.append(coackmarkContainer);
2373                                         
2374                                         
2375                                         $timeout(function () {
2376                                                 var currentCoachmarkContainer = document.getElementsByClassName('b2b-coachmark-container')[0];
2377                                                 currentCoachmarkContainer.focus();
2378
2379                                                 newElem = angular.element(currentCoachmarkContainer);
2380                                                 newElem.bind('keydown', function (e) {
2381                                                         if(e.keyCode == keymap.KEY.TAB){
2382                                                             if(e.shiftKey) {
2383                                                                 if(e.target.className === 'b2b-coachmark-container'){
2384                                                                         e.preventDefault();
2385                                                                         e.stopPropagation();
2386                                                                     }
2387                                                             }
2388                                                         }
2389                                                 });
2390                                                 var coachmarkHeight = window.getComputedStyle(currentCoachmarkContainer).height.split('px')[0];
2391                                                 var newOffsetHeight = Math.round(elementPosition.top) - elementPosition.height;
2392                                                 
2393                                                 // We need a slight offset to show the lightboxed item
2394                                                 if(!targetElement.cloneHtml){
2395                                                         TweenLite.to(window, 2, {scrollTo:{x: (scope.coackmarkElPos.left.split('px')[0] - 100), y: newOffsetHeight-200}});
2396                                                 }
2397                                         }, 200);
2398                                 }
2399                                 
2400                                 element.bind('click', function (e) {
2401                                         initaitedCoachmark = true;
2402                     
2403                                         scope.$watch('coachmarkIndex', function () {
2404                                                 if(initaitedCoachmark === true){
2405                             if(scope.coachmarkIndex === -1){
2406                                                                 scope.closeCoachmark();
2407                                                         }else{
2408                                 findAvailableCoachmark(scope.coachmarkIndex);
2409                                 showCoachmark(scope.coachmarks[scope.coachmarkIndex]);
2410                                                         }
2411                                                 }
2412                                         });
2413                                         coachmarkBackdrop();
2414                     var findAvailableCoachmark = function(index){
2415                         if(index === -1){
2416                                 scope.coachmarkIndex = 0;
2417                         } else if(!angular.isDefined(scope.coachmarks[index]) || angular.element(document.querySelector(scope.coachmarks[index].elementId)).length === 0){
2418                             findAvailableCoachmark(index-1);
2419                         } else {
2420                             scope.coachmarkIndex = index;
2421                         }
2422                     }
2423                                         if (angular.isFunction(scope.startCoachmarkCallback)){
2424                                                 scope.startCoachmarkCallback(); 
2425                                         }
2426                     findAvailableCoachmark(scope.coachmarkIndex);
2427                     showCoachmark(scope.coachmarks[scope.coachmarkIndex]);
2428                     
2429                                         $document.bind('keydown', function (evt) {
2430                                                 if (evt.which === 27 && initaitedCoachmark) {
2431                                                         scope.closeCoachmark();
2432                                                         scope.$apply(); 
2433                                                 }
2434                                         });
2435                                 });
2436                                 //performance technique to ensure scroll event doesn't cause lag
2437                                 var throttle = function(type, name, obj) {
2438                                 obj = obj || window; 
2439                                 var running = false; 
2440                                 var func = function() { 
2441                                     if (running) { return; } 
2442                                     running = true; 
2443                                      requestAnimationFrame(function() { 
2444                                         obj.dispatchEvent(new CustomEvent(name)); 
2445                                         running = false; 
2446                                     }); 
2447                                 }; 
2448                                 obj.addEventListener(type, func); 
2449                             };
2450                          
2451                             scope.viewportWidth = b2bViewport.viewportWidth(); 
2452                             /* init - you can init any event */ 
2453                             throttle("resize", "optimizedResize"); 
2454                             window.addEventListener("optimizedResize", function() {
2455                                 if(initaitedCoachmark){
2456                         showCoachmark(scope.coachmarks[scope.coachmarkIndex]);
2457                                         scope.viewportWidth = b2bViewport.viewportWidth(); 
2458                                         scope.$digest();
2459                                 }
2460                             });
2461             }
2462         };
2463     }])
2464         .directive('b2bCoachmarkContainer', ['$document', '$position', function($document, $position) {
2465                 return {
2466                         restrict: 'A',
2467                         transclude: true,
2468             replace: true,
2469                         templateUrl: 'b2bTemplate/coachmark/coachmark.html',
2470                         link: function (scope, element, attrs, ctrl) {
2471                                                         
2472                         }
2473                 };      
2474         }]);
2475         
2476
2477 /** 
2478  * @ngdoc directive 
2479  * @name Template.att:Configuration Section 
2480  * 
2481  * @description 
2482  *  <file src="src/configurationSection/docs/readme.md" /> 
2483  * 
2484  * @example 
2485  *  <section id="code"> 
2486         <b>HTML + AngularJS</b> 
2487         <example module="b2b.att"> 
2488             <file src="src/configurationSection/docs/demo.html" /> 
2489             <file src="src/configurationSection/docs/demo.js" /> 
2490        </example> 
2491     </section>    
2492  * 
2493  */
2494 angular.module('b2b.att.configurationSection', [])
2495   
2496 /** 
2497  * @ngdoc directive 
2498  * @name Template.att:Directory Listing 
2499  * 
2500  * @description 
2501  *  <file src="src/directoryListingTemplate/docs/readme.md" /> 
2502  * 
2503  * @example 
2504  *  <section id="code"> 
2505         <b>HTML + AngularJS</b> 
2506         <example module="b2b.att"> 
2507             <file src="src/directoryListingTemplate/docs/demo.html" /> 
2508             <file src="src/directoryListingTemplate/docs/demo.js" /> 
2509        </example> 
2510     </section>    
2511  * 
2512  */
2513 angular.module('b2b.att.directoryListingTemplate', [])
2514   
2515 /**
2516  * @ngdoc directive
2517  * @name Forms.att:dropdowns
2518  *
2519  * @description
2520  *  <file src="src/dropdowns/docs/readme.md" />
2521  * @usage
2522  *
2523  * @example
2524    <section id="code">
2525     <example module="b2b.att">
2526      <file src="src/dropdowns/docs/demo.html" />
2527      <file src="src/dropdowns/docs/demo.js" />
2528     </example>
2529    </section>
2530  */
2531 angular.module('b2b.att.dropdowns', ['b2b.att.utilities', 'b2b.att.position', 'ngSanitize'])
2532
2533 .constant('b2bDropdownConfig', {
2534     prev: '37,38',
2535     next: '39,40',
2536     menuKeyword: 'menu',
2537     linkMenuKeyword: 'link-menu',
2538     largeKeyword: 'large',
2539     smallKeyword: 'small'
2540 })  
2541
2542 .directive("b2bDropdown", ['$timeout', '$compile', '$templateCache', 'b2bUserAgent', 'b2bDropdownConfig', '$position', function ($timeout, $compile, $templateCache, b2bUserAgent, b2bDropdownConfig, $position) {
2543     return {
2544         restrict: 'A',
2545         scope: true,
2546         require: 'ngModel',
2547         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2548             scope.isInputDropdown = true;
2549             scope.placeHoldertext = attr.placeholderText;
2550             if (attr.type) {
2551                 if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1 || attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {
2552                     scope.isInputDropdown = false;
2553                     if (attr.type.indexOf(b2bDropdownConfig.linkMenuKeyword) > -1) {
2554                         scope.dropdownType = b2bDropdownConfig.linkMenuKeyword;
2555                     } else if (attr.type.indexOf(b2bDropdownConfig.menuKeyword) > -1) {
2556                         scope.dropdownType = b2bDropdownConfig.menuKeyword;
2557                     }
2558                 }
2559                 if (attr.type.indexOf(b2bDropdownConfig.largeKeyword) > -1) {
2560                     scope.dropdownSize = b2bDropdownConfig.largeKeyword;
2561                 } else if (attr.type.indexOf(b2bDropdownConfig.smallKeyword) > -1) {
2562                     scope.dropdownSize = b2bDropdownConfig.smallKeyword;
2563                 }
2564             }
2565
2566             scope.labelText = attr.labelText;
2567
2568             scope.setBlur = function () {
2569                 scope.setTouched();
2570             };
2571
2572             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2573                 var formCtrl = elem.controller('form');
2574                 scope.setNgModelController = function (name, ngModelCtrl) {
2575                     if (name && formCtrl && ngModelCtrl) {
2576                         formCtrl[name] = ngModelCtrl;
2577                     }
2578                 };
2579                 scope.setOptionalCta = function (optionalCta) {
2580                     scope.optionalCta = optionalCta;
2581                 };
2582                 var innerHtml = angular.element('<div></div>').append(elem.html());
2583                 innerHtml = ($compile(innerHtml)(scope)).html();
2584                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownDesktop.html'));
2585                 template.find('ul').eq(0).append(innerHtml);
2586                 template = $compile(template)(scope);
2587                 elem.replaceWith(template);
2588             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2589                 elem.css({
2590                     'opacity': '0',
2591                     'filter': 'alpha(opacity=0)'
2592                 });
2593                 elem.addClass('awd-select isWrapped');
2594                 elem.wrap('<span class="selectWrap"></span>');
2595                 var cover = angular.element('<span aria-hidden="true"><i class="icon-primary-down" aria-hidden="true"></i></span>');
2596                 elem.parent().append(cover);
2597                 elem.parent().append('<i class="icon-primary-down" aria-hidden="true"></i>');
2598                 var set = function () {
2599                     var sel = elem[0] ? elem[0] : elem;
2600                     var selectedText = "";
2601                     var selIndex = sel.selectedIndex;
2602                     if (typeof selIndex !== 'undefined') {
2603                         selectedText = sel.options[selIndex].text;
2604                     }
2605                     cover.text(selectedText).append('<i class="icon-primary-down" aria-hidden="true"></i>');
2606                 };
2607                 var update = function (value) {
2608                     $timeout(set, 100);
2609                 };
2610
2611                 if (attr.ngModel) {
2612                     scope.$watch(attr.ngModel, function (newVal, oldVal) {
2613                         update();
2614                     });
2615                 }
2616                 elem.bind('keyup', function (ev) {
2617                     if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2618                         return;
2619                     }
2620                     set();
2621                 });
2622             }
2623
2624         }],  
2625         link: function (scope, elem, attr, ctrl) {
2626             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2627                 scope.updateModel = function () {
2628                     ctrl.$setViewValue(scope.currentSelected.value);
2629                     if (scope.dropdownRequired && scope.currentSelected.value === '') {
2630                         scope.setRequired(false);
2631                     } else {
2632                         scope.setRequired(true);
2633                     }
2634
2635                     if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2636                         $timeout(function () {
2637                             scope.appendCaretPositionStyle();
2638                         }, 100);
2639                     }
2640                 };
2641                 ctrl.$render = function () {
2642
2643                 $timeout(function () {
2644
2645                         if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && (angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '')) {
2646                             scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2647                         } else if ((angular.isUndefined(scope.placeHoldertext) || scope.placeHoldertext == '') && ctrl.$viewValue !== '' ) {
2648                             scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2649                         } else if ((angular.isUndefined(ctrl.$viewValue) || ctrl.$viewValue == '') && scope.placeHoldertext !== '' )  {
2650                             scope.currentSelected.text = scope.placeHoldertext;
2651                             ctrl.$setViewValue(scope.placeHoldertext);
2652                         } else {
2653                             scope.dropdownLists[ctrl.$viewValue] && scope.dropdownLists[ctrl.$viewValue][0].updateDropdownValue();
2654                         }
2655
2656                     }, 100);
2657                 };
2658
2659                 scope.disabled = false;
2660                 scope.dropdownName = attr.name;
2661                 scope.dropdownId = attr.id;
2662                 scope.labelId = attr.ariaLabelledby;
2663                 scope.dropdownDescribedBy = attr.ariaDescribedby;
2664                 if (attr.required) {
2665                     scope.dropdownRequired = true;
2666                 } else {
2667                     scope.dropdownRequired = false;
2668                 }
2669                 elem.removeAttr('name');
2670                 elem.removeAttr('id');
2671                 scope.$parent.$watch(attr.ngDisabled, function (val) {
2672                     scope.disabled = val;
2673                 });
2674             }
2675         }
2676     };
2677 }])
2678
2679 .directive("b2bDropdownToggle", ['$document', '$documentBind', '$isElement', 'b2bDropdownConfig', 'keymap', 'b2bUtilitiesConfig', '$timeout', '$position', function ($document, $documentBind, $isElement, b2bDropdownConfig, keymap, b2bUtilitiesConfig, $timeout, $position) {
2680     return {
2681         restrict: 'A',
2682         require: '?^b2bKey',
2683         link: function (scope, elem, attr, ctrl) {
2684             scope.appendCaretPositionStyle = function () {
2685                 while (document.querySelector('style.b2bDropdownCaret')) {
2686                     document.querySelector('style.b2bDropdownCaret').remove();
2687                 };
2688                 var caretPosition = $position.position(elem).width - 26;
2689                 if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2690                     var template = angular.element('<style class="b2bDropdownCaret" type="text/css">.linkSelectorModule .active+.moduleWrapper:before {left: ' + caretPosition + 'px;}</style>');
2691                     $document.find('head').append(template);
2692                 }
2693             };
2694
2695             if (scope.isInputDropdown && (scope.labelText !== undefined)) {
2696                 elem.attr('aria-label', scope.labelText);
2697             }
2698
2699             scope.toggleFlag = false;
2700             scope.dropdownLists = {};
2701             scope.dropdownListValues = [];
2702             scope.dropdown = {
2703                 totalIndex: -1
2704             };
2705             scope.currentSelected = {
2706                 value: '',
2707                 text: '',
2708                 label: '',
2709                 index: -1
2710             };
2711             scope.dropdownTextList = [];
2712             var searchString = '';
2713
2714             scope.removeItem = function(value){
2715                 delete scope.dropdownLists[value];
2716                 var index = scope.dropdownListValues.indexOf(value);
2717                 scope.dropdownListValues.splice(index,1);
2718                 scope.dropdownTextList=[];
2719                 scope.dropdown.totalIndex = scope.dropdownListValues.length-1; 
2720             };
2721             var getDropdownText = function(){
2722                 var dropdownItems = elem.parent().find('ul').children();
2723                 var count = dropdownItems.length;
2724                 for(var i=0;i<count;i++){
2725                     scope.dropdownTextList.push(dropdownItems.eq(i).text());
2726                 }
2727             };
2728             var searchElement = function (searchExp) {
2729                  if(scope.dropdownTextList.length ==0){
2730                     getDropdownText ();
2731                 }
2732                 var regex = new RegExp("^" + searchExp, "i");
2733                 var position = scope.dropdownTextList.regexIndexOf(regex, scope.currentSelected.index + 1, true);
2734                 if (position > -1) {
2735                     return position;
2736                 }
2737                 return undefined;
2738             };
2739             var startTimer = function (time) {
2740                 if (searchString === '') {
2741                     $timeout(function () {
2742                         searchString = '';
2743                     }, time);
2744                 }
2745             };
2746             scope.toggleDropdown = function (toggleFlag) {
2747                 if (!scope.disabled) {
2748                     if (angular.isDefined(toggleFlag)) {
2749                         scope.toggleFlag = toggleFlag;
2750                     } else {
2751                         scope.toggleFlag = !scope.toggleFlag;
2752                     }
2753                     if (!scope.toggleFlag) {
2754                         if (scope.isInputDropdown) {
2755                             elem.parent().find('input')[0].focus();
2756                         } else {
2757                             elem.parent().find('button')[0].focus();
2758                         }
2759                     } else {
2760                         scope.dropdown.highlightedValue = scope.currentSelected.value;
2761                         if (ctrl && ctrl.enableSearch) {
2762                             if (angular.isDefined(scope.dropdownLists[scope.currentSelected.value])) {
2763                                 ctrl.resetCounter(scope.dropdownLists[scope.currentSelected.value][2]);
2764                             }
2765                         }
2766                         $timeout(function () {
2767                             if(scope.dropdownLists[scope.currentSelected.value] !== undefined){
2768                                 (scope.dropdownLists[scope.currentSelected.value][1])[0].focus();
2769                             } else {
2770                                 if (scope.isInputDropdown) {
2771                                     elem.parent().find('input')[0].focus();
2772                                 } else {
2773                                     elem.parent().find('button')[0].focus();
2774                                 }
2775                             }
2776                         }, 100);
2777                         if (scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) {
2778                             scope.appendCaretPositionStyle();
2779                         }
2780                     }
2781                 }
2782             };
2783
2784             elem.bind('keydown', function (ev) {
2785                 if (!ev.keyCode) {
2786                     if (ev.which) {
2787                         ev.keyCode = ev.which;
2788                     } else if (ev.charCode) {
2789                         ev.keyCode = ev.charCode;
2790                     }
2791                 }
2792                 if (!scope.toggleFlag) {
2793                     if (ev.keyCode) {
2794                         var currentIndex = scope.currentSelected.index;
2795                         if (ev.keyCode === keymap.KEY.DOWN) {
2796                             scope.toggleDropdown(true);
2797                             ev.preventDefault();
2798                             ev.stopPropagation();
2799                         } else if (b2bDropdownConfig.prev.split(',').indexOf(ev.keyCode.toString()) > -1) {
2800                             angular.isDefined(scope.dropdownListValues[currentIndex - 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex - 1]][0].updateDropdownValue() : angular.noop();
2801                             ev.preventDefault();
2802                             ev.stopPropagation();
2803                         } else if (b2bDropdownConfig.next.split(',').indexOf(ev.keyCode.toString()) > -1) {
2804                             angular.isDefined(scope.dropdownListValues[currentIndex + 1]) ? scope.dropdownLists[scope.dropdownListValues[currentIndex + 1]][0].updateDropdownValue() : angular.noop();
2805                             ev.preventDefault();
2806                             ev.stopPropagation();
2807                         } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {
2808                             startTimer(b2bUtilitiesConfig.searchTimer);
2809                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');
2810                             var position = searchElement(searchString);
2811                             angular.isDefined(scope.dropdownListValues[position]) ? scope.dropdownLists[scope.dropdownListValues[position]][0].updateDropdownValue() : angular.noop();
2812                             ev.preventDefault();
2813                             ev.stopPropagation();
2814                         }
2815                     }
2816                 } else {
2817                     if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {
2818                         scope.toggleDropdown(false);
2819                         ev.preventDefault();
2820                         ev.stopPropagation();
2821                     } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2822                         scope.toggleDropdown(false);
2823                         ev.preventDefault();
2824                         ev.stopPropagation();
2825                     }
2826                 }
2827                 scope.$apply(); // TODO: Move this into each block to avoid expensive digest cycles
2828             });
2829             var outsideClick = function (e) {
2830                 var isElement = $isElement(angular.element(e.target), elem.parent(), $document);
2831                 if (!isElement) {
2832                     scope.toggleDropdown(false);
2833                     scope.$apply();
2834                 }
2835             };
2836             $documentBind.click('toggleFlag', outsideClick, scope);
2837             $documentBind.touch('toggleFlag', outsideClick, scope);
2838         }
2839     };
2840 }])
2841
2842 .directive("b2bDropdownGroup", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {
2843     return {
2844         restrict: 'A',
2845         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2846             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2847                 var innerHtml = angular.element('<div></div>').append(elem.html());
2848                 innerHtml = ($compile(innerHtml)(scope)).html();
2849                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html'));
2850                 template.attr('ng-repeat', attr.optGroupRepeat);
2851                 template.attr('label', elem.attr('label'));
2852                 template.find('ul').append(innerHtml);
2853                 elem.replaceWith(template);
2854             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2855                 var template = angular.element(elem.prop('outerHTML'));
2856                 template.attr('ng-repeat', attr.optGroupRepeat);
2857                 template.removeAttr('b2b-dropdown-group');
2858                 template.removeAttr('opt-group-repeat');
2859                 template = $compile(template)(scope);
2860                 elem.replaceWith(template);
2861             }
2862         }]
2863     };
2864 }])
2865
2866 .directive("b2bDropdownGroupDesktop", [function () {
2867     return {
2868         restrict: 'A',
2869         scope: true,
2870         link: function (scope, elem, attr, ctrl) {
2871             scope.groupHeader = attr.label;
2872         }
2873     };
2874 }])
2875
2876 .directive("b2bDropdownList", ['$compile', '$templateCache', 'b2bUserAgent', function ($compile, $templateCache, b2bUserAgent) {
2877     return {
2878         restrict: 'A',
2879         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {           
2880             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2881                 var innerHtml = angular.element('<div></div>').append(elem.html());
2882                 innerHtml = ($compile(innerHtml)(scope)).html();
2883                 var template = angular.element($templateCache.get('b2bTemplate/dropdowns/b2bDropdownListDesktop.html'));
2884                 template.attr('ng-repeat', attr.optionRepeat);
2885                 template.attr('value', elem.attr('value'));
2886                 template.attr('search-key', elem.text());
2887                 if (elem.attr('aria-describedby')){
2888                     template.attr('aria-describedby', attr.ariaDescribedby);
2889                 }
2890                 if (elem.attr('imgsrc')) {
2891                     if (elem.attr('imgalt')) {
2892                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt="' + elem.attr('imgalt') + '"/>');
2893                     } else {
2894                         template.append('<img role="presentation" ng-src="' + elem.attr('imgsrc') + '" alt=""/>');
2895                     }
2896                 }
2897                 template.append(innerHtml);
2898                 elem.replaceWith(template);
2899             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2900                 var template = angular.element(elem.prop('outerHTML'));
2901                 template.attr('ng-repeat', attr.optionRepeat);
2902                 if (elem.attr('aria-describedby')){
2903                     template.attr('aria-describedby', attr.ariaDescribedby);
2904                 }
2905                 template.removeAttr('b2b-dropdown-list');
2906                 template.removeAttr('option-repeat');
2907                 template = $compile(template)(scope);
2908                 elem.replaceWith(template);
2909             }
2910         }]
2911     };
2912 }])
2913
2914 .directive("b2bDropdownListDesktop", ['$sce', 'keymap', 'b2bDropdownConfig', function ($sce, keymap, b2bDropdownConfig) {
2915     return {
2916         restrict: 'A',
2917         scope: true,
2918
2919         link: function (scope, elem, attr, ctrl) {
2920             var dropdownListValue = scope.dropdownListValue = attr.value;
2921             scope.dropdown.totalIndex++;
2922             var dropdownListIndex = scope.dropdown.totalIndex;
2923             scope.dropdownListValues.push(dropdownListValue);
2924             scope.dropdownLists[dropdownListValue] = [];
2925             scope.dropdownLists[dropdownListValue][0] = scope;
2926             scope.dropdownLists[dropdownListValue][1] = elem;
2927             scope.dropdownLists[dropdownListValue][2] = dropdownListIndex;
2928             scope.$parent.$parent.dropdownTextList=[];                                
2929             scope.updateDropdownValue = function () {
2930                 scope.currentSelected.value = dropdownListValue;
2931                 if (scope.isInputDropdown) {
2932                     scope.currentSelected.text = elem.text();
2933                     scope.currentSelected.label = elem.text();
2934                 } else if ((scope.dropdownType === b2bDropdownConfig.linkMenuKeyword) || (scope.dropdownType === b2bDropdownConfig.menuKeyword && scope.dropdownSize === b2bDropdownConfig.smallKeyword)) {
2935                     scope.currentSelected.text = dropdownListValue;
2936                     scope.currentSelected.label = dropdownListValue;
2937                 } else if (scope.dropdownType === b2bDropdownConfig.menuKeyword) {
2938                     scope.currentSelected.text = $sce.trustAsHtml(elem.html());
2939                     scope.currentSelected.label = elem.text();
2940                 }
2941                 scope.currentSelected.index = dropdownListIndex;
2942                 scope.updateModel();
2943             };
2944             scope.selectDropdownItem = function () {
2945                 scope.setDirty();
2946                 scope.updateDropdownValue();
2947                 scope.toggleDropdown(false);
2948             };
2949             scope.highlightDropdown = function () {
2950                 scope.dropdown.highlightedValue = dropdownListValue;
2951             };
2952             elem.bind('mouseover', function (ev) {
2953                 elem[0].focus();
2954             });
2955
2956             elem.bind('keydown', function (ev) {
2957                 if (!ev.keyCode) {
2958                     if (ev.which) {
2959                         ev.keyCode = ev.which;
2960                     } else if (ev.charCode) {
2961                         ev.keyCode = ev.charCode;
2962                     }
2963                 }
2964                 if (ev.altKey === true && ev.keyCode === keymap.KEY.UP) {
2965                     scope.toggleDropdown(false);
2966                     ev.preventDefault();
2967                     ev.stopPropagation();
2968                 } else if (ev.keyCode === keymap.KEY.TAB || ev.keyCode === keymap.KEY.ESC) {
2969                     scope.toggleDropdown(false);
2970                     ev.preventDefault();
2971                     ev.stopPropagation();
2972                 }
2973                 scope.$apply();
2974             });
2975             scope.$on('$destroy',function(){
2976                 scope.removeItem(dropdownListValue);
2977             });
2978         }
2979     };
2980 }])
2981
2982 .directive("b2bDropdownRepeat", ['$compile', 'b2bUserAgent', function ($compile, b2bUserAgent) {
2983     return {
2984         restrict: 'A',
2985         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
2986             if ((scope.isInputDropdown && b2bUserAgent.notMobile()) || (!scope.isInputDropdown)) {
2987                 var innerHtml = angular.element('<div></div>').append(elem.html());
2988                 innerHtml = ($compile(innerHtml)(scope)).html();
2989                 var template = angular.element('<div></div>');
2990                 template.attr('ng-repeat', attr.b2bDropdownRepeat);
2991                 template.append(innerHtml);
2992                 elem.replaceWith(template);
2993             } else if (scope.isInputDropdown && b2bUserAgent.isMobile()) {
2994                 angular.noop();
2995             }
2996         }]
2997     };
2998 }])
2999
3000 .directive("b2bDropdownValidation", ['$timeout', function ($timeout) {
3001     return {
3002         restrict: 'A',
3003         require: 'ngModel',
3004         link: function (scope, elem, attr, ctrl) {
3005             $timeout(function () {
3006                 scope.setNgModelController(attr.name, ctrl);
3007             }, 100);
3008             scope.setDirty = function () {
3009                 if (ctrl.$dirty === false) {
3010                     ctrl.$dirty = true;
3011                     ctrl.$pristine = false;
3012                 }
3013             };
3014             scope.setTouched = function () {
3015                 if (ctrl.$touched === false) {
3016                     ctrl.$touched = true;
3017                     ctrl.$pristine = false;
3018                 }
3019             };
3020             scope.setRequired = function (flag) {
3021                 ctrl.$setValidity('required', flag);
3022             };
3023         }
3024     };
3025 }])
3026
3027 .directive('b2bDropdownOptionalCta', [function () {
3028     return {
3029         restrict: 'EA',
3030         transclude: true,
3031         replace: true,
3032         template: '',
3033         compile: function (elem, attr, transclude) {
3034             return function link(scope, elem, attr, ctrl) {
3035                 if (scope.setOptionalCta) {
3036                     scope.setOptionalCta(transclude(scope, function () {}));
3037                 }
3038                 elem.remove();
3039             };
3040         }
3041     };
3042 }]);
3043 /**
3044  * @ngdoc directive
3045  * @name Forms.att:File Upload
3046  *
3047  * @description
3048  *  <file src="src/fileUpload/docs/readme.md" />
3049  *
3050  * @usage
3051  * 
3052 <form id="dragDropFile">                
3053     <div b2b-file-drop file-model="fileModel" on-drop="triggerFileUpload()"  align="center">
3054         <p>
3055             <br>To upload a file, drag & drop it here or 
3056                         <span b2b-file-link file-model="fileModel" on-file-select="triggerFileUpload()" >
3057                                 click here to select from your computer.
3058                         </span><br>
3059         </p>
3060     </div>
3061 </form>
3062  *
3063  * @example
3064  *  <section id="code">
3065         <example module="b2b.att">
3066             <file src="src/fileUpload/docs/demo.html" />
3067             <file src="src/fileUpload/docs/demo.js" />
3068        </example>
3069     </section>
3070  *
3071  */
3072 angular.module('b2b.att.fileUpload', ['b2b.att.utilities'])
3073     .directive('b2bFileDrop', [function() {
3074             return {
3075                 restrict: 'EA',
3076                 scope: {
3077                     fileModel: '=',
3078                     onDrop: '&'
3079                 },
3080                                 controller: ['$scope', '$attrs', function($scope, $attrs) {
3081                     this.onDrop = $scope.onDrop;
3082                 }],
3083                 link: function(scope, element) {
3084                     element.addClass('b2b-dragdrop');
3085                     element.bind(
3086                         'dragover',
3087                         function(e) {
3088                             if (e.originalEvent) {
3089                                 e.dataTransfer = e.originalEvent.dataTransfer;
3090                             }
3091                             e.dataTransfer.dropEffect = 'move';
3092                             // allows us to drop
3093                             if (e.preventDefault) {
3094                                 e.preventDefault();
3095                             }
3096                             element.addClass('b2b-dragdrop-over');
3097                             return false;
3098                         }
3099                     );
3100                     element.bind(
3101                         'dragenter',
3102                         function(e) {
3103                             // allows us to drop
3104                             if (e.preventDefault) {
3105                                 e.preventDefault();
3106                             }
3107                             element.addClass('b2b-dragdrop-over');
3108                             return false;
3109                         }
3110                     );
3111                     element.bind(
3112                         'dragleave',
3113                         function() {
3114                             element.removeClass('b2b-dragdrop-over');
3115                             return false;
3116                         }
3117                     );
3118                     element.bind(
3119                         'drop',
3120                         function(e) {
3121                             // Stops some browsers from redirecting.
3122                             if (e.preventDefault) {
3123                                 e.preventDefault();
3124                             }
3125                             if (e.stopPropagation) {
3126                                 e.stopPropagation();
3127                             }
3128                             if (e.originalEvent) {
3129                                 e.dataTransfer = e.originalEvent.dataTransfer;
3130                             }
3131                             element.removeClass('b2b-dragdrop-over');
3132                             if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
3133                                 scope.fileModel = e.dataTransfer.files[0];
3134                                 scope.$apply();
3135                                 if (angular.isFunction(scope.onDrop)) {
3136                                     scope.onDrop();
3137                                 }
3138                             }
3139                             return false;
3140                         }
3141                     );
3142                 }
3143             };
3144         }])
3145         .directive('b2bFileLink', [function() {
3146             return {
3147                 restrict: 'EA',
3148                 require: '^?b2bFileDrop',
3149                 replace: true,
3150                 transclude: true,
3151                 templateUrl: 'b2bTemplate/fileUpload/fileUpload.html',
3152                 scope: {
3153                     fileModel: '=?',
3154                     onFileSelect: '&'
3155                 },
3156                 controller: ['$scope', function($scope) {
3157                     this.setFileModel = function(fileModel) {
3158                         if ($scope.takeFileModelFromParent) {
3159                             $scope.$parent.fileModel = fileModel;
3160                             $scope.$parent.$apply();
3161                         } else {
3162                             $scope.fileModel = fileModel;
3163                             $scope.$apply();
3164                         }
3165                     };
3166                     this.callbackFunction = function() {
3167                         if (angular.isFunction($scope.onFileSelect)) {
3168                             $scope.onFileSelect();
3169                         }
3170                     };
3171                 
3172                 }],
3173                 link: function(scope, element, attr, b2bFileDropCtrl) {
3174                     scope.takeFileModelFromParent = false;
3175                     if (!(attr.fileModel) && b2bFileDropCtrl) {
3176                         scope.takeFileModelFromParent = true;
3177                     }
3178                     if (!(attr.onFileSelect) && b2bFileDropCtrl) {
3179                         scope.onFileSelect = b2bFileDropCtrl.onDrop;
3180                     }
3181                 }
3182             };
3183         }])
3184         .directive('b2bFileChange', ['$log', '$rootScope', function($log, $rootScope) {
3185             return {
3186                 restrict: 'A',
3187                 require: '^b2bFileLink',
3188                 link: function(scope, element, attr, b2bFileLinkCtrl) {
3189                     element.bind('change', changeFileModel);
3190
3191                     function changeFileModel(e) {
3192                         if (e.target.files && e.target.files.length > 0) {
3193                             b2bFileLinkCtrl.setFileModel(e.target.files[0]);
3194                             b2bFileLinkCtrl.callbackFunction();
3195                         } else {
3196                             var strFileName = e.target.value;
3197                             try {
3198                                 var objFSO = new ActiveXObject("Scripting.FileSystemObject");
3199                                 b2bFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));
3200                                 b2bFileLinkCtrl.callbackFunction();
3201                             } catch (e) {
3202                                 var errMsg = "There was an issue uploading " + strFileName + ". Please try again.";
3203                                 $log.error(errMsg);
3204                                 $rootScope.$broadcast('b2b-file-link-failure', errMsg);
3205                             }
3206                         }
3207                     }
3208                 }
3209             };
3210         }]);
3211 /**
3212  * @ngdoc directive
3213  * @name Navigation.att:filters
3214  *
3215  * @description
3216  *  <file src="src/filters/docs/readme.md" />
3217  *
3218  * @usage
3219  *  <div b2b-filters></div>
3220  *
3221  * @example
3222  *      <section id="code">
3223            <b>HTML + AngularJS</b>
3224             <example module="b2b.att">
3225             <file src="src/filters/docs/demo.html" />
3226             <file src="src/filters/docs/demo.js" />
3227        </example>
3228         </section>
3229  * 
3230  */
3231 angular.module('b2b.att.filters', ['b2b.att.utilities', 'b2b.att.multipurposeExpander'])
3232     .filter('filtersSelectedItemsFilter', [function () {
3233         return function (listOfItemsArray) {
3234
3235             if (!listOfItemsArray) {
3236                 listOfItemsArray = [];
3237             }
3238
3239             var returnArray = [];
3240
3241             for (var i = 0; i < listOfItemsArray.length; i++) {
3242                 for (var j = 0; j < listOfItemsArray[i].filterTypeItems.length; j++) {
3243                     if (listOfItemsArray[i].filterTypeItems[j].selected && !listOfItemsArray[i].filterTypeItems[j].inProgress) {
3244                         returnArray.push(listOfItemsArray[i].filterTypeItems[j]);
3245                     }
3246                 }
3247             }
3248
3249             return returnArray;
3250         };
3251     }]);
3252 /**
3253  * @ngdoc directive
3254  * @name Messages, modals & alerts.att:flyout
3255  *
3256  * @description
3257  *  <file src="src/flyout/docs/readme.md" />
3258  * @example
3259  *  <section id="code">
3260         <example module="b2b.att">
3261             <file src="src/flyout/docs/demo.html" />
3262             <file src="src/flyout/docs/demo.js" />
3263        </example>
3264     </section>
3265  *
3266  */
3267 angular.module('b2b.att.flyout', ['b2b.att.utilities', 'b2b.att.position'])
3268     .directive('b2bFlyout', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {
3269         return {
3270             restrict: 'EA',
3271             transclude: true,
3272             templateUrl: 'b2bTemplate/flyout/flyout.html',
3273             controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
3274                 scope.flyoutOpened = false;
3275                 var contentScope = '';
3276                 var togglerScope = '';
3277                 this.registerContentScope = function (scp) {
3278                     contentScope = scp;
3279                 };
3280                 this.registerTogglerScope = function (scp) {
3281                     togglerScope = scp;
3282                 };
3283
3284                 this.toggleFlyoutState = function () {
3285                     if (contentScope) {
3286                         contentScope.toggleFlyout();
3287                     }
3288                 };
3289                 this.getTogglerDimensions = function () {
3290                     return togglerScope.getTogglerDimensions();
3291                 }
3292                 this.setTogglerFocus = function () {
3293                     return togglerScope.setTogglerFocus();
3294                 }
3295
3296                 this.closeFlyout = function (e) {
3297                     contentScope.closeFromChild(e);
3298                 };
3299                 this.gotFocus = function () {
3300                     contentScope.gotFocus();
3301                 };
3302
3303                 this.updateAriaModel = function (val) {
3304                     scope.flyoutOpened = val;
3305                 };
3306
3307                 var firstTabableElement = undefined,
3308                     lastTabableElement = undefined;
3309
3310                 var firstTabableElementKeyhandler = function (e) {
3311                     if (!e.keyCode) {
3312                         e.keyCode = e.which;
3313                     }
3314                     if (e.keyCode === keymap.KEY.TAB && e.shiftKey && scope.flyoutOpened) { 
3315                         contentScope.gotFocus();
3316                         events.preventDefault(e);
3317                         events.stopPropagation(e);
3318                     }
3319                 };
3320
3321                 var lastTabableElementKeyhandler = function (e) {
3322                     if (!e.keyCode) {
3323                         e.keyCode = e.which;
3324                     }
3325                     if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {
3326                         contentScope.gotFocus();    
3327                         events.preventDefault(e);
3328                         events.stopPropagation(e);
3329                     }
3330                 };
3331                 this.associateTabEvent = function(){
3332                     $timeout(function () {
3333                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];
3334                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3335                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3336                         if(angular.isUndefined(firstTabableElement)){
3337                             angular.element(element).css('display','block');
3338                             firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3339                             lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3340                             angular.element(element).css('display','none');
3341                         }
3342                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
3343                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
3344                     });
3345                 }
3346                 this.updateTabbableElements = function(){
3347                     $timeout(function () {
3348                         var element = elem[0].getElementsByClassName('b2b-flyout-container')[0];
3349                         angular.element(element).css('display','block');
3350                         firstTabableElement = b2bDOMHelper.firstTabableElement(element);
3351                         lastTabableElement = b2bDOMHelper.lastTabableElement(element);
3352                         angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
3353                         angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
3354                         angular.element(element).css('display','none');
3355                     });
3356                 }
3357                 this.unbindTabbaleEvents = function(){
3358                     if(angular.isDefined(firstTabableElement)){
3359                         angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);
3360                     }
3361
3362                     if(angular.isDefined(lastTabableElement)){
3363                         angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);
3364                     }
3365                 }
3366             }],
3367             link: function (scope, element, attrs, ctrl) {
3368
3369             }
3370         };
3371     }])
3372     .directive('b2bFlyoutToggler', [function () {
3373         return {
3374             restrict: 'A',
3375             require: '^b2bFlyout',
3376             link: function (scope, element, attrs, ctrl) {
3377                 element.bind('click', function (e) {
3378                     ctrl.toggleFlyoutState();
3379                 });
3380
3381                 scope.getTogglerDimensions = function () {
3382                     return element[0].getBoundingClientRect();
3383                 }
3384
3385                 scope.setTogglerFocus = function () {
3386                     element[0].focus();
3387                 }
3388
3389                 ctrl.registerTogglerScope(scope);
3390             }
3391         };
3392     }])
3393     .directive('b2bFlyoutContent', ['$position', '$timeout', '$documentBind', '$isElement', '$document', function ($position, $timeout, $documentBind, $isElement, $document) {
3394         return {
3395             restrict: 'EA',
3396             transclude: true,
3397             replace: true,
3398             require: '^b2bFlyout',
3399             scope: {
3400                 horizontalPlacement: '@',
3401                 verticalPlacement: '@',
3402                 flyoutStyle: '@',
3403                 flyoutTitle: '@',
3404                 contentUpdated: "=?"
3405             },
3406             templateUrl: 'b2bTemplate/flyout/flyoutContent.html',
3407             link: function (scope, element, attrs, ctrl) {
3408                 var flyoutStyleArray, eachCssProperty, cssPropertyKey, cssPropertyVal, temp;
3409                 scope.openFlyout = false;
3410                 if (!scope.horizontalPlacement) {
3411                     scope.horizontalPlacement = 'center';
3412                 }
3413                 if (!scope.verticalPlacement) {
3414                     scope.verticalPlacement = 'below';
3415                 }
3416
3417                 scope.toggleFlyout = function () {
3418
3419                     scope.openFlyout = !scope.openFlyout;
3420
3421                     if (scope.openFlyout) {
3422
3423                         if (angular.isDefined(scope.flyoutStyle) && scope.flyoutStyle != "") {
3424                             flyoutStyleArray = scope.flyoutStyle.split(";");
3425                             for (i = 0; i < flyoutStyleArray.length; i++) {
3426                                 eachCssProperty = flyoutStyleArray[i].split(":");
3427                                 if (eachCssProperty.length == 2) {
3428                                     cssPropertyKey = eachCssProperty[0].trim();
3429                                     cssPropertyVal = eachCssProperty[1].trim();
3430                                     angular.element(element[0])[0].style[cssPropertyKey] = cssPropertyVal;
3431                                 }
3432                             }
3433                         }
3434
3435                         angular.element(element[0]).css({
3436                             'opacity': 0,
3437                             'display': 'block'
3438                         });
3439
3440                         var flyoutIcons = angular.element(document.querySelectorAll(".b2b-flyout-icon"));
3441                         angular.forEach(flyoutIcons, function (elm) {
3442                             angular.element(elm)[0].blur();
3443                         });
3444
3445                         $timeout(function () {
3446                             ctrl.setTogglerFocus();
3447
3448                             var togglerDimensions = ctrl.getTogglerDimensions();
3449                             var flyoutDimensions = element[0].getBoundingClientRect();
3450
3451                             switch (scope.horizontalPlacement) {
3452                             case "left":
3453                                 angular.element(element[0]).css({
3454                                     'left': ((togglerDimensions.width / 2) - 26) + 'px'
3455                                 });
3456                                 break;
3457                             case "right":
3458                                 angular.element(element[0]).css({
3459                                     'right': ((togglerDimensions.width / 2) - 23) + 'px'
3460                                 });
3461                                 break;  
3462
3463                             case "centerLeft":
3464                                 var marginLeft =  10-(flyoutDimensions.width)-20;
3465                                 angular.element(element[0]).css({
3466                                     'margin-left': marginLeft + 'px'
3467                                 });
3468                                 break;
3469                             case "centerRight":
3470                                 angular.element(element[0]).css({
3471                                     'left': ((togglerDimensions.width + 9 )) + 'px'
3472                                 });
3473                                 break;    
3474
3475                             default:
3476                                 var marginLeft = (togglerDimensions.width / 2) - (flyoutDimensions.width / 2) - 8;
3477                                 angular.element(element[0]).css({
3478                                     'margin-left': marginLeft + 'px'
3479                                 });
3480                             }
3481
3482                             switch (scope.verticalPlacement) {
3483                             case "above":
3484                                 angular.element(element[0]).css({
3485                                     'top': -(flyoutDimensions.height + 13) + 'px'
3486                                 });
3487                                 break;
3488                             case "centerLeft":
3489                                 angular.element(element[0]).css({
3490                                     'top': -((togglerDimensions.height-13))+ 'px'
3491                                 });
3492                                 break;
3493                             case "centerRight":
3494                                 angular.element(element[0]).css({
3495                                     'top': -(flyoutDimensions.height - 23)+ 'px'
3496                                 });
3497                                 break;                                    
3498                             default:
3499                                 angular.element(element[0]).css({
3500                                     'top': (togglerDimensions.height + 13) + 'px'
3501                                 });
3502                             }
3503
3504                             angular.element(element[0]).css({
3505                                 'opacity': 1
3506                             });
3507                         }, 100);
3508                     } else {
3509                         scope.hideFlyout();
3510                     }
3511                 };
3512
3513                 scope.gotFocus = function () {
3514                     scope.openFlyout = false;
3515                     scope.hideFlyout();
3516                     ctrl.setTogglerFocus();
3517                     scope.$apply();
3518                 };
3519
3520                 scope.closeFromChild = function (e) {
3521                     scope.openFlyout = false;
3522                     scope.hideFlyout();
3523                     ctrl.setTogglerFocus();
3524                     scope.$apply();
3525                 };
3526
3527                 scope.hideFlyout = function () {
3528                     angular.element(element[0]).css({
3529                         'opacity': 0,
3530                         'display': 'none'
3531                     });
3532                 };
3533
3534                 scope.closeFlyout = function (e) {
3535                     var isElement = $isElement(angular.element(e.target), element, $document);
3536                     if ((e.type === "keydown" && e.which === 27) || ((e.type === "click" || e.type==="touchend") && !isElement)) {
3537                         scope.openFlyout = false;
3538                         scope.hideFlyout();
3539                         ctrl.setTogglerFocus();
3540                         scope.$apply();
3541                     }
3542                 };
3543
3544                 scope.$watch('openFlyout', function () {
3545                     ctrl.updateAriaModel(scope.openFlyout);
3546                 });
3547
3548                 $documentBind.click('openFlyout', scope.closeFlyout, scope);
3549                 $documentBind.event('keydown', 'openFlyout', scope.closeFlyout, scope);
3550                 $documentBind.event('touchend', 'openFlyout', scope.closeFlyout, scope);
3551                 ctrl.registerContentScope(scope);
3552
3553                 if (angular.isDefined(scope.contentUpdated) && scope.contentUpdated !== null) {
3554                     scope.$watch('contentUpdated', function (newVal, oldVal) {
3555                         if(newVal){
3556                             if (newVal !== oldVal) {
3557                                 ctrl.unbindTabbaleEvents();
3558                                 ctrl.associateTabEvent();
3559                             }
3560                             scope.contentUpdated = false;
3561                         } 
3562                     });
3563                 }  
3564
3565             }
3566         };
3567     }])
3568     .directive('b2bCloseFlyout', [function () {
3569         return {
3570             restrict: 'A',
3571             require: '^b2bFlyout',
3572             scope: {
3573                 closeFlyout: '&'
3574             },
3575             link: function (scope, element, attrs, ctrl) {
3576                 element.bind('click touchstart', function (e) {
3577                     scope.closeFlyout(e);
3578                     ctrl.closeFlyout(e);
3579                 });
3580             }
3581         };
3582     }])
3583     .directive('b2bFlyoutTrapFocusInside', [function () {
3584         return {
3585             restrict: 'A',
3586             transclude: false,
3587             require: '^b2bFlyout',
3588             link: function (scope, elem, attr, ctrl) {
3589                 /* Before opening modal, find the focused element */
3590                 ctrl.updateTabbableElements();
3591             }
3592         };
3593     }]);
3594 /**
3595  * @ngdoc directive
3596  * @name Layouts.att:footer
3597  *
3598  * @description
3599  *  <file src="src/footer/docs/readme.md" />
3600  *
3601  * @usage
3602  * 
3603  <footer class="b2b-footer-wrapper" role="contentinfo" aria-label="footer">
3604         <div class="b2b-footer-container" b2b-column-switch-footer footer-link-items='footerItems'>
3605             <hr>
3606             <div class="divider-bottom-footer">
3607                 <div class="span2 dispalyInline">&nbsp;</div>
3608                 <div class="span6 dispalyInline">
3609                     <ul class="footer-nav-content">
3610                         <li><a href="Terms_of_use.html" title="Terms of use" id="foot0">Terms of use</a>|</li>
3611                         <li><a href="Privacy_policy.html" title="Privacy policy" id="foot1" class="active">Privacy policy</a>|</li>
3612                         <li><a href="Tollfree_directory_assistance.html" title="Tollfree directory assistance" id="foot2">Tollfree directory assistance</a>|</li>
3613                         <li><a href="compliance.html" title="Accessibility" id="foot3">Accessibility</a></li>
3614
3615                     </ul>
3616                     <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.
3617
3618                     </p>
3619                 </div>
3620                 <div class="span3 footerLogo dispalyInline">
3621                     <a href="index.html" class="footer-logo">
3622                         <i class="icon-primary-att-globe"><span class="hidden-spoken">A T &amp; T</span></i>
3623                         <h2 class="logo-title">AT&amp;T</h2>
3624                     </a>
3625                 </div>
3626             </div>
3627
3628         </div>  
3629     </footer>
3630
3631  * @example
3632  *  <section id="code">   
3633  <example module="b2b.att">
3634  <file src="src/footer/docs/demo.html" />
3635  <file src="src/footer/docs/demo.js" />
3636  </example>
3637  </section>
3638  *
3639  */
3640 angular.module('b2b.att.footer', ['b2b.att.utilities']).
3641         directive('b2bColumnSwitchFooter', [function() {
3642                 return {
3643                     restrict: 'A',
3644                     transclude: true,
3645                     scope: {
3646                         footerLinkItems: "="
3647                     },
3648                     templateUrl: 'b2bTemplate/footer/footer_column_switch_tpl.html',
3649                     link: function(scope) {
3650                                                 var tempFooterColumns = scope.footerLinkItems.length;
3651                                                 scope.footerColumns = 3;
3652                         if ( (tempFooterColumns === 5) || (tempFooterColumns === 4) ) {
3653                                                         scope.footerColumns = tempFooterColumns;
3654                         }
3655                     }
3656
3657                 };
3658
3659             }]);
3660      
3661
3662 /**
3663  * @ngdoc directive
3664  * @name Layouts.att:header
3665  *
3666  * @description
3667  *  <file src="src/header/docs/readme.md" />
3668  *
3669  * @usage
3670  *  <li b2b-header-menu class="header__item b2b-headermenu" ng-repeat="item in tabItems" role="presentation">
3671         <a href="#" class="menu__item" role="menuitem">{{item.title}}</a>
3672         <div class="header-secondary-wrapper">
3673             <ul class="header-secondary" role="menu">
3674                 <li class="header-subitem" b2b-header-submenu ng-repeat="i in item.subitems" role="presentation">
3675                     <a href="#" class="menu__item" aria-haspopup="true" role="menuitem">{{i.value}}</a>
3676                     <div class="header-tertiary-wrapper" ng-if="i.links">
3677                         <ul class="header-tertiary" role="menu">
3678                             <li b2b-header-tertiarymenu ng-repeat="link in i.links" role="presentation">
3679                                 <label>{{link.title}}</label>
3680                                 <div b2b-tertiary-link ng-repeat="title in link.value">
3681                                     <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>
3682                                     <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>
3683                                     <ul class="header-quarternary" role="menu"  ng-if="title.subitems">
3684                                         <li b2b-header-quarternarymenu role="presentation">
3685                                             <a href="{{nav.href}}" ng-repeat="nav in title.subitems" role="menuitem" aria-haspopup="true">{{nav.title}}</a>
3686                                         </li>
3687                                     </ul>
3688                                 </div>
3689                             </li>
3690                         </ul>
3691                     </div>
3692                 </li>
3693             </ul>
3694         </div>
3695     </li> 
3696  *
3697  * @example
3698  *  <section id="code">
3699  <example module="b2b.att.header">
3700  <file src="src/header/docs/demo.html" />
3701  <file src="src/header/docs/demo.js" />
3702  </example>
3703  </section>
3704  *
3705  */
3706 angular.module('b2b.att.header', ['b2b.att.dropdowns','b2b.att.utilities'])
3707         .directive('b2bHeaderMenu', ['keymap', '$documentBind', '$timeout', '$isElement', '$document', function (keymap, $documentBind, $timeout, $isElement, $document) {
3708         return {
3709             restrict: 'A',
3710             controller:['$scope',function($scope){
3711                 this.nextSiblingFocus = function (elObj,flag) {
3712                         if (elObj.nextElementSibling) {
3713                             if(flag){
3714                                 var nextmenuItem = this.getFirstElement(elObj.nextElementSibling,'a');
3715                                 nextmenuItem.focus();
3716                             }else{
3717                                 elObj.nextElementSibling.focus();
3718                             }
3719                         }
3720                 };
3721                 
3722                 this.previousSiblingFocus = function (elObj,flag) {
3723                         if (elObj.previousElementSibling) {
3724                             if(flag){
3725                                 var prevmenuItem = this.getFirstElement(elObj.previousElementSibling,'a');
3726                                 prevmenuItem.focus();
3727                             }else{
3728                                 elObj.previousElementSibling.focus();
3729                             }
3730                         }
3731                 };
3732                     
3733                 this.getFirstElement = function(elmObj,selector){
3734                         return elmObj.querySelector(selector);                        
3735                     };
3736             }],
3737             link: function (scope, elem,attr,ctrl) {
3738                 scope.showMenu = false;
3739                 var activeElm, subMenu, tertiaryMenu, el= angular.element(elem)[0], 
3740                         menuItem = angular.element(elem[0].children[0]);
3741                 menuItem.bind('click', function () {
3742                     elem.parent().children().removeClass('active');
3743                     elem.addClass('active');
3744                     var elems= this.parentElement.parentElement.querySelectorAll('li[b2b-header-menu]>a');
3745                     for (var i=0; i<elems.length; i++) {
3746                         elems[i].setAttribute("aria-expanded",false);
3747                     }
3748                     scope.showMenu = true;
3749                     var elmTofocus = ctrl.getFirstElement(this.parentElement,'li[b2b-header-submenu]');
3750                     elmTofocus.firstElementChild.focus();
3751                     this.setAttribute('aria-expanded',true);
3752                     scope.$apply();
3753                 });
3754                
3755                 elem.bind('keydown', function (evt) {
3756                     activeElm = document.activeElement;
3757                     subMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-submenu]');
3758                     tertiaryMenu = ctrl.getFirstElement(activeElm.parentElement,'li[b2b-header-tertiarymenu]');
3759                     switch (evt.keyCode) {
3760                         case keymap.KEY.ENTER:
3761                         case keymap.KEY.SPACE:
3762                             elem[0].click();
3763                             break;
3764                         case keymap.KEY.UP:
3765                             evt.stopPropagation();
3766                             evt.preventDefault();
3767                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3768                                 menuItem[0].focus();
3769                             }
3770                             break;
3771                         case keymap.KEY.DOWN:
3772                             evt.stopPropagation();
3773                             evt.preventDefault();
3774                             if (subMenu) {
3775                                 subMenu.firstElementChild.focus();
3776                             } else if (tertiaryMenu) {
3777                                 var firstSubitem = ctrl.getFirstElement(tertiaryMenu,'a.header-tertiaryitem');
3778                                 firstSubitem.focus();
3779                             }
3780                             break;
3781                         case keymap.KEY.RIGHT:
3782                             evt.stopPropagation();
3783                             evt.preventDefault();
3784                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3785                                 var elm = angular.element(activeElm.parentElement)[0];
3786                                 ctrl.nextSiblingFocus(elm,true);
3787                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {
3788                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];
3789                                 if (tertiaryLI.nextElementSibling) {
3790                                     var nextElm = ctrl.getFirstElement(tertiaryLI.nextElementSibling,"a.header-tertiaryitem");
3791                                     nextElm.focus();
3792                                 }
3793                             }
3794                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')){
3795                                 ctrl.nextSiblingFocus(el,true);
3796                             }
3797                             break;
3798                         case keymap.KEY.LEFT:
3799                             evt.stopPropagation();
3800                             evt.preventDefault();
3801                             if (activeElm.parentElement.hasAttribute('b2b-header-submenu')) {
3802                                 var previousElm = angular.element(activeElm.parentElement)[0];
3803                                 ctrl.previousSiblingFocus(previousElm,true);
3804                             } else if (activeElm.parentElement.parentElement.hasAttribute('b2b-header-tertiarymenu')) {
3805                                 var tertiaryLI = angular.element(activeElm.parentElement.parentElement)[0];
3806                                 if (tertiaryLI.previousElementSibling) {
3807                                     var prevElm = ctrl.getFirstElement(tertiaryLI.previousElementSibling,"a.header-tertiaryitem");
3808                                     prevElm.focus();
3809                                 }
3810                             }
3811                             else if(activeElm.parentElement.hasAttribute('b2b-header-menu')) {
3812                                 ctrl.previousSiblingFocus(el,true);
3813                             }
3814                             break;
3815                         case keymap.KEY.ESC:
3816                             evt.stopPropagation();
3817                             evt.preventDefault();
3818                             scope.showMenu = false;
3819                             elem.removeClass('active');
3820                                                         menuItem.attr('aria-expanded',false);
3821                                                         $timeout(function(){
3822                                                                 menuItem[0].focus();
3823                                                         },100);
3824                             scope.$apply();
3825                             break;
3826                         default:
3827                             break;
3828                     }
3829                 });
3830                 var outsideClick = function (e) {
3831                     var isElement = $isElement(angular.element(e.target), elem, $document);
3832                     if (!isElement) {
3833                         scope.showMenu = false;
3834                         elem.removeClass('active');
3835                         scope.$apply();
3836                     }
3837                 };
3838                 $documentBind.click('showMenu', outsideClick, scope);
3839             }
3840         };
3841     }]).directive('b2bHeaderSubmenu', ['$timeout',function ($timeout) {
3842         return{
3843             restrict: 'A',
3844             link: function (scope, elem) {
3845                 var caretSign = angular.element("<i class='menuCaret'></i>");
3846                 $timeout(function(){
3847                                         var menuItem = angular.element(elem[0].children[0]);
3848                                         menuItem.bind('focus mouseenter', function () {
3849                                                 elem.parent().children().removeClass('active');
3850                                                 elem.addClass('active');
3851                                                 if(elem[0].childElementCount > 1){ // > 1 has third level menu
3852                                                         menuItem.attr('aria-expanded',true);
3853                                                         menuItem.attr('aria-haspopup',true);
3854                                                 }
3855                                                 var caretLeft = (elem[0].offsetLeft +  elem[0].offsetWidth/2) - 10;
3856                                                 caretSign.css({left: caretLeft + 'px'});
3857                                                 angular.element(caretSign);
3858                                                 var tertiaryItems = elem[0].querySelectorAll('[b2b-header-tertiarymenu]');
3859                                                 if(tertiaryItems.length >=1){
3860                                                         elem.append(caretSign);
3861                                                 }
3862                                         });
3863                                         menuItem.bind('blur', function () {
3864                                                 $timeout(function () {
3865                                                         var parentElm = document.activeElement.parentElement.parentElement;
3866                                                         if(parentElm){
3867                                                                 if (!(parentElm.hasAttribute('b2b-header-tertiarymenu'))) {
3868                                                                         elem.removeClass('active');
3869                                                                         if(elem[0].childElementCount > 1){ // > 1 has third level menu
3870                                                                                 menuItem.attr('aria-expanded',false);
3871                                                                         }
3872                                                                         var caret = elem[0].querySelector('.menuCaret');
3873                                                                         if(caret){
3874                                                                                 caret.remove();
3875                                                                         }   
3876                                                                 }
3877                                                         }
3878                                                 });
3879                                         });
3880                 });
3881             }
3882         };
3883     }]).directive('b2bHeaderTertiarymenu', ['$timeout','keymap', function ($timeout,keymap){
3884         return{
3885             restrict: 'A',
3886             require:'^b2bHeaderMenu',
3887             link: function (scope, elem,attr,ctrl) {
3888                 
3889                 elem.bind('keydown', function (evt) {
3890                     var activeElm = document.activeElement;
3891                     var activeParentElm = activeElm.parentElement;
3892                     var activeParentObj  = angular.element(activeParentElm)[0];
3893                     
3894                     if(activeParentElm.hasAttribute('b2b-tertiary-link')){
3895                         var quarterNav = angular.element(activeParentElm)[0].querySelector('li[b2b-header-quarternarymenu]');
3896                         if(quarterNav){
3897                             var links = ctrl.getFirstElement(angular.element(quarterNav)[0],'a');
3898                         }
3899                     }
3900                     var tertiaryMenu = activeElm.parentElement.parentElement.parentElement;
3901                     var tertiaryMenuFlag = tertiaryMenu.hasAttribute('b2b-tertiary-link');
3902                     
3903                     switch (evt.keyCode) {
3904                         case keymap.KEY.DOWN:
3905                             evt.stopPropagation();
3906                             evt.preventDefault();
3907                             if (activeParentElm.hasAttribute('b2b-tertiary-link')) {
3908                                 if(angular.element(quarterNav).hasClass('active')){
3909                                     links.focus();
3910                                 }else if(activeParentObj.nextElementSibling){
3911                                     ctrl.nextSiblingFocus(activeParentObj,true);
3912                                 }
3913                             }
3914                             else if(angular.element(activeParentElm).hasClass('active')){
3915                                 ctrl.nextSiblingFocus(activeElm);
3916                             }
3917                             break;                        
3918                         case keymap.KEY.UP:
3919                             evt.stopPropagation();
3920                             evt.preventDefault();
3921                             if(activeParentElm.hasAttribute('b2b-tertiary-link')){
3922                                 if(activeParentObj.previousElementSibling.hasAttribute('b2b-tertiary-link')){
3923                                     ctrl.previousSiblingFocus(activeParentObj,true);
3924                                 }else{
3925                                     var elm = angular.element(activeElm.parentElement.parentElement.parentElement.parentElement.parentElement)[0];
3926                                     ctrl.getFirstElement(elm,"a").focus();
3927                                 }
3928                             }else if(angular.element(activeParentElm).hasClass('active')){
3929                                     if (activeElm.previousElementSibling) {
3930                                         ctrl.previousSiblingFocus(activeElm);
3931                                     }else if (tertiaryMenuFlag) {
3932                                         var elm = angular.element(tertiaryMenu)[0];
3933                                         ctrl.getFirstElement(elm,"a.header-tertiaryitem").focus();
3934                                     }
3935                                 }
3936                             break;
3937                         default:
3938                             break;
3939                     }
3940                 });
3941             }            
3942         };          
3943     }]).directive('b2bHeaderTogglemenu', ['$timeout', 'keymap', function ($timeout, keymap) {
3944         return{
3945             restrict: 'A',
3946             require: '^b2bHeaderMenu',
3947             link: function (scope, elem, attrs, ctrl) {
3948                 var quarterNav;
3949                 $timeout(function () {
3950                     quarterNav = angular.element(elem.parent())[0].querySelector('li[b2b-header-quarternarymenu]');
3951                     elem.bind('click', function () {
3952                         angular.element(quarterNav).toggleClass('active');
3953                     });
3954                 });
3955             }
3956         };
3957     }]).directive('b2bHeaderResponsive', ['$timeout',function ($timeout) {
3958         return{
3959             restrict: 'A',
3960                         controller: function($scope){
3961                                 this.applyMediaQueries = function(value){
3962                                         document.querySelector('style').textContent += 
3963                                                 "@media screen and (max-width:950px) { \
3964                                                         .header__item.profile { right: " + value + "px; } \
3965                                                 }";
3966                                 };
3967                                 this.arrangeResponsiveHeader = function(children){
3968                                         /* 
3969                                          * clientWidth of 1090 === max-width of 1100px
3970                                          * clientWidth of 920 === max-width of 950px
3971                                          * see b2b-angular.css for rest of responsive header CSS
3972                                          */
3973                                   if (document.documentElement.clientWidth <= 920) { 
3974                                                 switch(children){
3975                                                         case 1:
3976                                                                 this.applyMediaQueries(200);                                    
3977                                                                 break;
3978                                                         case 2:
3979                                                                 this.applyMediaQueries(200);                                                    
3980                                                                 break;
3981                                                         default: // anthing above 3, however, should not have more than 3 to date
3982                                                                 this.applyMediaQueries(200);                                                                                                                                                    
3983                                                 }
3984                                         }
3985                                 }
3986                         },
3987             link: function (scope, elem, attrs, ctrl) {
3988                                 var children;
3989                                 var profile;
3990                                 
3991                                 // onload of page
3992                                 $timeout(function(){ 
3993                                         profile = document.querySelector('li.header__item.profile');
3994                                         children = angular.element(profile).children().length;
3995                                         
3996                                         ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers
3997                                 });
3998
3999                                 // on screen resize
4000                                 window.addEventListener('resize', function(event){ // caret adjustmet
4001                                         var activeSubmenu = elem[0].querySelector('[b2b-header-menu] [b2b-header-submenu].active');
4002                                         var activeSubmenuEl = angular.element(activeSubmenu);
4003                                         if(activeSubmenu){
4004                                                 var caretSign = activeSubmenu.querySelector('i.menuCaret');
4005                                                 if(caretSign){
4006                                                         var caretSignEl = angular.element(caretSign);
4007                                                         var caretLeft = (activeSubmenu.offsetLeft +  activeSubmenu.offsetWidth/2) - 10;
4008                                                         caretSignEl.css({left: caretLeft + 'px'});
4009                                                 }
4010                                         }
4011
4012                                         ctrl.arrangeResponsiveHeader(children); // shift right-side icon flyovers
4013                                 });
4014             }
4015         };
4016         }]);
4017
4018 /**
4019  * @ngdoc directive
4020  * @name Layouts.att:headings & copy
4021  *
4022  * @description
4023  *  <file src="src/headingsAndCopy/docs/readme.md" />
4024  *
4025  * @example
4026  <section id="code">
4027     <b>HTML + AngularJS</b>
4028     <example module="b2b.att">
4029     <file src="src/headingsAndCopy/docs/demo.html" />
4030 </example>
4031 </section>
4032  */
4033
4034 var b2bLegalCopy = angular.module('b2b.att.headingsAndCopy', []);
4035 /**
4036  * @ngdoc directive
4037  * @name Tabs, tables & accordions.att:horizontalTable
4038  *
4039  * @description
4040  *  <file src="src/horizontalTable/docs/readme.md" />
4041  *
4042  * @usage
4043  * @param {int} sticky - Number of sticky columns to have. Maximum of 3.
4044  * @param {boolean} refresh - A boolean that when set to true will force a re-render of table. Only use when using 'bulk mode'
4045  * @param {string} legendContent - A string of html to fill in the legend flyout. This should generally be a <ul> with <li> and should not rely on Angular for repeating.
4046  * @param {boolean} retainColumnSet - A boolean that on re-render of the table, determines if the columns visible should reset to 0 or not. Default is false. 
4047  * @example
4048  *  <section id="code">
4049         <example module="b2b.att">
4050             <file src="src/horizontalTable/docs/demo.html" />
4051             <file src="src/horizontalTable/docs/demo.js" />
4052        </example>
4053     </section>
4054  *
4055  */
4056 angular.module('b2b.att.horizontalTable', [])
4057     .constant('b2bHorizontalTableConfig', {
4058         'maxStickyColumns': 3
4059     })
4060     .directive('b2bHorizontalTable', ['$timeout', 'b2bHorizontalTableConfig', 'b2bDOMHelper', function ($timeout, b2bHorizontalTableConfig, b2bDOMHelper) {
4061         return {
4062             restrict: 'EA',
4063             scope: true,
4064             transclude: true,
4065             scope: {
4066                 numOfStickyCols: '=?sticky',
4067                 refresh: '=?',
4068                 legendContent: '=?',
4069                 retainColumnSet: '=?'
4070
4071             },
4072             templateUrl: 'b2bTemplate/horizontalTable/horizontalTable.html',
4073             link: function (scope, element, attrs, ctrl) {
4074                 scope.numOfStickyCols = scope.numOfStickyCols || 1;
4075                 scope.viewportIndex = scope.numOfStickyCols;
4076                 scope.countDisplayText = "";
4077                 var tableElement = element.find('table');
4078                 var thElements = element.find('th');
4079                 var innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));
4080                 var outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));
4081
4082                 var tableColumns = [];
4083                 var tableRows = element.find('tr');
4084
4085                 var maxWidth = 0,
4086                     maxHeight = 0;
4087                 var totalWidth = element.children()[0].offsetWidth;
4088                 var lastVisibleColumn = 0;
4089                 var collectiveColumnWidth = [];
4090                 var collectiveRowHeight = [];
4091                 var columnSets = [];
4092                 var setIndex = 0; 
4093                 var stickyPixels = 0;
4094
4095                 var displayNoneCSS = {'display': 'none'};
4096                 var displayBlockCSS = {'display': 'table-cell'};
4097
4098                 var init = function() {
4099                     // Reset this from a previous execution
4100                     tableColumns = [];
4101                     collectiveColumnWidth = [];
4102                     collectiveRowHeight = [];
4103                     maxWidth = 0;
4104                     maxHeight = 0;
4105                     lastVisibleColumn = 0;
4106                     columnSets = [];
4107                     if ((!!scope.retainColumnSet)) {
4108                         setIndex = 0;
4109                     }
4110                     visibleColumns = [];
4111                     stickyPixels = 0;
4112
4113                     tableElement = element.find('table');
4114                     thElements = element.find('th');
4115                     innerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table-inner-container'));
4116                     outerContainer = angular.element(element[0].querySelector('.b2b-horizontal-table'));
4117                     totalWidth = element.children()[0].offsetWidth;
4118                     tableRows = element.find('tr');
4119
4120                     scope.disableLeft = true;
4121                     scope.disableRight = false;
4122
4123                     if (scope.numOfStickyCols > b2bHorizontalTableConfig.maxStickyColumns) {
4124                         throw new Error('Table can only support ' + b2bHorizontalTableConfig.maxStickyColumns + ' sticky columns.');
4125                     }             
4126                     scope.countDisplayText = "";
4127                     for(var count = 1; count <= scope.numOfStickyCols; count++) {
4128                         scope.countDisplayText = scope.countDisplayText + count + ", "
4129                     }
4130                     angular.forEach(tableRows, function(row, rowIndex) {
4131                         for(var j = 0; j < row.children.length; j++) {
4132                             if (tableColumns[j] === undefined) {
4133                                 tableColumns[j] = [];
4134                             }
4135                             tableColumns[j].push(row.children[j]);
4136                         }
4137                     });
4138
4139                     // We need to reset all the displayNones from previous runs, if applicable
4140                     if (attrs.refresh !== undefined && attrs.refresh !== '')  {
4141                         for (var i = scope.numOfStickyCols+1; i < tableColumns.length; i++) {
4142                             angular.element(tableColumns[i]).css(displayBlockCSS);
4143                         }
4144                     }   
4145
4146                     // We must calculate here as we need cells to be reset after re-render. 
4147                     angular.forEach(tableRows, function(row, rowIndex) {
4148                         collectiveRowHeight.push(findMax(row.children, 'height')); // BUG: Keeping this here now causes row height bugs
4149                     });
4150                     
4151                     
4152                     for (var i = 0; i < tableColumns.length; i++) {
4153                         collectiveColumnWidth.push(findMax(tableColumns[i], 'width')); //offsetWidth doesn't take into account custom css inside
4154                     }
4155                     for(var i = 0; i < scope.numOfStickyCols; i++) {
4156                         maxWidth += collectiveColumnWidth[i];
4157                     }
4158
4159                     // BUG: The code I put in to fix the table not spanning 100%  width is now preventing 
4160                     // table cells from laying out more than stickyPixels and thus we have weird wrapping
4161                     stickyPixels = totalWidth-maxWidth;
4162
4163                     // At this point, for each tr, I need to set the properties (height) and each numOfStickyCols children
4164                     // should be set with sticky properties (margin-left and width)
4165                     var width = maxWidth;
4166                     var additive = 0; 
4167
4168                     if (angular.element(document).find('html').hasClass('isIE')) {
4169                         additive = 25;
4170                     }
4171                     var thObject = undefined;
4172                     for(var i = 0; i < scope.numOfStickyCols; i++) {
4173                         for (var j = 0; j < tableRows.length; j++) {
4174                             thObject = angular.element(tableRows[j].children[i]);
4175                             angular.element(thObject).css({
4176                                 'margin-left': -(width + 2) + 'px', 
4177                                 'width': (collectiveColumnWidth[i] + 3) + 'px', // instead of taking the max width, grab max width for that column
4178                                 'height': (collectiveRowHeight[j] + additive) + 'px',
4179                                 'position': 'absolute',
4180                                 'background-color': '#F2F2F2'
4181                             });
4182                         }
4183                         width -= collectiveColumnWidth[i];
4184                     }
4185                     angular.element(tableRows[0]).css('height', collectiveRowHeight[0] + 'px');
4186                     for(var i = 0; i < tableRows.length; i++) {
4187                         angular.element(tableRows[i]).css('height', (collectiveRowHeight[i] + additive) + 'px'); 
4188                     }
4189                     
4190                     innerContainer.css({
4191                         'padding-left': (maxWidth + 2) + 'px'
4192                     });
4193
4194
4195                     // Let's precompute all the (set) combinations beforehand
4196                     columnSets = []; 
4197                     for (var i = scope.numOfStickyCols; i < tableColumns.length;) {
4198                         visibleColumns = calculateVisibleColumns(i);
4199                         if(visibleColumns === tableColumns.length){
4200                             columnSets.push([i, visibleColumns-1]);
4201                         }else{
4202                             columnSets.push([i, visibleColumns]);
4203                         }
4204                         i = visibleColumns + 1;
4205                     }
4206                     
4207                     //columnSets = [[1, 1], [2,7]]; 
4208                     
4209                     updateCellDisplay(columnSets[setIndex]);
4210                     checkScrollArrows();
4211
4212                     scope.numOfCols = tableColumns.length;
4213
4214                 }
4215
4216                 // JM520E: This is a temporary hack until I solve the ngRepeat issue
4217                 function hack() {
4218                     if (element.find('th').length < scope.numOfStickyCols) {
4219                         // DOM ngRepeat is not ready, let's check back in 10 ms
4220                         $timeout(hack, 10, false);
4221                     } else {
4222                         if (scope.refresh !== undefined) {
4223                             scope.$watch('refresh', function(oldVal, newVal) { // this watch calls too many times
4224                                 if (!angular.equals(oldVal, newVal)) { //hackFinished && oldVal < newVal
4225                                     // From testing it takes about 30 ms before ngRepeat executes, so let's set initial timeout
4226                                     // NOTE: May need to expose timeout to developers. Application is known to have digest cycle of 3-5k watches.
4227                                     $timeout(init, 100, false);
4228                                     scope.refresh = false;
4229                                 }
4230                             });
4231                         }
4232
4233                         init();
4234                     }
4235                 }
4236
4237
4238                 
4239
4240                 // Let's get started with some math!
4241                 hack();
4242
4243                 function calculateVisibleColumns(startingPoint) {
4244                     var usedWidth = 0, 
4245                         visibleColumns = startingPoint || scope.numOfStickyCols;
4246
4247                     while(usedWidth < stickyPixels && visibleColumns < collectiveColumnWidth.length) {
4248                         if (usedWidth+collectiveColumnWidth[visibleColumns] > stickyPixels) {
4249                             if (startingPoint === visibleColumns) {
4250                                 return visibleColumns; // The next cell is too large to fit, it should be only thing to fit
4251                             }
4252                             visibleColumns--;
4253                             return visibleColumns;
4254                         }
4255                         usedWidth += collectiveColumnWidth[visibleColumns];
4256                         visibleColumns++;
4257                     }
4258
4259                     if (usedWidth > stickyPixels) {
4260                         return --visibleColumns;
4261                     }
4262                     return visibleColumns;
4263                 }
4264
4265                 function updateCellDisplay(set) {
4266                     for (var i = scope.numOfStickyCols; i < tableColumns.length; i++) {
4267                         angular.element(tableColumns[i]).css(displayNoneCSS);
4268                     }
4269
4270                     for (var i = set[0]; i <= set[1]; i++) {
4271                         angular.element(tableColumns[i]).css(displayBlockCSS);
4272                     }
4273                 }
4274
4275                 function findMax(arr, prop) {
4276                     var max = 0;
4277                     var localVal = 0;
4278                     var prevDisplay;
4279                     var item;
4280                     for (var i = 0; i < arr.length; i++) {
4281                         item = arr[i];
4282                         prevDisplay = angular.element(item).css('display');
4283
4284                         if (scope.$$phase) {
4285                             scope.$digest();
4286                         }
4287                         // Remove inline styles, they will mess up calculations from original run
4288                         angular.element(item).css('height', '');
4289                         angular.element(item).css('width', ''); 
4290                         if (prop === 'width') {
4291                             // If we do not undo previous run's inline styles, this will grow widths on each re-render.
4292                             localVal = Math.ceil(parseInt(window.getComputedStyle(item).width.split('px')[0], 10)) + 30; // 30 px is padding
4293                         } else if (prop === 'offsetWidth') {
4294                             localVal = item.offsetWidth;
4295                         } else if (prop === 'height') {
4296                             //localVal = item.offsetHeight;
4297                             localVal = Math.ceil(parseInt(window.getComputedStyle(item).height.split('px')[0], 10))
4298                         }
4299
4300                         if (localVal >= max) {
4301                             max = localVal;
4302                         }
4303                     }
4304                     
4305                     return max;
4306                 }
4307
4308                 function checkScrollArrows() {
4309                     scope.disableLeft = (setIndex === 0);
4310                     scope.disableRight = !(setIndex < columnSets.length-1);
4311                 }
4312
4313                 scope.moveViewportLeft = function () {
4314                     setIndex--;
4315                     updateCellDisplay(columnSets[setIndex]);
4316                     checkScrollArrows();
4317
4318                     if (scope.disableLeft) {
4319                         element[0].querySelector('.b2b-horizontal-table-column-info').focus();
4320                     }
4321                 };
4322                 
4323                 scope.moveViewportRight = function () {
4324                     setIndex++;
4325                     updateCellDisplay(columnSets[setIndex]);
4326                     checkScrollArrows();
4327                     
4328                     if (scope.disableRight) {
4329                         element[0].querySelector('.b2b-horizontal-table-column-info').focus();
4330                     }
4331                 };
4332
4333                 scope.getColumnSet = function () {
4334                     return columnSets[setIndex];
4335                 };
4336
4337                 innerContainer.bind('scroll', function () {
4338                     $timeout(function () {
4339                         checkScrollArrows();
4340                     }, 1);
4341                 });
4342
4343             }
4344         };
4345     }]);
4346 /**
4347  * @ngdoc directive
4348  * @name Forms.att:hourPicker
4349  *
4350  * @description
4351  *  <file src="src/hourPicker/docs/readme.md" />
4352  *
4353  * @usage
4354  * <div b2b-hourpicker ng-model="hourpickerValue.value"></div>
4355     
4356  * @example
4357  *  <section id="code">
4358         <example module="b2b.att">
4359             <file src="src/hourPicker/docs/demo.html" />
4360             <file src="src/hourPicker/docs/demo.js" />
4361         </example>
4362     </section>
4363  *
4364  */
4365 angular.module('b2b.att.hourPicker', ['b2b.att.utilities'])
4366
4367 .constant('b2bHourpickerConfig', {
4368     dayOptions: [{
4369         title: 'sunday',
4370         caption: 'Sun',
4371         label: 'S',
4372         disabled: false
4373     }, {
4374         title: 'monday',
4375         caption: 'Mon',
4376         label: 'M',
4377         disabled: false
4378     }, {
4379         title: 'tuesday',
4380         caption: 'Tues',
4381         label: 'T',
4382         disabled: false
4383     }, {
4384         title: 'wednesday',
4385         caption: 'Wed',
4386         label: 'W',
4387         disabled: false
4388     }, {
4389         title: 'thursday',
4390         caption: 'Thu',
4391         label: 'T',
4392         disabled: false
4393     }, {
4394         title: 'friday',
4395         caption: 'Fri',
4396         label: 'F',
4397         disabled: false
4398     }, {
4399         title: 'saturday',
4400         caption: 'Sat',
4401         label: 'S',
4402         disabled: false
4403     }],
4404     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'],
4405     startTimeDefaultOptionIndex: -1,
4406     startTimeDefaultMeridiem: "am",
4407     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'],
4408     endTimeDefaultOptionIndex: -1,
4409     endTimeDefaultMeridiem: "pm",
4410     sameDayOption: true
4411 })
4412
4413 .factory('b2bNormalizeHourpickerValues', [function () {
4414     var _normalize = function (hourpickerValues) {
4415         if (angular.isDefined(hourpickerValues) && hourpickerValues != null) {
4416             var finalHourpickerValues = [];
4417             var hourpickerValue = {};
4418             var days = {};
4419             for (var i = 0; i < hourpickerValues.length; i++) {
4420                 days = hourpickerValues[i].days ? hourpickerValues[i].days : {};
4421                 hourpickerValue.startTime = hourpickerValues[i].startTime ? hourpickerValues[i].startTime : '';
4422                 hourpickerValue.startMeridiem = hourpickerValues[i].startMeridiem ? hourpickerValues[i].startMeridiem : '';
4423                 hourpickerValue.endTime = hourpickerValues[i].endTime ? hourpickerValues[i].endTime : '';
4424                 hourpickerValue.endMeridiem = hourpickerValues[i].endMeridiem ? hourpickerValues[i].endMeridiem : '';
4425                 hourpickerValue.days = [];
4426
4427                 var retrieveDaysText = function (daysDetails) {
4428                     var daysTexts = [];
4429                     var first = -1;
4430                     var last = -1;
4431                     var index = -1;
4432                     for (var i in days) {
4433                         if (days[i].value) {
4434                             daysTexts.push(i);
4435                         }
4436                     }
4437
4438                     first = daysTexts[0];
4439                     last = daysTexts[0];
4440                     index = 0;
4441                     hourpickerValue.days[index] = days[first].caption;
4442                     if (daysTexts.length > 1) {
4443                         for (var i = 1; i < daysTexts.length; i++) {
4444                             if (daysTexts[i] - last === 1) {
4445                                 last = daysTexts[i];
4446                                 hourpickerValue.days[index] = days[first].caption + ' - ' + days[last].caption;
4447                             } else {
4448                                 index++;
4449                                 first = last = daysTexts[i];
4450                                 hourpickerValue.days[index] = days[first].caption;
4451                             }
4452                         }
4453                     }
4454                 };
4455                 retrieveDaysText();
4456
4457                 finalHourpickerValues.push(angular.copy(hourpickerValue));
4458             }
4459
4460             return angular.copy(finalHourpickerValues);
4461         }
4462     };
4463
4464     return {
4465         normalize: _normalize
4466     };
4467 }])
4468
4469 .directive('b2bHourpicker', ['b2bHourpickerConfig', 'b2bNormalizeHourpickerValues', function (b2bHourpickerConfig, b2bNormalizeHourpickerValues) {
4470     return {
4471         restrict: 'EA',
4472         replace: false,
4473         scope: true,
4474         require: 'ngModel',
4475         templateUrl: 'b2bTemplate/hourPicker/b2bHourpicker.html',
4476         controller: ['$scope', function (scope) {
4477
4478         }],
4479         link: function (scope, elem, attr, ctrl) {
4480             scope.hourpicker = {};
4481             scope.hourpicker.dayOptions = attr.dayOptions ? scope.$parent.$eval(attr.dayOptions) : b2bHourpickerConfig.dayOptions;
4482             scope.hourpicker.startTimeOptions = attr.startTimeOptions ? scope.$parent.$eval(attr.startTimeOptions) : b2bHourpickerConfig.startTimeOptions;
4483             scope.hourpicker.endTimeOptions = attr.endTimeOptions ? scope.$parent.$eval(attr.endTimeOptions) : b2bHourpickerConfig.endTimeOptions;
4484             scope.hourpicker.startTimeDefaultOptionIndex = attr.startTimeDefaultOptionIndex ? scope.$parent.$eval(attr.startTimeDefaultOptionIndex) : b2bHourpickerConfig.startTimeDefaultOptionIndex;
4485             scope.hourpicker.endTimeDefaultOptionIndex = attr.endTimeDefaultOptionIndex ? scope.$parent.$eval(attr.endTimeDefaultOptionIndex) : b2bHourpickerConfig.endTimeDefaultOptionIndex;
4486             scope.hourpicker.startTimeDefaultMeridiem = attr.startTimeDefaultMeridiem ? scope.$parent.$eval(attr.startTimeDefaultMeridiem) : b2bHourpickerConfig.startTimeDefaultMeridiem;
4487             scope.hourpicker.endTimeDefaultMeridiem = attr.endTimeDefaultMeridiem ? scope.$parent.$eval(attr.endTimeDefaultMeridiem) : b2bHourpickerConfig.endTimeDefaultMeridiem;
4488             scope.hourpicker.sameDayOption = attr.sameDayOption ? scope.$parent.$eval(attr.sameDayOption) : b2bHourpickerConfig.sameDayOption;
4489             scope.hourpicker.editMode = -1;
4490
4491             scope.hourpickerValues = [];
4492             scope.finalHourpickerValues = [];
4493             scope.addHourpickerValue = function (hourpickerPanelValue) {
4494                 if (hourpickerPanelValue) {
4495                     if (scope.hourpicker.editMode > -1) {
4496                         scope.hourpickerValues[scope.hourpicker.editMode] = hourpickerPanelValue;
4497                         scope.hourpicker.editMode = -1;
4498                     } else {
4499                         scope.hourpickerValues.push(hourpickerPanelValue);
4500                     }
4501                 }
4502                 scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));
4503                 ctrl.$setViewValue(angular.copy(scope.hourpickerValues));
4504             };
4505             ctrl.$render = function () {
4506                 if (angular.isDefined(ctrl.$modelValue)) {
4507                     scope.hourpickerValues = angular.copy(ctrl.$modelValue);
4508                     scope.finalHourpickerValues = b2bNormalizeHourpickerValues.normalize(angular.copy(scope.hourpickerValues));
4509                 }
4510             };
4511             scope.editHourpickerValue = function (index) {
4512                 scope.hourpickerPanelValue = angular.copy(scope.hourpickerValues[index]);
4513                 scope.hourpicker.editMode = index;
4514             };
4515             scope.deleteHourpickerValue = function (index) {
4516                 scope.hourpickerValues.splice(index, 1);
4517                 scope.resetHourpickerPanelValue();
4518                 scope.addHourpickerValue();
4519             };
4520
4521             scope.setValidity = function (errorType, errorValue) {
4522                 ctrl.$setValidity(errorType, errorValue);
4523             }
4524         }
4525     }
4526 }])
4527
4528 .directive('b2bHourpickerPanel', [function () {
4529     return {
4530         restrict: 'EA',
4531         replace: false,
4532         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerPanel.html',
4533         controller: ['$scope', function (scope) {
4534
4535         }],
4536         link: function (scope, elem, attr, ctrl) {
4537             var hourpickerPanelValueTemplate = {
4538                 days: {},
4539                 startTime: '',
4540                 startMeridiem: 'am',
4541                 endTime: '',
4542                 endMeridiem: 'pm'
4543             };
4544             for (var i = 0; i < scope.hourpicker.dayOptions.length; i++) {
4545                 hourpickerPanelValueTemplate.days[i] = {
4546                     value: false,
4547                     title: scope.hourpicker.dayOptions[i].title,
4548                     caption: scope.hourpicker.dayOptions[i].caption
4549                 };
4550             }
4551             scope.hourpickerPanelValue = {};
4552             scope.disableAddBtn = true;
4553
4554             scope.$watch('hourpickerPanelValue.days', function(){
4555                 for(var i in scope.hourpickerPanelValue.days)
4556                 {
4557                     if(scope.hourpickerPanelValue.days[i].value)
4558                     {
4559                         scope.disableAddBtn = false;
4560                         break;
4561                     }
4562                     scope.disableAddBtn = true;
4563                 }
4564             }, true);
4565
4566             scope.resetHourpickerPanelValue = function () {
4567                 scope.hourpickerPanelValue = angular.copy(hourpickerPanelValueTemplate);
4568                 if (scope.hourpicker.startTimeDefaultOptionIndex > -1) {
4569                     scope.hourpickerPanelValue.startTime = scope.hourpicker.startTimeOptions[scope.hourpicker.startTimeDefaultOptionIndex];
4570                 }
4571                 if (scope.hourpicker.endTimeDefaultOptionIndex > -1) {
4572                     scope.hourpickerPanelValue.endTime = scope.hourpicker.endTimeOptions[scope.hourpicker.endTimeDefaultOptionIndex];
4573                 }
4574                 scope.hourpickerPanelValue.startMeridiem = scope.hourpicker.startTimeDefaultMeridiem;
4575                 scope.hourpickerPanelValue.endMeridiem = scope.hourpicker.endTimeDefaultMeridiem;
4576                 scope.hourpicker.editMode = -1;
4577                 scope.setValidity('invalidHourpickerData', true);
4578                 scope.setValidity('invalidHourpickerTimeRange', true);
4579             };
4580             scope.resetHourpickerPanelValue();
4581             scope.updateHourpickerValue = function () {
4582                 if (scope.isFormValid() && !scope.isTimeOverlap()) {
4583                     scope.addHourpickerValue(angular.copy(scope.hourpickerPanelValue));
4584                     scope.resetHourpickerPanelValue();
4585                 }
4586             };
4587
4588             scope.isFormValid = function () {
4589                 var isStartTimeAvailable = scope.hourpickerPanelValue.startTime ? true : false;
4590                 var isStartMeridiemAvailable = scope.hourpickerPanelValue.startMeridiem ? true : false;
4591                 var isEndTimeAvailable = scope.hourpickerPanelValue.endTime ? true : false;
4592                 var isEndMeridiemAvailable = scope.hourpickerPanelValue.endMeridiem ? true : false;
4593                 var currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);
4594                 var currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);
4595                 var isTimeInProperSequence = currentEndTime > currentStartTime;
4596                 var isDayChecked = false;
4597                 for (var i in scope.hourpickerPanelValue.days) {
4598                     if (scope.hourpickerPanelValue.days[i].value) {
4599                         isDayChecked = true;
4600                         break;
4601                     }
4602                 }
4603
4604                 if (isStartTimeAvailable && isStartMeridiemAvailable && isEndTimeAvailable && isEndMeridiemAvailable && isTimeInProperSequence && isDayChecked) {
4605                     scope.setValidity('invalidHourpickerData', true);
4606                     return true;
4607                 } else {
4608                     scope.setValidity('invalidHourpickerData', false);
4609                     return false;
4610                 }
4611             };
4612             scope.isTimeOverlap = function () {
4613                 var selectedDays = [];
4614                 for (var i in scope.hourpickerPanelValue.days) {
4615                     if (scope.hourpickerPanelValue.days[i].value) {
4616                         selectedDays.push(i);
4617                     }
4618                 }
4619
4620                 var currentStartTime, currentEndTime, existingStartTime, existingEndTime;
4621                 currentStartTime = getTime(scope.hourpickerPanelValue.startTime, scope.hourpickerPanelValue.startMeridiem);
4622                 currentEndTime = getTime(scope.hourpickerPanelValue.endTime, scope.hourpickerPanelValue.endMeridiem);
4623                 for (var i = 0; i < scope.hourpickerValues.length; i++) {
4624                     
4625                     if (i === scope.hourpicker.editMode) {
4626                         continue;
4627                     }
4628
4629                     for (var j = 0; j < selectedDays.length; j++) {
4630                         existingStartTime = getTime(scope.hourpickerValues[i].startTime, scope.hourpickerValues[i].startMeridiem);
4631                         existingEndTime = getTime(scope.hourpickerValues[i].endTime, scope.hourpickerValues[i].endMeridiem);
4632                         if (scope.hourpickerValues[i].days[selectedDays[j]].value) {
4633                             if(!scope.hourpicker.sameDayOption){
4634                                 scope.setValidity('dayAlreadySelected', false);
4635                                 return true;
4636                             } else if ((currentStartTime > existingStartTime && currentStartTime < existingEndTime) || (currentEndTime > existingStartTime && currentEndTime < existingEndTime)) {
4637                                 scope.setValidity('invalidHourpickerTimeRange', false);
4638                                 return true;
4639                             } else if ((existingStartTime > currentStartTime && existingStartTime < currentEndTime) || (existingEndTime > currentStartTime && existingEndTime < currentEndTime)) {
4640                                 scope.setValidity('invalidHourpickerTimeRange', false);
4641                                 return true;
4642                             } else if ((currentStartTime === existingStartTime) && (currentEndTime === existingEndTime)) {
4643                                 scope.setValidity('invalidHourpickerTimeRange', false);
4644                                 return true;
4645                             }
4646                         }
4647                     }
4648                 }
4649
4650                 scope.setValidity('dayAlreadySelected', true);
4651                 scope.setValidity('invalidHourpickerTimeRange', true);
4652                 return false;
4653             };
4654             var getTime = function (timeString, meridiem) {
4655                 var tempDate = new Date();
4656                 if (timeString && meridiem) {
4657                     var timeSplit = timeString.split(':');
4658                     var hour = ((meridiem === 'PM' || meridiem === 'pm') && timeSplit[0] !== '12') ? parseInt(timeSplit[0], 10) + 12 : parseInt(timeSplit[0], 10);
4659                     tempDate.setHours(hour, parseInt(timeSplit[1], 10), 0, 0);
4660                 }
4661
4662                 return tempDate.getTime();
4663             };
4664         }
4665     }
4666 }])
4667
4668 .directive('b2bHourpickerValue', [function () {
4669     return {
4670         restrict: 'EA',
4671         replace: false,
4672         templateUrl: 'b2bTemplate/hourPicker/b2bHourpickerValue.html',
4673         controller: ['$scope', function (scope) {
4674
4675         }],
4676         link: function (scope, elem, attr, ctrl) {
4677             scope.hourpickerValue = {};
4678             scope.hourpickerValue.startTime = attr.startTime ? scope.$eval(attr.startTime) : '';
4679             scope.hourpickerValue.startMeridiem = attr.startMeridiem ? scope.$eval(attr.startMeridiem) : '';
4680             scope.hourpickerValue.endTime = attr.endTime ? scope.$eval(attr.endTime) : '';
4681             scope.hourpickerValue.endMeridiem = attr.endMeridiem ? scope.$eval(attr.endMeridiem) : '';
4682             scope.hourpickerValue.days = attr.days ? scope.$eval(attr.days).join(', ') : '';
4683             scope.hourpickerValue.index = attr.b2bHourpickerValue ? scope.$eval(attr.b2bHourpickerValue) : -1;
4684         }
4685     }
4686 }]);
4687 /**
4688  * @ngdoc directive
4689  * @name Template.att:inputTemplate
4690  *
4691  * @description
4692  *  <file src="src/inputTemplate/docs/readme.md" />
4693  *
4694  * @usage
4695  *  <input type="text" id="fieldId" placeholder="placholder text here" class="span12 input-enhanced" name="fieldName">
4696  *
4697  * @example
4698  <section id="code">
4699     <b>HTML + AngularJS</b>
4700     <example module="b2b.att">
4701         <file src="src/inputTemplate/docs/demo.html" />
4702         <file src="src/inputTemplate/docs/demo.js" />
4703     </example>
4704  </section>
4705  */
4706 angular.module('b2b.att.inputTemplate', []);
4707
4708 /**
4709  * @ngdoc directive
4710  * @name Navigation.att:leftNavigation
4711  *
4712  * @description
4713  *  <file src="src/leftNavigation/docs/readme.md" />
4714  *
4715  * @usage
4716  *   <b2b-left-navigation data-menu="menuData"></b2b-left-navigation> 
4717  *
4718  * @example
4719  *  <section id="code">
4720         <example module="b2b.att">
4721             <file src="src/leftNavigation/docs/demo.html" />
4722             <file src="src/leftNavigation/docs/demo.js" />
4723        </example>
4724     </section>
4725  *
4726  */
4727 angular.module('b2b.att.leftNavigation', [])
4728     .directive('b2bLeftNavigation', [function () {
4729         return {
4730             restrict: 'EA',
4731             templateUrl: 'b2bTemplate/leftNavigation/leftNavigation.html',
4732             scope: {
4733                 menuData: '='
4734             },
4735             link: function (scope, element, attrs, ctrl) {
4736                 scope.idx = -1;
4737                 scope.itemIdx = -1;
4738                 scope.navIdx = -1;
4739                 scope.toggleNav = function (val) {
4740                     if (val === scope.idx) {
4741                         scope.idx = -1;
4742                         return;
4743                     }
4744                     scope.idx = val;
4745                 };
4746                 scope.liveLink = function (evt, val1, val2) {
4747                     scope.itemIdx = val1;
4748                     scope.navIdx = val2;
4749                     evt.stopPropagation();
4750                 };
4751             }
4752         };
4753     }]);
4754 /**
4755  * @ngdoc directive
4756  * @name Buttons, links & UI controls.att:links
4757  *
4758  * @description
4759  *  <file src="src/links/docs/readme.md" />
4760  * @usage
4761  *      <!-- See below examples for link implementation -->
4762  *      
4763  * @example
4764        <section id="code">              
4765            <b>HTML + AngularJS</b>
4766            <example module="b2b.att">
4767            <file src="src/links/docs/demo.html" />
4768             <file src="src/links/docs/demo.js" />            
4769           </example>          
4770         </section>
4771  */
4772 angular.module('b2b.att.links', []);
4773 /**
4774  * @ngdoc directive
4775  * @name Misc.att:listbox
4776  *
4777  * @description
4778  *  <file src="src/listbox/docs/readme.md" />
4779  *
4780  * @param {int} currentIndex - Current index of selected listbox item. Is not supported on multiselect listbox
4781  * @param {Array} listboxData - Data of listbox items. Should include full data regardless if HTML will be filtered.
4782
4783  * @example
4784  *  <section id="code">   
4785      <example module="b2b.att">
4786      <file src="src/listbox/docs/demo.html" />
4787      <file src="src/listbox/docs/demo.js" />
4788      </example>
4789     </section>
4790  *
4791  */
4792 angular.module('b2b.att.listbox', ['b2b.att.utilities'])
4793 .directive('b2bListBox', ['keymap', 'b2bDOMHelper', '$rootScope', function(keymap, b2bDOMHelper, $rootScope) {
4794                 return {
4795                     restrict: 'AE',
4796                     transclude: true,
4797                     replace: true,
4798                     scope: {
4799                         currentIndex: '=', 
4800                         listboxData: '='
4801                     },
4802                     templateUrl: 'b2bTemplate/listbox/listbox.html',
4803                     link: function(scope, elem, attr) {
4804
4805                         if (attr.ariaMultiselectable !== undefined || attr.ariaMultiselectable === 'true') {
4806                             scope.multiselectable = true;
4807                         } else {
4808                             scope.multiselectable = false;
4809                         }
4810
4811                         var shiftKey = false;
4812                         var elements = [];
4813                         var prevDirection = undefined; // previous direction is used for an edge case when shifting
4814                         var shiftKeyPressed = false; // Used to handle shift clicking
4815                         var ctrlKeyPressed = false;
4816
4817                         var currentIndexSet = {
4818                             'elementIndex': 0,
4819                             'listboxDataIndex': 0
4820                         };
4821
4822                         function isTrue(item) {
4823                             if (item.selected === true) {
4824                                 return true;
4825                             }
4826                         }
4827
4828                         function incrementIndex(elem) {
4829                             $rootScope.$apply();
4830
4831                             var nextElem = elem.next();
4832                             if (!angular.isDefined(nextElem) || nextElem.length === 0) {
4833                                 return;
4834                             }
4835
4836                             currentIndexSet.elementIndex += 1;
4837                             currentIndexSet.listboxDataIndex = parseInt(nextElem.attr('data-index'), 10);
4838                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4839
4840                             if (currentIndexSet.elementIndex >= elements.length - 1) {
4841                                 currentIndexSet.elementIndex = elements.length-1;
4842                             }
4843                         }
4844
4845                         function decrementIndex(elem) {
4846                             $rootScope.$apply();
4847                             var prevElem = angular.element(b2bDOMHelper.previousElement(elem));
4848                             if (!angular.isDefined(prevElem) || prevElem.length === 0) {
4849                                 return;
4850                             }
4851
4852                             currentIndexSet.elementIndex -= 1;
4853                             currentIndexSet.listboxDataIndex = parseInt(prevElem.attr('data-index'), 10);
4854                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4855
4856                             if (currentIndexSet.elementIndex <= 0) {
4857                                 currentIndexSet.elementIndex = 0;
4858                             }
4859                         }
4860
4861                         var focusOnElement = function(index) {
4862                             try {
4863                                 elements[index].focus();
4864                             } catch (e) {};
4865                         }
4866
4867                         function selectItems(startIndex, endIndex, forceValue) {
4868                             for (var i = startIndex; i < endIndex; i++) {
4869                                 if (forceValue === undefined) {
4870                                     // We will flip the value
4871                                     scope.listboxData[i].selected = !scope.listboxData[i].selected;
4872                                 } else {
4873                                     scope.listboxData[i].selected = forceValue;
4874                                 }
4875                             }
4876
4877                             if (!scope.$$phase) {
4878                                 scope.$apply();
4879                             }
4880                         }
4881
4882                         elem.bind('focus', function(evt) { 
4883                             // If multiselectable or not and nothing is selected, put focus on first element 
4884                             // If multiselectable and a range is set, put focus on first element of range 
4885                             // If not multiselectable and something selected, put focus on element 
4886                             elements = elem.children(); 
4887                              var selectedItems = scope.listboxData.filter(isTrue); 
4888                              var elementsIndies = Array.prototype.map.call(elements, function(item) {
4889                                 return parseInt(angular.element(item).attr('data-index'), 10);
4890                             });
4891  
4892                             if (selectedItems.length == 0) { 
4893                                 focusOnElement(0); 
4894                                 currentIndexSet.listboxDataIndex = 0;
4895                             } else if (attr.ariaMultiselectable) { 
4896                                 var index = scope.listboxData.indexOf(selectedItems[0]); 
4897                                 var indies = elementsIndies.filter(function(item) {
4898                                     return (item === index);
4899                                 });
4900
4901                                 if (indies.length === 0 || indies[0] != index) {
4902                                     // Set focused on 0
4903                                     currentIndexSet.elementIndex = elementsIndies[0]; 
4904                                     currentIndexSet.listboxDataIndex = 0;
4905                                     focusOnElement(currentIndexSet.elementIndex);
4906                                 } else {
4907                                     focusOnElement(indies[0]); 
4908                                     currentIndexSet.elementIndex = indies[0];
4909                                     currentIndexSet.listboxDataIndex = index;
4910                                 }
4911                             } else { 
4912                                 focusOnElement(currentIndexSet.elementIndex);  
4913                             }
4914                             scope.currentIndex = currentIndexSet.listboxDataIndex;
4915
4916                             if (!scope.$$phase) {
4917                                 scope.$apply();
4918                             }
4919                         });
4920                         elem.bind('keyup', function(evt) {
4921                             if (evt.keyCode === keymap.KEY.SHIFT) {
4922                                 shiftKeyPressed = false;
4923                             } else if (evt.keyCode === keymap.KEY.CTRL) {
4924                                 ctrlKeyPressed = false;
4925                             }
4926                         });
4927                 
4928                         elem.bind('keydown', function(evt) {
4929                             var keyCode = evt.keyCode;
4930                             elements = elem.children();
4931                             if (keyCode === keymap.KEY.SHIFT) {
4932                                 shiftKeyPressed = true;
4933                             } else if (evt.keyCode === keymap.KEY.CTRL) {
4934                                 ctrlKeyPressed = true;
4935                             }
4936
4937                             switch(keyCode) {
4938                                 case 65: // A key
4939                                 {
4940                                     if (scope.multiselectable && evt.ctrlKey) {
4941                                         var arr = scope.listboxData.filter(isTrue);
4942                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {
4943                                             return parseInt(angular.element(item).attr('data-index'), 10);
4944                                         });
4945                                         var val = !(arr.length === scope.listboxData.length);
4946                                         for (var i = 0; i < elementsIndies.length; i++) {
4947                                             scope.listboxData[elementsIndies[i]].selected = val;
4948                                         }
4949
4950                                         if (!scope.$$phase) {
4951                                             scope.$apply();
4952                                         }
4953                                         
4954                                         evt.preventDefault();
4955                                         evt.stopPropagation();
4956                                     }
4957                                     break;
4958                                 }
4959                                 case keymap.KEY.END:
4960                                 {
4961                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {
4962                                         var elementsIndies = Array.prototype.map.call(elements, function(item) {
4963                                             return parseInt(angular.element(item).attr('data-index'), 10);
4964                                         }).filter(function(item) {
4965                                             return (item >= currentIndexSet.listboxDataIndex);
4966                                         });
4967                                         for (var i = 0; i < elementsIndies.length; i++) {
4968                                             scope.listboxData[elementsIndies[i]].selected = true;
4969                                         }
4970                                         evt.preventDefault();
4971                                         evt.stopPropagation();
4972
4973                                         if (!scope.$$phase) {
4974                                             scope.$apply();
4975                                         }
4976                                     }
4977                                     break;
4978                                 }
4979                                 case keymap.KEY.HOME: 
4980                                 {
4981                                     if (scope.multiselectable && evt.ctrlKey && evt.shiftKey) {
4982                                         selectItems(0, currentIndexSet.listboxDataIndex+1, true); // currentIndex+1 is what is being focused on
4983                                         evt.preventDefault();
4984                                         evt.stopPropagation();
4985                                     }
4986                                     break;
4987                                 }
4988                                 case keymap.KEY.LEFT:
4989                                 case keymap.KEY.UP:
4990                                 {
4991                                     if (currentIndexSet.listboxDataIndex === 0) {
4992                                         evt.preventDefault();
4993                                         evt.stopPropagation();
4994                                         return;
4995                                     }
4996
4997                                     decrementIndex(elements.eq(currentIndexSet.elementIndex));
4998                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {
4999                                         if (evt.shiftKey) {
5000                                             if (prevDirection === 'DOWN') {
5001                                                 scope.listboxData[currentIndexSet.listboxDataIndex+1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex+1].selected;
5002                                             }
5003                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;
5004                                         }
5005                                         prevDirection = 'UP';
5006                                     } else {
5007                                         // If no modifier keys are selected, all other items need to be unselected.
5008                                         prevDirection = undefined;
5009                                         selectItems(0, scope.listboxData.length, false);
5010                                         if(currentIndexSet.listboxDataIndex !== undefined && !isNaN(currentIndexSet.listboxDataIndex)){
5011                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;
5012                                         }
5013                                     }
5014                                     focusOnElement(currentIndexSet.elementIndex);
5015                                     if(!scope.$$phase) {
5016                                         scope.$apply();
5017                                     }
5018                                     evt.preventDefault();
5019                                     evt.stopPropagation();
5020                                     break;
5021                                 }
5022                                 case keymap.KEY.RIGHT:
5023                                 case keymap.KEY.DOWN:
5024                                 {
5025                                     if (currentIndexSet.listboxDataIndex === scope.listboxData.length-1) {
5026                                         evt.preventDefault();
5027                                         evt.stopPropagation();
5028                                         return;
5029                                     }
5030
5031                                     incrementIndex(elements.eq(currentIndexSet.elementIndex));
5032                                     
5033                                     if (scope.multiselectable && (evt.shiftKey || evt.ctrlKey)) {
5034                                         if (evt.shiftKey) {
5035                                             if (prevDirection === 'UP') {
5036                                                 scope.listboxData[currentIndexSet.listboxDataIndex-1].selected = !scope.listboxData[currentIndexSet.listboxDataIndex-1].selected;
5037                                             }
5038                                             
5039                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = !scope.listboxData[currentIndexSet.listboxDataIndex].selected;    
5040                                         }
5041                                         prevDirection = 'DOWN';
5042                                     } else {
5043                                         // If no modifier keys are selected, all other items need to be unselected.
5044                                         prevDirection = undefined;
5045                                         selectItems(0, scope.listboxData.length, false);
5046                                         if(currentIndexSet.listboxDataIndex !== undefined && !isNaN(currentIndexSet.listboxDataIndex)){
5047                                             scope.listboxData[currentIndexSet.listboxDataIndex].selected = true;
5048                                         }
5049                                     }
5050
5051                                     focusOnElement(currentIndexSet.elementIndex);
5052                                     if(!scope.$$phase) {
5053                                         scope.$apply();
5054                                     }
5055                                     evt.preventDefault();
5056                                     evt.stopPropagation();
5057                                     break;
5058                                 }
5059                                 case keymap.KEY.TAB:
5060                                     if(evt.shiftKey) {
5061                                         var previousElement = b2bDOMHelper.previousElement(elem.parent().parent(), true);
5062                                         evt.preventDefault();
5063                                         previousElement.focus();
5064                                     }
5065                                     break;
5066                                 default:
5067                                     break;
5068                             }
5069                         });
5070
5071                         elem.bind('click', function(evt) {
5072                             var index = parseInt(evt.target.dataset.index, 10);
5073                             if (index === undefined || isNaN(index)) {
5074                                 return;
5075                             }
5076                             if (scope.multiselectable && currentIndexSet.listboxDataIndex !== undefined) {
5077                                 if (shiftKeyPressed) {
5078                                     var min = Math.min(index, currentIndexSet.listboxDataIndex);
5079                                     var max = Math.max(index, currentIndexSet.listboxDataIndex);
5080
5081                                     if (index === min) { // clicking up
5082                                         var firstIndex = scope.listboxData.findIndex(function(item) { return item.selected === true;});
5083                                         // Given the firstIndex, let's find the matching element to get proper element match
5084                                         elements = elem.children();
5085                                         elements.eq(firstIndex)
5086                                         var elementsThatMatch = Array.prototype.filter.call(elements, function(item) {
5087                                             if (parseInt(angular.element(item).attr('data-index'), 10) === firstIndex) {
5088                                                 return true;
5089                                             }
5090                                         });
5091                                         firstIndex = parseInt(angular.element(elementsThatMatch).attr('data-index'), 10);
5092                                         
5093                                         if (index <= firstIndex && scope.listboxData.filter(isTrue).length > 1) {
5094                                             // Break the selection into 2
5095                                             selectItems(firstIndex + 1, max + 1, undefined); // + 1 needed because selectItems only selects up to MAX
5096                                             selectItems(min, firstIndex, undefined); 
5097                                         } else if (scope.listboxData.filter(isTrue).length == 1){
5098                                             selectItems(min, max, undefined); 
5099                                         } else {
5100                                             selectItems(min + 1, max + 1, undefined);
5101                                         }
5102                                     } else { // clicking down
5103                                         selectItems(min + 1, max + 1, scope.listboxData[min].selected);
5104                                     }
5105                                 } else if (ctrlKeyPressed) {
5106                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;
5107                                 } else {
5108                                     selectItems(0, scope.listboxData.length, false);
5109                                     scope.listboxData[index].selected = !scope.listboxData[index].selected;
5110                                 }
5111                             } else {
5112                                 selectItems(0, scope.listboxData.length, false);
5113                                 scope.listboxData[index].selected = !scope.listboxData[index].selected;
5114                             }
5115                             currentIndexSet.elementIndex = index;
5116                             currentIndexSet.listboxDataIndex = index;
5117                             scope.currentIndex = currentIndexSet.listboxDataIndex;
5118                             if (!scope.$$phase) {
5119                                 scope.$apply();
5120                             }
5121                             focusOnElement(index);
5122                         });
5123                     }
5124                 };
5125             }]);
5126 /**
5127  * @ngdoc directive
5128  * @name Videos, audio & animation.att:loaderAnimation
5129  *
5130  * @description
5131  *  <file src="src/loaderAnimation/docs/readme.md" />
5132  *
5133  * @usage
5134  *   <!-- Below demo js shows-->
5135  *   Angular library uses Global.css's icon-primary-spinner.
5136  *
5137  * @example
5138  *  <section id="code">
5139         <example module="b2b.att">
5140             <file src="src/loaderAnimation/docs/demo.html" />
5141             <file src="src/loaderAnimation/docs/demo.js" />
5142        </example>
5143     </section>
5144  *
5145  */
5146 angular.module('b2b.att.loaderAnimation', [])
5147     .constant('b2bSpinnerConfig', {
5148         loadingText: 'Loading...',
5149         startEvent: 'startButtonSpinner',
5150         stopEvent: 'stopButtonSpinner'
5151     })
5152     .constant("progressTrackerConfig", {
5153         loadingText: 'Loading...',
5154         minDuration: "",
5155         activationDelay: "",
5156         minDurationPromise: "",
5157         activationDelayPromise: ""
5158     })
5159
5160 .provider('progressTracker', function () {
5161     this.$get = ['$q', '$timeout', function ($q, $timeout) {
5162         function cancelTimeout(promise) {
5163             if (promise) {
5164                 $timeout.cancel(promise);
5165             }
5166         }
5167         return function ProgressTracker(options) {
5168             //do new if user doesn't
5169             if (!(this instanceof ProgressTracker)) {
5170                 return new ProgressTracker(options);
5171             }
5172
5173             options = options || {};
5174             //Array of promises being tracked
5175             var tracked = [];
5176             var self = this;
5177             //Allow an optional "minimum duration" that the tracker has to stay active for.
5178             var minDuration = options.minDuration;
5179             //Allow a delay that will stop the tracker from activating until that time is reached
5180             var activationDelay = options.activationDelay;
5181             var minDurationPromise;
5182             var activationDelayPromise;
5183             self.active = function () {
5184                 //Even if we have a promise in our tracker, we aren't active until delay is elapsed
5185                 if (activationDelayPromise) {
5186                     return false;
5187                 }
5188                 return tracked.length > 0;
5189             };
5190             self.tracking = function () {
5191                 //Even if we aren't active, we could still have a promise in our tracker
5192                 return tracked.length > 0;
5193             };
5194             self.destroy = self.cancel = function () {
5195                 minDurationPromise = cancelTimeout(minDurationPromise);
5196                 activationDelayPromise = cancelTimeout(activationDelayPromise);
5197                 for (var i = tracked.length - 1; i >= 0; i--) {
5198                     tracked[i].resolve();
5199                 }
5200                 tracked.length = 0;
5201             };
5202             //Create a promise that will make our tracker active until it is resolved.
5203             // @return deferred - our deferred object that is being tracked
5204             self.createPromise = function () {
5205                 var deferred = $q.defer();
5206                 tracked.push(deferred);
5207                 //If the tracker was just inactive and this the first in the list of promises, we reset our delay and minDuration again.
5208                 if (tracked.length === 1) {
5209                     if (activationDelay) {
5210                         activationDelayPromise = $timeout(function () {
5211                             activationDelayPromise = cancelTimeout(activationDelayPromise);
5212                             startMinDuration();
5213                         }, activationDelay);
5214                     } else {
5215                         startMinDuration();
5216                     }
5217                 }
5218                 deferred.promise.then(onDone(false), onDone(true));
5219                 return deferred;
5220
5221                 function startMinDuration() {
5222                     if (minDuration) {
5223                         minDurationPromise = $timeout(angular.noop, minDuration);
5224                     }
5225                 }
5226                 //Create a callback for when this promise is done. It will remove our tracked promise from the array if once minDuration is complete
5227                 function onDone() {
5228                     return function () {
5229                         (minDurationPromise || $q.when()).then(function () {
5230                             var index = tracked.indexOf(deferred);
5231                             tracked.splice(index, 1);
5232                             //If this is the last promise, cleanup the timeouts for activationDelay
5233                             if (tracked.length === 0) {
5234                                 activationDelayPromise = cancelTimeout(activationDelayPromise);
5235                             }
5236                         });
5237                     };
5238                 }
5239             };
5240             self.addPromise = function (promise) {
5241                 
5242 //                we cannot assign then function in other var and then add the resolve and reject 
5243                 var thenFxn = promise && (promise.then || promise.$then || (promise.$promise && promise.$promise.then));                
5244                 if (!thenFxn) {
5245                     throw new Error("progressTracker expects a promise object :: Not found");
5246                 }
5247                 var deferred = self.createPromise();
5248                 //When given promise is done, resolve our created promise
5249                 //Allow $then for angular-resource objects
5250
5251                 promise.then(function (value) {
5252                         deferred.resolve(value);
5253                         return value;
5254                     }, function (value) {
5255                         deferred.reject(value);
5256                         return $q.reject(value);
5257                     }
5258                 );
5259                 return deferred;
5260             };
5261         };
5262     }];
5263 })
5264
5265 .config(['$httpProvider', function ($httpProvider) {
5266     $httpProvider.interceptors.push(['$q', 'progressTracker', function ($q) {
5267         return {
5268             request: function (config) {
5269                 if (config.tracker) {
5270                     if (!angular.isArray(config.tracker)) {
5271                         config.tracker = [config.tracker];
5272                     }
5273                     config.$promiseTrackerDeferred = config.$promiseTrackerDeferred || [];
5274
5275                     angular.forEach(config.tracker, function (tracker) {
5276                         var deferred = tracker.createPromise();
5277                         config.$promiseTrackerDeferred.push(deferred);
5278                     });
5279                 }
5280                 return $q.when(config);
5281             },
5282             response: function (response) {
5283                 if (response.config && response.config.$promiseTrackerDeferred) {
5284                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {
5285                         deferred.resolve(response);
5286                     });
5287                 }
5288                 return $q.when(response);
5289             },
5290             responseError: function (response) {
5291                 if (response.config && response.config.$promiseTrackerDeferred) {
5292                     angular.forEach(response.config.$promiseTrackerDeferred, function (deferred) {
5293                         deferred.reject(response);
5294                     });
5295                 }
5296                 return $q.reject(response);
5297             }
5298         };
5299     }]);
5300 }])
5301
5302 .directive('b2bClickSpin', ['$timeout', '$parse', '$rootScope', 'progressTracker', function ($timeout, $parse, $rootScope, progressTracker) {
5303     return {
5304         restrict: 'A',
5305         link: function (scope, elm, attrs) {
5306             var fn = $parse(attrs.b2bClickSpin);
5307             elm.on('click', function (event) {
5308                 var promise = $timeout(function () {console.log("inside Promise")}, 5000);
5309                 scope.$apply(function () {
5310                     fn(scope, {
5311                         $event: event
5312                     });
5313                 });
5314                 //comment this line if not running unit test
5315                 $rootScope.loadingTracker = progressTracker({
5316                     minDuration: 750
5317                 });
5318                 $rootScope.loadingTracker.addPromise(promise);
5319                 angular.forEach("$routeChangeSuccess $viewContentLoaded $locationChangeSuccess".split(" "), function (event) {
5320                     $rootScope.$on(event, function () {
5321
5322                         $timeout.cancel(promise);
5323                     });
5324                 });
5325             });
5326         }
5327     };
5328 }])
5329
5330 .directive('b2bProgressTracker', ['progressTrackerConfig', function (ptc) {
5331     return {
5332         restrict: 'EA',
5333         replace: true,
5334         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>'
5335     };
5336 }])
5337
5338 .directive('b2bLoadButton', ['b2bSpinnerConfig', '$timeout', function (spinnerConfig, $timeout) {
5339     var spinButton = function (state, element, data) {
5340         
5341         var attr = element.html() ? 'html' : 'val';
5342         state = state + 'Text';
5343         if (state === 'loadingText') {
5344             element[attr](data[state]);
5345             element.attr("disabled",'disabled');
5346             element.addClass('disabled');
5347         } else if (state === 'resetText') {
5348             element[attr](data[state]);
5349             element.removeAttr("disabled");
5350             element.removeClass('disabled');
5351         }
5352     };
5353
5354     return {
5355         restrict: 'A',
5356         replace: false,
5357         scope: {
5358             promise: '=promise',
5359             startEvent: '@startEvent',
5360             stopEvent: '@stopEvent'
5361         },
5362         link: function (scope, element, attr) {
5363             var validAttr = element.html() ? 'html' : 'val';
5364             var data = {
5365                 loadingText: '',
5366                 resetText: ''
5367             };
5368
5369             var updateLoadingText = function (val) {
5370                 var loadingText = val;
5371                 if (!angular.isDefined(loadingText) || loadingText === "") {
5372                     loadingText = spinnerConfig.loadingText;
5373                 }
5374                 data.loadingText = validAttr === 'html' ? "<i class=\"icon-primary-spinner small\"></i>" + loadingText : loadingText;
5375             };
5376             var updateResetText = function (val) {
5377                 data.resetText = val;
5378             };
5379
5380             attr.$observe('b2bLoadButton', function (val) {
5381                 updateLoadingText(val);
5382             });
5383             $timeout(function () {
5384                 updateResetText(element[validAttr]());
5385             }, 500);
5386
5387             if (!angular.isDefined(scope.startEvent) || scope.startEvent === "") {
5388                 scope.startEvent = spinnerConfig.startEvent;
5389             }
5390
5391             if (!angular.isDefined(scope.stopEvent) || scope.stopEvent === "") {
5392                 scope.stopEvent = spinnerConfig.stopEvent;
5393             }
5394
5395             scope.$watch('promise', function () {
5396                 if (angular.isDefined(scope.promise) && angular.isFunction(scope.promise.then)) {
5397                     spinButton('loading', element, data);
5398                     scope.promise.then(function () {
5399                         spinButton('reset', element, data);
5400                     }, function () {
5401                         spinButton('reset', element, data);
5402                     });
5403                 }
5404             });
5405
5406             scope.$on(scope.startEvent, function () {
5407                 spinButton('loading', element, data);
5408                 scope.$on(scope.stopEvent, function () {
5409                     spinButton('reset', element, data);
5410                 });
5411             });
5412         }
5413     };
5414 }]);
5415  /**
5416  * @ngdoc directive
5417  * @name Misc.att:messageWrapper
5418  * @scope
5419  * @param {boolean} trigger - A boolean that triggers directive to switch focus
5420  * @param {integer} delay  - Extra delay added to trigger code to allow for DOM to be ready. Default is 10ms.
5421  * @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)
5422  * @param {string} trapFocus - Attribute-based API to trap focus within the message. This should be enabled by default on all toast messages.
5423  * @description
5424  *  <file src="src/messageWrapper/docs/readme.md" />
5425  * @usage
5426  * <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>
5427  *
5428  * @example
5429  *  <section id="code">   
5430  <b>HTML + AngularJS</b>
5431  <example module="b2b.att">
5432  <file src="src/messageWrapper/docs/demo.html" />
5433  <file src="src/messageWrapper/docs/demo.js" />
5434  </example>
5435  </section>
5436  *
5437  */
5438 angular.module('b2b.att.messageWrapper', ['b2b.att.utilities'])
5439 .directive('b2bMessageWrapper', ['b2bDOMHelper', '$compile', '$timeout', '$log', function(b2bDOMHelper, $compile, $timeout, $log) {
5440   return {
5441     restrict: 'AE',
5442     scope: {
5443       trigger: '=',
5444       delay: '=?'
5445     },
5446     transclude: true,
5447     replace: true,
5448     template: '<div ng-transclude></div>',
5449     link: function(scope, elem, attrs) {
5450       scope.delay = scope.delay || 10;
5451
5452       if (attrs.trapFocus != undefined && !elem.children().eq(0).attr('b2b-trap-focus-inside-element')) {
5453         // Append b2bTrapFocusInsideElement onto first child and recompile
5454         elem.children().eq(0).attr('b2b-trap-focus-inside-element', 'false');
5455         elem.children().eq(0).attr('trigger', scope.trigger);
5456         $compile(elem.contents())(scope);
5457       }
5458
5459       var firstElement = undefined,
5460           launchingElement = undefined;
5461       
5462       scope.$watch('trigger', function(oldVal, newVal) {
5463         if (oldVal === newVal) return;
5464         if (!angular.isDefined(launchingElement)) {
5465           launchingElement = document.activeElement;
5466         }
5467         $timeout(function() {
5468           if (scope.trigger) {
5469
5470             if (attrs.noFocus === true || attrs.noFocus === "") {
5471               elem.children()[0].focus();
5472             } else {
5473               firstElement = b2bDOMHelper.firstTabableElement(elem);
5474
5475               if (angular.isDefined(firstElement)) {
5476                 firstElement.focus();
5477               }
5478             }
5479             
5480           } else {
5481             if (angular.isDefined(launchingElement) && launchingElement.nodeName !== 'BODY') {
5482               if (launchingElement === document.activeElement) {
5483                 return;
5484               }
5485
5486               if (b2bDOMHelper.isInDOM(launchingElement) && b2bDOMHelper.isTabable(launchingElement)) {
5487                   // At this point, launchingElement is still a valid element, but focus will fail and 
5488                   // activeElement will become body, hence we want to apply custom logic and find previousElement
5489                   var prevLaunchingElement = launchingElement;
5490                   launchingElement.focus();
5491
5492                   if (document.activeElement !== launchingElement || document.activeElement.nodeName === 'BODY') {
5493                     launchingElement = b2bDOMHelper.previousElement(angular.element(prevLaunchingElement), true);
5494                     launchingElement.focus();
5495                   }
5496               } else {
5497                 launchingElement = b2bDOMHelper.previousElement(launchingElement, true);
5498                 launchingElement.focus();
5499               }
5500             }
5501           }
5502         }, scope.delay); 
5503       });
5504     }
5505   };
5506 }]);
5507 /**
5508  * @ngdoc directive
5509  * @name Messages, modals & alerts.att:modalsAndAlerts
5510  *
5511  * @description
5512  *  <file src="src/modalsAndAlerts/docs/readme.md" />
5513  *
5514  * @usage
5515  *  <button class="btn" b2b-modal="b2bTemplate/modalsAndAlerts/demo_modal.html" modal-ok="ok()" modal-cancel="cancel()">Launch demo modal</button>
5516  *
5517  * @example
5518  *  <section id="code">
5519      <example module="b2b.att">
5520       <file src="src/modalsAndAlerts/docs/demo.html" />
5521       <file src="src/modalsAndAlerts/docs/demo.js" />
5522      </example>
5523     </section>
5524  *
5525  */
5526 angular.module('b2b.att.modalsAndAlerts', ['b2b.att.position', 'b2b.att.transition', 'b2b.att.utilities'])
5527
5528 /**
5529  * A helper, internal data structure that acts as a map but also allows getting / removing
5530  * elements in the LIFO order
5531  */
5532 .factory('$$stackedMap', function () {
5533     return {
5534         createNew: function () {
5535             var stack = [];
5536
5537             return {
5538                 add: function (key, value) {
5539                     stack.push({
5540                         key: key,
5541                         value: value
5542                     });
5543                 },
5544                 get: function (key) {
5545                     for (var i = 0; i < stack.length; i++) {
5546                         if (key === stack[i].key) {
5547                             return stack[i];
5548                         }
5549                     }
5550                 },
5551                 keys: function () {
5552                     var keys = [];
5553                     for (var i = 0; i < stack.length; i++) {
5554                         keys.push(stack[i].key);
5555                     }
5556                     return keys;
5557                 },
5558                 top: function () {
5559                     return stack[stack.length - 1];
5560                 },
5561                 remove: function (key) {
5562                     var idx = -1;
5563                     for (var i = 0; i < stack.length; i++) {
5564                         if (key === stack[i].key) {
5565                             idx = i;
5566                             break;
5567                         }
5568                     }
5569                     return stack.splice(idx, 1)[0];
5570                 },
5571                 removeTop: function () {
5572                     return stack.splice(stack.length - 1, 1)[0];
5573                 },
5574                 length: function () {
5575                     return stack.length;
5576                 }
5577             };
5578         }
5579     };
5580 }).factory('trapFocusInElement', ['$document', '$isElement', 'b2bDOMHelper', 'keymap', function ($document, $isElement, b2bDOMHelper, keymap) {
5581     var elementStack = [];
5582     var stackHead = undefined;
5583     var firstTabableElement, lastTabableElement;
5584
5585     var trapKeyboardFocusInFirstElement = function (e) {
5586         if (!e.keyCode) {
5587             e.keyCode = e.which;
5588         }
5589
5590         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
5591             lastTabableElement[0].focus();
5592             e.preventDefault(e);
5593             e.stopPropagation(e);
5594         }
5595
5596     };
5597
5598     var trapKeyboardFocusInLastElement = function (e) {
5599         if (!e.keyCode) {
5600             e.keyCode = e.which;
5601         }
5602
5603         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
5604             firstTabableElement[0].focus();
5605             e.preventDefault(e);
5606             e.stopPropagation(e);
5607         }
5608     };
5609     
5610     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {
5611         var bodyElements = $document.find('body').children();
5612
5613         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(b2bDOMHelper.firstTabableElement(stackHead));
5614         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(b2bDOMHelper.lastTabableElement(stackHead));
5615
5616         if (flag) {
5617             for (var i = 0; i < bodyElements.length; i++) {
5618                 if (bodyElements[i] !== stackHead[0]) {
5619                     bodyElements.eq(i).attr('aria-hidden', true);
5620                 }
5621             }
5622             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
5623             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
5624         } else {
5625             for (var j = 0; j < bodyElements.length; j++) {
5626                 if (bodyElements[j] !== stackHead[0]) {
5627                     bodyElements.eq(j).removeAttr('aria-hidden');
5628                 }
5629             }
5630             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
5631             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
5632         }
5633     };
5634     var toggleTrapFocusInElement = function (flag, element) {
5635         if (angular.isDefined(flag) && angular.isDefined(element)) {
5636             if (angular.isUndefined(stackHead)) {
5637                 stackHead = element;
5638                 trapFocusInElement(flag);
5639             } else {
5640                 if (flag) {
5641                     trapFocusInElement(false);
5642                     elementStack.push(stackHead);
5643                     stackHead = element;
5644                     trapFocusInElement(true);
5645                 } else {
5646                     if (stackHead.prop('$$hashKey') === element.prop('$$hashKey')) {
5647                         trapFocusInElement(false);
5648                         stackHead = elementStack.pop();
5649                         if (angular.isDefined(stackHead)) {
5650                             trapFocusInElement(true);
5651                         }
5652                     }
5653                 }
5654             }
5655         }else {
5656             if (angular.isDefined(stackHead)) {
5657                 trapFocusInElement(false, firstTabableElement, lastTabableElement);
5658                 trapFocusInElement(true);
5659             }
5660         }
5661     };
5662
5663     return toggleTrapFocusInElement;
5664 }])
5665
5666 /**
5667  * A helper directive for the $modal service. It creates a backdrop element.
5668  */
5669 .directive('b2bModalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
5670     return {
5671         restrict: 'EA',
5672         replace: true,
5673         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-backdrop.html',
5674         link: function (scope, element, attrs) {
5675             scope.close = function (evt) {
5676                 var modal = $modalStack.getTop();
5677                 if (modal && modal.value.backdrop && modal.value.backdrop !== 'static') {
5678                     evt.preventDefault();
5679                     evt.stopPropagation();
5680                     $modalStack.dismiss(modal.key, 'backdrop click');
5681                 }
5682             };
5683         }
5684     };
5685 }])
5686
5687 .directive('b2bModalWindow', ['$timeout', 'windowOrientation', '$window', 'keymap', function ($timeout, windowOrientation, $window, keymap) {
5688     return {
5689         restrict: 'EA',
5690         scope: {
5691             index: '@'
5692         },
5693         replace: true,
5694         transclude: true,
5695         templateUrl: 'b2bTemplate/modalsAndAlerts/b2b-window.html',
5696         controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {
5697             scope.windowClass = attrs.windowClass || '';
5698             scope.sizeClass = attrs.sizeClass || '';
5699             scope.isNotifDialog = false;
5700             scope.modalClose = attrs.modalClose || false;
5701
5702             this.setTitle = function (title) {
5703                 scope.title = title;
5704             };
5705             this.setContent = function (content) {
5706                 scope.content = content;
5707                 scope.isNotifDialog = true;
5708             };
5709             this.isDockedModal = scope.windowClass.indexOf('modal-docked') > -1;
5710         }],
5711         link: function (scope, element, attrs, ctrl) {
5712             if (ctrl.isDockedModal) {
5713                 scope.isModalLandscape = false;
5714
5715                 var window = angular.element($window);
5716                 scope.updateCss = function () {
5717                     if (windowOrientation.isPotrait()) { // Potrait Mode
5718                         scope.isModalLandscape = false;
5719                     } else if (windowOrientation.isLandscape()) { // Landscape Mode
5720                         scope.isModalLandscape = true;
5721                     }
5722                 };
5723
5724                 $timeout(function () {
5725                     scope.updateCss();
5726                     scope.$apply();
5727                 }, 100);
5728                 window.bind('orientationchange', function () {
5729                     scope.updateCss();
5730                     scope.$apply();
5731                 });
5732                 window.bind('resize', function () {
5733                     scope.updateCss();
5734                     scope.$apply();
5735                 });
5736             }else {
5737                 angular.element(element[0].querySelectorAll(".awd-select-list")).css({
5738                     "max-height": "200px"
5739                 });
5740             }
5741
5742             var isIE = /msie|trident/i.test(navigator.userAgent);
5743             if (isIE) {
5744                 if(angular.element(element[0].querySelector('.corner-button button.close')).length > 0){
5745                     angular.element(element[0].querySelector('.corner-button button.close')).bind('focus', function () {
5746                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollLeft = 0;
5747                        angular.element(element[0].querySelector('.b2b-modal-header'))[0].scrollTop = 0;
5748                     });
5749                 }
5750             }
5751
5752             if(scope.modalClose){
5753                 element.bind('keydown', function (e) {
5754                     if(e.keyCode == keymap.KEY.ESC){
5755                         e.preventDefault();
5756                         e.stopPropagation();
5757                     }
5758                 });
5759             }
5760         }
5761     };
5762 }])
5763
5764 .directive('b2bModalTitle', [function () {
5765     return {
5766         restrict: 'A',
5767         require: '^b2bModalWindow',
5768         link: function (scope, elem, attr, ctrl) {
5769             ctrl.setTitle(attr.id);
5770         }
5771     };
5772 }])
5773
5774 .directive('b2bModalContent', [function () {
5775     return {
5776         restrict: 'A',
5777         require: '^b2bModalWindow',
5778         link: function (scope, elem, attr, ctrl) {
5779             ctrl.setContent(attr.id);
5780         }
5781     };
5782 }])
5783
5784
5785 .directive('b2bModalBody', ['$timeout', '$position', '$document', '$window', 'windowOrientation', 'b2bAwdBreakpoints', function ($timeout, $position, $document, $window, windowOrientation, b2bAwdBreakpoints) {
5786     return {
5787         restrict: 'AC',
5788         scope: {
5789             index: '@'
5790         },
5791         require: '^b2bModalWindow',
5792         link: function (scope, element, attrs, ctrl) {
5793             var window = angular.element($window);
5794             var body = $document.find('body').eq(0);
5795             scope.setModalHeight = function () {
5796                 var modalHeaderHeight, modalFooterHeight, modalBodyHeight, windowHeight, windowWidth, modalHeight;
5797                 modalHeaderHeight = 0;
5798                 modalFooterHeight = 0;
5799                 windowHeight = $window.innerHeight;
5800                 windowWidth = $window.innerWidth;
5801                 body.css({
5802                     'height': windowHeight + 'px'
5803                 });
5804
5805                 if (ctrl.isDockedModal) {
5806                     var modalElements = element.parent().children();
5807                     for (var i = 0; i < modalElements.length; i++) {
5808                         if (modalElements.eq(i).hasClass('b2b-modal-header')) {
5809                             modalHeaderHeight = $position.position(modalElements.eq(i)).height;
5810                         } else if (modalElements.eq(i).hasClass('b2b-modal-footer')) {
5811                             modalFooterHeight = $position.position(modalElements.eq(i)).height;
5812                         }
5813                     }
5814
5815                     modalHeight = $position.position(element.parent()).height;
5816
5817                     modalBodyHeight = modalHeight - (modalHeaderHeight + modalFooterHeight) + 'px';
5818
5819                     if (windowOrientation.isPotrait()) { // Potrait Mode
5820                         element.removeAttr('style').css({
5821                             height: modalBodyHeight
5822                         });
5823                     } else if (windowOrientation.isLandscape() && windowWidth < b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Mobile
5824                         element.removeAttr('style');
5825                     } else if (windowOrientation.isLandscape() && windowWidth >= b2bAwdBreakpoints.breakpoints.mobile.max) { // Landscape Mode Non-Mobile
5826                         element.removeAttr('style').css({
5827                             height: modalBodyHeight
5828                         });
5829                     }
5830                 }
5831             };
5832
5833             $timeout(function () {
5834                 scope.setModalHeight();
5835                 scope.$apply();
5836             }, 100);
5837             window.bind('orientationchange', function () {
5838                 scope.setModalHeight();
5839                 scope.$apply();
5840             });
5841             window.bind('resize', function () {
5842                 scope.setModalHeight();
5843                 scope.$apply();
5844             });
5845         }
5846     };
5847 }])
5848
5849 .directive('b2bModalFooter', ['windowOrientation', '$window', function (windowOrientation, $window) {
5850     return {
5851         restrict: 'AC',
5852         scope: {
5853             index: '@'
5854         },
5855         link: function (scope, element, attrs) {
5856
5857         }
5858     };
5859 }])
5860
5861 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', '$log', '$timeout', 'trapFocusInElement', function ($document, $compile, $rootScope, $$stackedMap, $log, $timeout, trapFocusInElement) {
5862     var backdropjqLiteEl, backdropDomEl;
5863     var backdropScope = $rootScope.$new(true);
5864     var body = $document.find('body').eq(0);
5865     var html = $document.find('html').eq(0);
5866     var openedWindows = $$stackedMap.createNew();
5867     var $modalStack = {};
5868
5869     function backdropIndex() {
5870         var topBackdropIndex = -1;
5871         var opened = openedWindows.keys();
5872         for (var i = 0; i < opened.length; i++) {
5873             if (openedWindows.get(opened[i]).value.backdrop) {
5874                 topBackdropIndex = i;
5875             }
5876         }
5877         return topBackdropIndex;
5878     }
5879
5880     $rootScope.$watch(backdropIndex, function (newBackdropIndex) {
5881         backdropScope.index = newBackdropIndex;
5882     });
5883
5884     function removeModalWindow(modalInstance) {
5885         //background scroll fix
5886         html.removeAttr('style');
5887         body.removeAttr('style');
5888         body.removeClass('styled-by-modal');
5889
5890         var modalWindow = openedWindows.get(modalInstance).value;
5891         trapFocusInElement(false, modalWindow.modalDomEl);
5892
5893         //clean up the stack
5894         openedWindows.remove(modalInstance);
5895
5896         //remove window DOM element
5897         modalWindow.modalDomEl.remove();
5898
5899         //remove backdrop if no longer needed
5900         if (backdropDomEl && backdropIndex() === -1) {
5901             backdropDomEl.remove();
5902             backdropDomEl = undefined;
5903         }
5904
5905         //destroy scope
5906         modalWindow.modalScope.$destroy();
5907     }
5908
5909     $document.bind('keydown', function (evt) {
5910         var modal;
5911
5912         if (evt.which === 27) {
5913             modal = openedWindows.top();
5914             if (modal && modal.value.keyboard) {
5915                 $rootScope.$apply(function () {
5916                     $modalStack.dismiss(modal.key);
5917                 });
5918             }
5919         }
5920     });
5921
5922     $modalStack.open = function (modalInstance, modal) {
5923
5924         openedWindows.add(modalInstance, {
5925             deferred: modal.deferred,
5926             modalScope: modal.scope,
5927             backdrop: modal.backdrop,
5928             keyboard: modal.keyboard
5929         });
5930
5931         var angularDomEl = angular.element('<div b2b-modal-window></div>');
5932         angularDomEl.attr('window-class', modal.windowClass);
5933         angularDomEl.attr('size-class', modal.sizeClass);
5934         angularDomEl.attr('index', openedWindows.length() - 1);
5935         angularDomEl.attr('modal-close', modal.modalClose);
5936         angularDomEl.html(modal.content);
5937
5938         var modalDomEl = $compile(angularDomEl)(modal.scope);
5939         openedWindows.top().value.modalDomEl = modalDomEl;
5940         //background page scroll fix
5941         html.css({
5942             'overflow-y': 'hidden'
5943         });
5944         body.css({
5945             'overflow-y': 'hidden',
5946             'width': '100%',
5947             'height': window.innerHeight + 'px'
5948         });
5949         body.addClass('styled-by-modal');
5950         body.append(modalDomEl);
5951
5952         if (backdropIndex() >= 0 && !backdropDomEl) {
5953             backdropjqLiteEl = angular.element('<div b2b-modal-backdrop></div>');
5954             backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
5955             body.append(backdropDomEl);
5956         }
5957
5958         $timeout(function () {
5959
5960             if (modal.scope.$$childHead.isNotifDialog) {
5961                 angular.element(modalDomEl).find('button')[0].focus();
5962             } else {
5963                 angular.element(modalDomEl)[0].focus();
5964             }
5965             trapFocusInElement(true, angular.element(modalDomEl).eq(0));
5966         }, 200);
5967     };
5968
5969     $modalStack.close = function (modalInstance, result) {
5970         var modal = openedWindows.get(modalInstance);
5971         if (modal) {
5972             modal.value.deferred.resolve(result);
5973             removeModalWindow(modalInstance);
5974         }
5975     };
5976
5977     $modalStack.dismiss = function (modalInstance, reason) {
5978         var modalWindow = openedWindows.get(modalInstance).value;
5979         if (modalWindow) {
5980             modalWindow.deferred.reject(reason);
5981             removeModalWindow(modalInstance);
5982         }
5983     };
5984
5985     $modalStack.getTop = function () {
5986         return openedWindows.top();
5987     };
5988
5989     return $modalStack;
5990 }])
5991
5992 .provider('$modal', function () {
5993     var $modalProvider = {
5994         options: {
5995             backdrop: true, //can be also false or 'static'
5996             keyboard: true
5997         },
5998         $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
5999             var $modal = {};
6000
6001             function getTemplatePromise(options) {
6002                 return options.template ? $q.when(options.template) :
6003                     $http.get(options.templateUrl, {
6004                         cache: $templateCache
6005                     }).then(function (result) {
6006                         return result.data;
6007                     });
6008             }
6009
6010             function getResolvePromises(resolves) {
6011                 var promisesArr = [];
6012                 angular.forEach(resolves, function (value, key) {
6013                     if (angular.isFunction(value) || angular.isArray(value)) {
6014                         promisesArr.push($q.when($injector.invoke(value)));
6015                     }
6016                 });
6017                 return promisesArr;
6018             }
6019
6020             $modal.open = function (modalOptions) {
6021
6022                 var modalResultDeferred = $q.defer();
6023                 var modalOpenedDeferred = $q.defer();
6024                 //prepare an instance of a modal to be injected into controllers and returned to a caller
6025                 var modalInstance = {
6026                     result: modalResultDeferred.promise,
6027                     opened: modalOpenedDeferred.promise,
6028                     close: function (result) {
6029                         $modalStack.close(modalInstance, result);
6030                     },
6031                     dismiss: function (reason) {
6032                         $modalStack.dismiss(modalInstance, reason);
6033                     }
6034                 };
6035
6036                 //merge and clean up options
6037                 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
6038                 modalOptions.resolve = modalOptions.resolve || {};
6039
6040                 //verify options
6041                 if (!modalOptions.template && !modalOptions.templateUrl) {
6042                     throw new Error('One of template or templateUrl options is required.');
6043                 }
6044
6045                 var templateAndResolvePromise =
6046                     $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
6047
6048
6049                 templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
6050
6051                     var modalScope = (modalOptions.scope || $rootScope).$new();
6052                     modalScope.$close = modalInstance.close;
6053                     modalScope.$dismiss = modalInstance.dismiss;
6054
6055                     var ctrlInstance, ctrlLocals = {};
6056                     var resolveIter = 1;
6057
6058                     //controllers
6059                     if (modalOptions.controller) {
6060                         ctrlLocals.$scope = modalScope;
6061                         ctrlLocals.$modalInstance = modalInstance;
6062                         angular.forEach(modalOptions.resolve, function (value, key) {
6063                             ctrlLocals[key] = tplAndVars[resolveIter++];
6064                         });
6065
6066                         ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
6067                     }
6068
6069                     $modalStack.open(modalInstance, {
6070                         scope: modalScope,
6071                         deferred: modalResultDeferred,
6072                         content: tplAndVars[0],
6073                         backdrop: modalOptions.backdrop,
6074                         keyboard: modalOptions.keyboard,
6075                         windowClass: modalOptions.windowClass,
6076                         sizeClass: modalOptions.sizeClass,
6077                         modalClose: modalOptions.modalClose
6078                     });
6079
6080                 }, function resolveError(reason) {
6081                     modalResultDeferred.reject(reason);
6082                 });
6083
6084                 templateAndResolvePromise.then(function () {
6085                     modalOpenedDeferred.resolve(true);
6086                 }, function () {
6087                     modalOpenedDeferred.reject(false);
6088                 });
6089
6090                 return modalInstance;
6091             };
6092
6093             return $modal;
6094         }]
6095     };
6096
6097     return $modalProvider;
6098 })
6099
6100 .directive("b2bModal", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {
6101     return {
6102         restrict: 'A',
6103         scope: {
6104             b2bModal: '@',
6105             modalController: '@',
6106             modalOk: '&',
6107             modalCancel: '&',
6108             windowClass: '@',
6109             sizeClass: '@', 
6110             modalClose: '@'
6111         },
6112         link: function (scope, elm, attr) {
6113             elm.bind('click', function (ev) {
6114                 var currentPosition = ev.pageY - ev.clientY;
6115                 ev.preventDefault();
6116                 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {
6117                     scope.b2bModal = elm.attr("href");
6118                 }
6119                 $modal.open({
6120                     templateUrl: scope.b2bModal,
6121                     controller: scope.modalController,
6122                     windowClass: scope.windowClass,
6123                     sizeClass: scope.sizeClass, 
6124                     modalClose: scope.modalClose
6125                 }).result.then(function (value) {
6126                     scope.modalOk({
6127                         value: value
6128                     });
6129                     elm[0].focus();
6130                 }, function (value) {
6131                     scope.modalCancel({
6132                         value: value
6133                     });
6134                     elm[0].focus();
6135                 });
6136             });
6137         }
6138     };
6139 }])
6140
6141 .directive("utilityFilter", ["$modal", "$log", '$scrollTo', function ($modal, $log, $scrollTo) {
6142     return {
6143         restrict: 'EA',
6144         scope: {
6145             utilityFilter: '@'
6146         },
6147         require: 'ngModel',
6148         templateUrl: 'b2bTemplate/modal/u-filter.html',
6149         link: function (scope, element, attribute, ctrl) {
6150             //controller to be passed to $modal service
6151             scope.options = angular.copy(scope.$parent.$eval(attribute.ngModel));
6152             scope.$parent.$watch(attribute.ngModel, function (newVal, oldVal) {
6153                 if (newVal !== oldVal) {
6154                     scope.options = newVal;
6155                 }
6156             });
6157             var modalCtrl = function ($scope, options) {
6158                 $scope.options = angular.copy(options);
6159             };
6160
6161             if (angular.isDefined(scope.utilityFilter)) {
6162                 scope.templateUrl = scope.utilityFilter;
6163             } else {
6164                 scope.templateUrl = 'b2bTemplate/modal/u-filter-window.html';
6165             }
6166             element.bind('click', function (ev) {
6167                 var currentPosition = ev.pageY - ev.clientY;
6168                 $modal.open({
6169                     templateUrl: scope.templateUrl,
6170                     controller: modalCtrl,
6171                     resolve: {
6172                         options: function () {
6173                             return scope.options;
6174                         }
6175                     }
6176                 }).result.then(function (value) {
6177                     ctrl.$setViewValue(value);
6178                     element[0].focus();
6179                     $scrollTo(0, currentPosition, 0);
6180                 }, function () {
6181                     element[0].focus();
6182                     $scrollTo(0, currentPosition, 0);
6183                 });
6184             });
6185         }
6186     };
6187 }]);
6188 /**
6189  * @ngdoc directive
6190  * @name Forms.att:monthSelector
6191  *
6192  * @description
6193  *  <file src="src/monthSelector/docs/readme.md" />
6194  *
6195  * @usage
6196  * <div b2b-monthpicker ng-model="dt" min="minDate" max="maxDate" mode="monthpicker"></div>
6197     
6198  * @example
6199  *  <section id="code">
6200         <example module="b2b.att">
6201             <file src="src/monthSelector/docs/demo.html" />
6202             <file src="src/monthSelector/docs/demo.js" />
6203         </example>
6204     </section>
6205  *
6206  */
6207 angular.module('b2b.att.monthSelector', ['b2b.att.position', 'b2b.att.utilities'])
6208
6209 .constant('b2bMonthpickerConfig', {
6210     dateFormat: 'MM/dd/yyyy',
6211     dayFormat: 'd',
6212     monthFormat: 'MMMM',
6213     yearFormat: 'yyyy',
6214     dayHeaderFormat: 'EEEE',
6215     dayTitleFormat: 'MMMM yyyy',
6216     disableWeekend: false,
6217     disableSunday: false,
6218     disableDates: null,
6219     onSelectClose: null,
6220     startingDay: 0,
6221     minDate: null,
6222     maxDate: null,
6223     dueDate: null,
6224     fromDate: null,
6225     legendIcon: null,
6226     legendMessage: null,
6227     calendarDisabled: false,
6228     collapseWait: 0,
6229     orientation: 'left',
6230     inline: false,
6231     mode:0,
6232     helperText: 'The date you selected is $date. Double tap to open calendar. Select a date to close the calendar.',
6233     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.',
6234     MonthpickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'collapseWait', 'orientation','mode','id'],
6235     MonthpickerWatchAttributes: ['min', 'max', 'due', 'from', 'legendIcon', 'legendMessage', 'ngDisabled'],
6236     MonthpickerFunctionAttributes: ['disableDates', 'onSelectClose']
6237 })
6238
6239 .factory('b2bMonthpickerService', ['b2bMonthpickerConfig', 'dateFilter', function (b2bMonthpickerConfig, dateFilter) {
6240     var setAttributes = function (attr, elem) {
6241         if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
6242             var attributes = b2bMonthpickerConfig.MonthpickerEvalAttributes.concat(b2bMonthpickerConfig.MonthpickerWatchAttributes, b2bMonthpickerConfig.MonthpickerFunctionAttributes);
6243             for (var key in attr) {
6244                 var val = attr[key];
6245                 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6246                     elem.attr(key.toSnakeCase(), key);
6247                 }
6248             }
6249         }
6250     };
6251
6252     var bindScope = function (attr, scope) {
6253         if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
6254             var evalFunction = function (key, val) {
6255                 scope[key] = scope.$parent.$eval(val);
6256             };
6257
6258             var watchFunction = function (key, val) {
6259                 scope.$parent.$watch(val, function (value) {
6260                     scope[key] = value;
6261                 });
6262                 scope.$watch(key, function (value) {
6263                     scope.$parent[val] = value;
6264                 });
6265             };
6266
6267             var evalAttributes = b2bMonthpickerConfig.MonthpickerEvalAttributes;
6268             var watchAttributes = b2bMonthpickerConfig.MonthpickerWatchAttributes;
6269             for (var key in attr) {
6270                 var val = attr[key];
6271                 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6272                     evalFunction(key, val);
6273                 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
6274                     watchFunction(key, val);
6275                 }
6276             }
6277         }
6278     };
6279
6280     return {
6281         setAttributes: setAttributes,
6282         bindScope: bindScope
6283     };
6284 }])
6285
6286 .controller('b2bMonthpickerController', ['$scope', '$attrs', 'dateFilter', '$element', '$position', 'b2bMonthpickerConfig', function ($scope, $attrs, dateFilter, $element, $position, dtConfig) {
6287     var format = {
6288             date: getValue($attrs.dateFormat, dtConfig.dateFormat),
6289             day: getValue($attrs.dayFormat, dtConfig.dayFormat),
6290             month: getValue($attrs.monthFormat, dtConfig.monthFormat),
6291             year: getValue($attrs.yearFormat, dtConfig.yearFormat),
6292             dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
6293             dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
6294             disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
6295             disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday),
6296             disableDates: getValue($attrs.disableDates, dtConfig.disableDates)
6297         },
6298         startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
6299
6300     $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
6301     $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
6302     $scope.dueDate = dtConfig.dueDate ? $scope.resetTime(dtConfig.dueDate) : null;
6303     $scope.fromDate = dtConfig.fromDate ? $scope.resetTime(dtConfig.fromDate) : null;
6304     $scope.legendIcon = dtConfig.legendIcon ? dtConfig.legendIcon : null;
6305     $scope.legendMessage = dtConfig.legendMessage ? dtConfig.legendMessage : null;
6306     $scope.ngDisabled = dtConfig.calendarDisabled ? dtConfig.calendarDisabled : null;
6307     $scope.collapseWait = getValue($attrs.collapseWait, dtConfig.collapseWait);
6308     $scope.orientation = getValue($attrs.orientation, dtConfig.orientation);
6309     $scope.onSelectClose = getValue($attrs.onSelectClose, dtConfig.onSelectClose);
6310     $scope.mode = getValue($attrs.mode, dtConfig.mode);
6311     
6312     $scope.inline = $attrs.inline === 'true' ? true : dtConfig.inline;
6313
6314     function getValue(value, defaultValue) {
6315         return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
6316     }
6317
6318     function getDaysInMonth(year, month) {
6319         return new Date(year, month, 0).getDate();
6320     }
6321
6322     function getDates(startDate, n) {
6323         var dates = new Array(n);
6324         var current = startDate,
6325             i = 0;
6326         while (i < n) {
6327             dates[i++] = new Date(current);
6328             current.setDate(current.getDate() + 1);
6329         }
6330         return dates;
6331     }
6332
6333     this.updatePosition = function (b2bMonthpickerPopupTemplate) {
6334         $scope.position = $position.offset($element);
6335         if($element.find('input').length > 0 ){
6336             $scope.position.top += $element.find('input').prop('offsetHeight');
6337         }else{
6338             $scope.position.top += $element.find('a').prop('offsetHeight');
6339         }
6340         
6341         if ($scope.orientation === 'right') {
6342             $scope.position.left -= (((b2bMonthpickerPopupTemplate && b2bMonthpickerPopupTemplate.prop('offsetWidth')) || 290) - $element.find('input').prop('offsetWidth'));
6343         }
6344     };
6345
6346     function isSelected(dt) { 
6347         if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
6348             return true;
6349         }
6350         return false;
6351     }
6352
6353     function isFromDate(dt) {
6354         if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
6355             return true;
6356         }
6357         return false;
6358     }
6359
6360     function isDateRange(dt) {
6361         if (dt && $scope.fromDate && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
6362             return true;
6363         } else if (dt && $scope.fromDate && compare(dt, $scope.fromDate) === 0) {
6364             return true;
6365         }
6366         return false;
6367     }
6368
6369     function isOld(date, currentMonthDate) {
6370         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())) {
6371             return true;
6372         } else {
6373             return false;
6374         }
6375     }
6376
6377     function isNew(date, currentMonthDate) {
6378         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())) {
6379             return true;
6380         } else {
6381             return false;
6382         }
6383     }
6384
6385     function isPastDue(dt) {
6386         if ($scope.dueDate) {
6387             return (dt > $scope.dueDate);
6388         }
6389         return false;
6390     }
6391
6392     function isDueDate(dt) {
6393         if ($scope.dueDate) {
6394             return (dt.getTime() === $scope.dueDate.getTime());
6395         }
6396         return false;
6397     }
6398
6399     var isDisabled = function (date, currentMonthDate) {
6400         if ($attrs.from && !angular.isDate($scope.fromDate)) {
6401             return true;
6402         }
6403         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
6404             return true;
6405         }
6406         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
6407             return true;
6408         }
6409         if (isOld(date, currentMonthDate) || isNew(date, currentMonthDate)) {
6410             return true;
6411         }
6412         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({
6413             date: date
6414         })));
6415     };
6416     
6417     var isDisabledMonth = function (date, currentMonthDate) {
6418         if ($attrs.from && !angular.isDate($scope.fromDate)) {
6419             return true;
6420         }
6421         if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
6422             return true;
6423         }
6424         if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
6425             return true;
6426         }
6427         return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0) || (format.disableDates && format.disableDates({
6428             date: date
6429         })));
6430     };    
6431          
6432     var compare = function (date1, date2) {
6433         return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
6434     };
6435
6436     function isMinDateAvailable(startDate, endDate) {
6437         if (($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
6438             $scope.disablePrev = true;
6439             $scope.visibilityPrev = "hidden";
6440         } else {
6441             $scope.disablePrev = false;
6442             $scope.visibilityPrev = "visible";
6443         }
6444     }
6445     
6446     function isMaxDateAvailable(startDate, endDate) {
6447         if (($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
6448             $scope.disableNext = true;
6449             $scope.visibilityNext = "hidden";
6450         } else {
6451             $scope.disableNext = false;
6452             $scope.visibilityNext = "visible";
6453         }
6454     }    
6455     
6456     function isYearInRange(currentYear) {
6457             
6458         if ($scope.minDate && currentYear === $scope.minDate.getFullYear()) {
6459             $scope.disablePrev = true;
6460             $scope.visibilityPrev = "hidden";
6461         } else {
6462             $scope.disablePrev = false;
6463             $scope.visibilityPrev = "visible";
6464         }
6465         
6466         if ($scope.maxDate && currentYear === $scope.maxDate.getFullYear()) {
6467             $scope.disableNext = true;
6468             $scope.visibilityNext = "hidden";
6469         } else {
6470             $scope.disableNext = false;
6471             $scope.visibilityNext = "visible";
6472         }
6473         
6474     }    
6475
6476     this.focusNextPrev = function(b2bMonthpickerPopupTemplate,init){
6477         if(init){
6478             if (!$scope.disablePrev){
6479                 b2bMonthpickerPopupTemplate[0].querySelector('th.prev').focus();
6480             }else if (!$scope.disableNext){
6481                 b2bMonthpickerPopupTemplate[0].querySelector('th.next').focus();
6482             }else{
6483                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();
6484             }
6485         }else{
6486             if ($scope.disableNext || $scope.disablePrev){
6487                 b2bMonthpickerPopupTemplate[0].querySelector('th.b2b-monthSelector-label').focus();
6488             }       
6489         }    
6490     };
6491
6492     function getLabel(label) {
6493         if (label) {
6494             var labelObj = {
6495                 pre: label.substr(0, 1).toUpperCase(),
6496                 post: label
6497             };
6498             return labelObj;
6499         }
6500         return;
6501     }
6502
6503     function makeDate(date, dayFormat, dayHeaderFormat, isSelected, isFromDate, isDateRange, isOld, isNew, isDisabled, dueDate, pastDue) {
6504         return {
6505             date: date,
6506             label: dateFilter(date, dayFormat),
6507             header: dateFilter(date, dayHeaderFormat),
6508             selected: !!isSelected,
6509             fromDate: !!isFromDate,
6510             dateRange: !!isDateRange,
6511             oldMonth: !!isOld,
6512             nextMonth: !!isNew,
6513             disabled: !!isDisabled,
6514             dueDate: !!dueDate,
6515             pastDue: !!pastDue,
6516             focusable: !((isDisabled && !(isSelected || isDateRange)) || (isOld || isNew))
6517         };
6518     }
6519     
6520     this.modes = [
6521         {
6522             name: 'day',
6523             getVisibleDates: function (date) {
6524                 var year = date.getFullYear(),
6525                     month = date.getMonth(),
6526                     firstDayOfMonth = new Date(year, month, 1),
6527                     lastDayOfMonth = new Date(year, month + 1, 0);
6528                 var difference = startingDay - firstDayOfMonth.getDay(),
6529                     numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
6530                     firstDate = new Date(firstDayOfMonth),
6531                     numDates = 0;
6532
6533                 if (numDisplayedFromPreviousMonth > 0) {
6534                     firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
6535                     numDates += numDisplayedFromPreviousMonth; // Previous
6536                 }
6537                 numDates += getDaysInMonth(year, month + 1); // Current
6538                 numDates += (7 - numDates % 7) % 7; // Next
6539
6540                 var days = getDates(firstDate, numDates),
6541                     labels = new Array(7);
6542                 for (var i = 0; i < numDates; i++) {
6543                     var dt = new Date(days[i]);
6544                     days[i] = makeDate(dt,
6545                         format.day,
6546                         format.dayHeader,
6547                         isSelected(dt),
6548                         isFromDate(dt),
6549                         isDateRange(dt),
6550                         isOld(dt, date),
6551                         isNew(dt, date),
6552                         isDisabled(dt, date),
6553                         isDueDate(dt),
6554                         isPastDue(dt));
6555                 }
6556                 for (var j = 0; j < 7; j++) {
6557                     labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
6558                 }
6559                 isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
6560                 isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
6561                 return {
6562                     objects: days,
6563                     title: dateFilter(date, format.dayTitle),
6564                     labels: labels
6565                 };
6566             },
6567             split: 7,
6568             step: {
6569                 months: 1
6570             }
6571         },
6572         {
6573             name: 'month',
6574             getVisibleDates: function(date) {
6575                 var months = [], 
6576                     labels = [], 
6577                     year = date.getFullYear();
6578                     for (var i = 0; i < 12; i++) {
6579                         var dt = new Date(year,i,1);                
6580                         months[i] = makeDate(dt,
6581                                     format.month,
6582                                     format.dayHeader,
6583                                     isSelected(dt), 
6584                                     isFromDate(dt),
6585                                     isDateRange(dt),
6586                                     false,
6587                                     false,
6588                                     isDisabledMonth(dt, date),
6589                                     isDueDate(dt),                                       
6590                                     isPastDue(dt));                                                                                                                                                         
6591                     }
6592                 isYearInRange(year);  
6593                 return {objects: months, title: dateFilter(date, format.year), labels: labels};
6594             },
6595             split:4,
6596             step: {years: 1}
6597         }
6598     ];
6599 }])
6600
6601 .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) {
6602     return {
6603         restrict: 'EA',
6604         scope: {
6605           trigger: '='
6606         },
6607         replace: true,
6608         transclude: true,
6609         templateUrl: function (elem, attr) {
6610             if (attr.inline === 'true') {
6611                 return 'b2bTemplate/monthSelector/monthSelector-popup.html';
6612             }else if (attr.link === 'true') {
6613                 return 'b2bTemplate/monthSelector/monthSelectorLink.html';
6614             }else {
6615                 return 'b2bTemplate/monthSelector/monthSelector.html';
6616             }
6617         },
6618         scope: {},
6619         require: ['b2bMonthpickerPopup', 'ngModel', '?^b2bMonthpickerGroup'],
6620         controller: 'b2bMonthpickerController',
6621         link: function (scope, element, attrs, ctrls) {
6622             var MonthpickerCtrl = ctrls[0],
6623                 ngModel = ctrls[1],
6624                 b2bMonthpickerGroupCtrl = ctrls[2];
6625             var b2bMonthpickerPopupTemplate;
6626
6627             if (!ngModel) {
6628                 $log.error("ng-model is required.");
6629                 return; // do nothing if no ng-model
6630             }
6631
6632             // Configuration parameters
6633             var mode = scope.mode,
6634                 selected;
6635             scope.isOpen = false;
6636
6637             scope.headers = [];
6638             scope.footers = [];
6639             scope.triggerInterval=undefined;
6640
6641
6642             if (b2bMonthpickerGroupCtrl) {
6643                 b2bMonthpickerGroupCtrl.registerMonthpickerScope(scope);
6644             }
6645
6646             element.bind('keydown', function (ev) {                   
6647                 if (!ev.keyCode) {
6648                     if (ev.which) {
6649                         ev.keyCode = ev.which;
6650                     } else if (ev.charCode) {
6651                         ev.keyCode = ev.charCode;
6652                     }
6653                 }                                
6654                 if(ev.keyCode === keymap.KEY.ESC)
6655                 {
6656                     scope.isOpen = false;
6657                     toggleCalendar(scope.isOpen);
6658                     scope.$apply();
6659                 }
6660             });
6661             
6662             element.find('button').bind('click', function () {
6663                 onClicked();                
6664             });
6665
6666             element.find('a').bind('click', function () {
6667                 onClicked();                
6668             });
6669
6670             
6671             element.find('input').bind('click', function () {
6672                 onClicked();
6673             });
6674
6675             var onClicked = function() {        
6676                 if (!scope.ngDisabled) {
6677                     scope.isOpen = !scope.isOpen;
6678                     toggleCalendar(scope.isOpen);                    
6679                     MonthpickerCtrl.updatePosition(b2bMonthpickerPopupTemplate);
6680                     scope.$apply();
6681                 }
6682             };
6683         
6684             var toggleCalendar = function (flag) {
6685                 if (!scope.inline) {
6686                     if (flag) {
6687                         b2bMonthpickerPopupTemplate = angular.element($templateCache.get('b2bTemplate/monthSelector/monthSelector-popup.html'));
6688                         b2bMonthpickerPopupTemplate.attr('b2b-trap-focus-inside-element', 'false');
6689                         b2bMonthpickerPopupTemplate.attr('trigger', 'true');
6690                         b2bMonthpickerPopupTemplate = $compile(b2bMonthpickerPopupTemplate)(scope);
6691                         $document.find('body').append(b2bMonthpickerPopupTemplate);
6692                         b2bMonthpickerPopupTemplate.bind('keydown', escPress);
6693                         $timeout(function () {
6694                             scope.getFocus = true;
6695                             scope.trigger=0;
6696                             scope.$apply();
6697                             $timeout(function () {
6698                                 scope.getFocus = false;
6699                                 scope.$apply();
6700                                 MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,true);
6701                             }, 100);
6702                         });
6703                         scope.triggerInterval = $interval(function () {
6704                             //This value is updated to trigger init() function of directive on year change.
6705                             scope.trigger=(scope.trigger === 0 ? 1 : 0);
6706                         }, 200);
6707
6708                     } else {
6709                         b2bMonthpickerPopupTemplate.unbind('keydown', escPress);
6710                         if(scope.triggerInterval)
6711                         {
6712                             $interval.cancel(scope.triggerInterval);
6713                             scope.triggerInterval=undefined;
6714                         }
6715                         b2bMonthpickerPopupTemplate.remove();
6716                         if(element.find('button').length > 0){
6717                             element.find('button')[0].focus();
6718                         }else{
6719                             element.find('a')[0].focus();
6720                         }
6721                         
6722                         scope.getFocus = false;
6723                     }
6724                 }
6725             };
6726
6727             var outsideClick = function (e) {
6728                 var isElement = $isElement(angular.element(e.target), element, $document);
6729                 var isb2bMonthpickerPopupTemplate = $isElement(angular.element(e.target), b2bMonthpickerPopupTemplate, $document);
6730                 if (!(isElement || isb2bMonthpickerPopupTemplate)) {
6731                     scope.isOpen = false;
6732                     toggleCalendar(scope.isOpen);
6733                     scope.$apply();
6734                 }
6735             };
6736
6737             var escPress = function (ev) {
6738                 if (!ev.keyCode) {
6739                     if (ev.which) {
6740                         ev.keyCode = ev.which;
6741                     } else if (ev.charCode) {
6742                         ev.keyCode = ev.charCode;
6743                     }
6744                 }
6745                 if (ev.keyCode) {
6746                     if (ev.keyCode === keymap.KEY.ESC) {
6747                         scope.isOpen = false;
6748                         toggleCalendar(scope.isOpen);
6749                         ev.preventDefault();
6750                         ev.stopPropagation();
6751                     } else if (ev.keyCode === 33) {
6752                         !scope.disablePrev && scope.move(-1);
6753                         $timeout(function () {
6754                             scope.getFocus = true;
6755                             scope.$apply();
6756                             $timeout(function () {
6757                                 scope.getFocus = false;
6758                                 scope.$apply();
6759                             }, 100);
6760                         });
6761                         ev.preventDefault();
6762                         ev.stopPropagation();
6763                     } else if (ev.keyCode === 34) {
6764                         !scope.disableNext && scope.move(1);
6765                         $timeout(function () {
6766                             scope.getFocus = true;
6767                             scope.$apply();
6768                             $timeout(function () {
6769                                 scope.getFocus = false;
6770                                 scope.$apply();
6771                             }, 100);
6772                         });
6773                         ev.preventDefault();
6774                         ev.stopPropagation();
6775                     }
6776                     scope.$apply();
6777                 }
6778             };                          
6779                                         
6780             $documentBind.click('isOpen', outsideClick, scope);
6781
6782             scope.$on('$destroy', function () {
6783                 if (scope.isOpen) {
6784                     scope.isOpen = false;
6785                     toggleCalendar(scope.isOpen);
6786                 }
6787             });
6788
6789             scope.resetTime = function (date) {
6790                 if (typeof date === 'string') {
6791                     date = date + 'T12:00:00';
6792                 }
6793                 var dt;
6794                 if (!isNaN(new Date(date))) {
6795                     dt = new Date(date);
6796                     if(scope.mode === 1){
6797                         dt = new Date(dt.getFullYear(), dt.getMonth());
6798                     }else{
6799                         dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
6800                     }                                                            
6801                 } else {
6802                     return null;
6803                 }
6804                 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
6805             };
6806             
6807             if (attrs.min) {
6808                 scope.$parent.$watch($parse(attrs.min), function (value) {
6809                     scope.minDate = value ? scope.resetTime(value) : null;
6810                     refill();
6811                 });
6812             }
6813             if (attrs.max) {
6814                 scope.$parent.$watch($parse(attrs.max), function (value) {
6815                     scope.maxDate = value ? scope.resetTime(value) : null;
6816                     refill();
6817                 });
6818             }
6819             if (attrs.due) {
6820                 scope.$parent.$watch($parse(attrs.due), function (value) {
6821                     scope.dueDate = value ? scope.resetTime(value) : null;
6822                     refill();
6823                 });
6824             }
6825             if (attrs.from) {
6826                 scope.$parent.$watch($parse(attrs.from), function (value) {
6827                     scope.fromDate = value ? scope.resetTime(value) : null;
6828                     refill();
6829                 });
6830             }
6831
6832             if (attrs.legendIcon) {
6833                 scope.$parent.$watch(attrs.legendIcon, function (value) {
6834                     scope.legendIcon = value ? value : null;
6835                     refill();
6836                 });
6837             }
6838             if (attrs.legendMessage) {
6839                 scope.$parent.$watch(attrs.legendMessage, function (value) {
6840                     scope.legendMessage = value ? value : null;
6841                     refill();
6842                 });
6843             }
6844             if (attrs.ngDisabled) {
6845                 scope.$parent.$watch(attrs.ngDisabled, function (value) {
6846                     scope.ngDisabled = value ? value : null;
6847                 });
6848             }      
6849             
6850
6851             // Split array into smaller arrays
6852             function split(arr, size) {
6853                 var arrays = [];
6854                 while (arr.length > 0) {
6855                     arrays.push(arr.splice(0, size));
6856                 }
6857                 return arrays;
6858             }
6859             
6860             var moveMonth = function(selectedDate, direction) {
6861                 var step = MonthpickerCtrl.modes[scope.mode].step;
6862                 selectedDate.setDate(1);
6863                 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));
6864                 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));
6865
6866                 return selectedDate;
6867             };            
6868
6869             function refill(date) {
6870                 if (angular.isDate(date) && !isNaN(date)) {
6871                     selected = new Date(date);
6872                 } else {
6873                     if (!selected) {
6874                         selected = new Date();
6875                     }
6876                 }
6877
6878                 if (selected) {                    
6879                     var selectedCalendar;
6880                     if(scope.mode === 1){
6881                         if(!angular.isDate(selected))
6882                            {                           
6883                                 selected = new Date();
6884                            }
6885                         selectedCalendar = moveMonth(angular.copy(selected), -1);
6886                     } else {
6887                         selectedCalendar = angular.copy(selected);
6888                     }
6889                     
6890                     var currentMode = MonthpickerCtrl.modes[mode],
6891                         data = currentMode.getVisibleDates(selected);
6892
6893                     scope.rows = split(data.objects, currentMode.split);
6894             
6895                     var flag=false;
6896                     var startFlag=false;
6897                     var firstSelected = false;
6898                     for(var i=0; i<scope.rows.length; i++)
6899                     {
6900                         for(var j=0; j<scope.rows[i].length; j++)
6901                         {
6902                             if(!scope.rows[i][j].disabled && !firstSelected)
6903                             {
6904                                 firstSelected=true;
6905                                 var firstDay = scope.rows[i][j];
6906                             }
6907
6908                             if(scope.rows[i][j].selected)
6909                             {
6910                                 flag=true;
6911                                 break;
6912                             }                  
6913                         }
6914                         if(flag)
6915                         {
6916                             break;
6917                         }
6918                     }
6919                     if(!flag && firstSelected)
6920                     {
6921                        firstDay.firstFocus=true;
6922                     }
6923
6924                     scope.labels = data.labels || [];
6925                     scope.title = data.title;                    
6926                 }
6927             }
6928
6929             scope.select = function (date,$event) {
6930                 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
6931                 scope.currentDate = dt;
6932                 if (!scope.onSelectClose || (scope.onSelectClose && scope.onSelectClose({
6933                         date: dt
6934                     }) !== false)) {
6935                     if (angular.isNumber(scope.collapseWait)) {
6936                         $timeout(function () {
6937                             scope.isOpen = false;
6938                             toggleCalendar(scope.isOpen);
6939                         }, scope.collapseWait);
6940                     } else {
6941                         scope.isOpen = false;
6942                         toggleCalendar(scope.isOpen);
6943                     }
6944                 }
6945             };
6946
6947             scope.move = function (direction,$event) {
6948                 var step = MonthpickerCtrl.modes[mode].step;
6949                 selected.setDate(1);
6950                 selected.setMonth(selected.getMonth() + direction * (step.months || 0));
6951                 selected.setFullYear(selected.getFullYear() + direction * (step.years || 0));
6952                 refill();
6953                 scope.getFocus = true;
6954                 $timeout(function () {
6955                     if (attrs.inline === 'true') {
6956                         MonthpickerCtrl.focusNextPrev(element,false); 
6957                     }else{
6958                         MonthpickerCtrl.focusNextPrev(b2bMonthpickerPopupTemplate,false);
6959                     }
6960                 },100);
6961                 $event.preventDefault();
6962                 $event.stopPropagation();
6963             };
6964
6965             scope.$watch('currentDate', function (value) {
6966                 if (angular.isDefined(value) && value !== null) {
6967                     refill(value);
6968                 } else {
6969                     refill();
6970                 }
6971                 ngModel.$setViewValue(value);
6972             });
6973
6974             ngModel.$render = function () {
6975                 scope.currentDate = ngModel.$viewValue;
6976             };
6977
6978             var stringToDate = function (value) {
6979                 if (!isNaN(new Date(value))) {
6980                     value = new Date(value);
6981                 }
6982                 return value;
6983             };
6984             ngModel.$formatters.unshift(stringToDate);
6985         }
6986     };
6987 }])
6988
6989 .directive('b2bMonthpicker', ['$compile', '$log', 'b2bMonthpickerConfig', 'b2bMonthpickerService', function ($compile, $log, b2bMonthpickerConfig, b2bMonthpickerService) {
6990     return {
6991         restrict: 'A',
6992         scope: {
6993             disableDates: '&',
6994             onSelectClose: '&'
6995         },
6996         require: 'ngModel',
6997         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
6998             var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : b2bMonthpickerConfig.dateFormat;
6999             var helperText = angular.isDefined(attr.helperText) ? scope.$parent.$eval(attr.helperText) : b2bMonthpickerConfig.helperText; 
7000             helperText = helperText.replace('$date', '{{dt | date : \'' + dateFormatString + '\'}}');
7001
7002             var descriptionText = angular.isDefined(attr.descriptionText) ? scope.$parent.$eval(attr.descriptionText) : b2bMonthpickerConfig.descriptionText;  
7003
7004
7005             var inline = false;
7006             if (elem.prop('nodeName') !== 'INPUT' && elem.prop('nodeName') !== 'A') {
7007                 inline = true;
7008             }
7009
7010             var selectedDateMessage = "";
7011             
7012             if (elem.prop('nodeName') !== 'A'){
7013                 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>';    
7014                 elem.attr('tabindex', '-1'); 
7015                 elem.attr('aria-hidden', 'true');  
7016                 elem.attr('readonly', 'true'); 
7017             }else{
7018                 selectedDateMessage = ''
7019                 elem.attr('aria-label', helperText);
7020             }
7021             
7022             var descriptionTextSpan = '<span class="offscreen-text" id="monthpicker-description'+scope.$id+'">'+descriptionText+'</span>';
7023             elem.removeAttr('b2b-Monthpicker');
7024             elem.removeAttr('ng-model');
7025             elem.removeAttr('ng-disabled');
7026             elem.addClass('Monthpicker-input');
7027             elem.attr('ng-model', 'dt');
7028             elem.attr('aria-describedby', 'monthpicker-description'+scope.$id);
7029             
7030             
7031             
7032             elem.attr('ng-disabled', 'ngDisabled');
7033             elem.attr('b2b-format-date', dateFormatString);
7034
7035             var wrapperElement = angular.element('<div></div>');
7036             wrapperElement.attr('b2b-Monthpicker-popup', '');
7037             wrapperElement.attr('ng-model', 'dt');
7038             if (inline) {
7039                 wrapperElement.attr('inline', inline);
7040             }
7041             if (elem.prop('nodeName') === 'A'){
7042                 wrapperElement.attr('link', true);
7043             }
7044             b2bMonthpickerService.setAttributes(attr, wrapperElement);
7045             b2bMonthpickerService.bindScope(attr, scope);
7046
7047             wrapperElement.html('');
7048             wrapperElement.append(selectedDateMessage);
7049             wrapperElement.append('');
7050             wrapperElement.append(descriptionTextSpan);
7051             wrapperElement.append('');
7052             wrapperElement.append(elem.prop('outerHTML'));
7053
7054             var elm = wrapperElement.prop('outerHTML');
7055             elm = $compile(elm)(scope);
7056             elem.replaceWith(elm);
7057         }],
7058         link: function (scope, elem, attr, ctrl) {
7059             if (!ctrl) {
7060                 $log.error("ng-model is required.");
7061                 return; // do nothing if no ng-model
7062             }
7063             
7064             scope.$watch('dt', function (value) {
7065                 ctrl.$setViewValue(value);
7066             });
7067             ctrl.$render = function () {
7068                 scope.dt = ctrl.$viewValue;
7069             };
7070         }
7071     };
7072 }])
7073
7074 .directive('b2bMonthpickerGroup', [function () {
7075     return {
7076         restrict: 'EA',
7077         controller: ['$scope', '$element', '$attrs', function (scope, elem, attr) {
7078             this.$$headers = [];
7079             this.$$footers = [];
7080             this.registerMonthpickerScope = function (MonthpickerScope) {
7081                 MonthpickerScope.headers = this.$$headers;
7082                 MonthpickerScope.footers = this.$$footers;
7083             };
7084         }],
7085         link: function (scope, elem, attr, ctrl) {}
7086     };
7087 }])
7088
7089 .directive('b2bFormatDate', ['dateFilter', function (dateFilter) {
7090     return {
7091         restrict: 'A',
7092         require: 'ngModel',
7093         link: function (scope, elem, attr, ctrl) {
7094             var b2bFormatDate = "";
7095             attr.$observe('b2bFormatDate', function (value) {
7096                 b2bFormatDate = value;
7097             });
7098             var dateToString = function (value) {
7099                 if (!isNaN(new Date(value))) {
7100                     return dateFilter(new Date(value), b2bFormatDate);
7101                 }
7102                 return value;
7103             };
7104             ctrl.$formatters.unshift(dateToString);
7105         }
7106     };
7107 }])
7108
7109 .directive('b2bMonthpickerHeader', [function () {
7110     return {
7111         restrict: 'EA',
7112         require: '^b2bMonthpickerGroup',
7113         transclude: true,
7114         replace: true,
7115         template: '',
7116         compile: function (elem, attr, transclude) {
7117             return function link(scope, elem, attr, ctrl) {
7118                 if (ctrl) {
7119                     ctrl.$$headers.push(transclude(scope, function () {}));
7120                 }
7121                 elem.remove();
7122             };
7123         }
7124     };
7125 }])
7126
7127 .directive('b2bMonthpickerFooter', [function () {
7128     return {
7129         restrict: 'EA',
7130         require: '^b2bMonthpickerGroup',
7131         transclude: true,
7132         replace: true,
7133         template: '',
7134         compile: function (elem, attr, transclude) {
7135             return function link(scope, elem, attr, ctrl) {
7136                 if (ctrl) {
7137                     ctrl.$$footers.push(transclude(scope, function () {}));
7138                 }
7139                 elem.remove();
7140             };
7141         }
7142     };
7143 }]);
7144 /**
7145  * @ngdoc directive
7146  * @name Navigation.att:multiLevelNavigation
7147  *
7148  * @description
7149  *  <file src="src/multiLevelNavigation/docs/readme.md" />
7150  *
7151  * @usage
7152  *       <div class="b2b-ml-nav">
7153  *          <ul role="tree">
7154  *             <li aria-label="{{child.name}}" tabindex="-1" b2b-ml-nav="{{child.type}}" role="treeitem" ng-repeat="child in treeStructure">
7155  *                  <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>
7156  *                      <!-- Below UL tag is RECURSIVE to generate n-childs -->
7157  *                      <ul role="group" ng-if="child.child">
7158  *                          <li aria-label="{{child.name}}" b2b-ml-nav="{{child.type}}" tabindex="-1" role="treeitem" ng-repeat="child in child.child">
7159  *                          <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>
7160  *                               <!-- RECURSIVE UL tag goes here -->
7161  *                          </li>
7162  *                      </ul>
7163  *             </li>
7164  *           </ul>
7165  *        </div>
7166  *
7167  * @example
7168  *  <section id="code">
7169         <example module="b2b.att">
7170             <file src="src/multiLevelNavigation/docs/demo.html" />
7171             <file src="src/multiLevelNavigation/docs/demo.js" />
7172        </example>
7173     </section>
7174  *
7175  */
7176 angular.module('b2b.att.multiLevelNavigation', ['b2b.att.utilities'])
7177     //directive b2bMlNav Test coverage 100% on 5/13
7178     .directive('b2bMlNav', ['keymap', function (keymap) {
7179         return {
7180             restrict: 'EA',
7181             link: function (scope, element) {
7182                 var rootE, parentE, upE, downE, lastE, homeE, endE;
7183                 //default root tree element tabindex set zero
7184                 if (element.parent().parent().hasClass('b2b-ml-nav') && (element[0].previousElementSibling === null)) {
7185                     element.attr('tabindex', 0);
7186                 }
7187                 //check root via class
7188                 var isRoot = function (elem) {
7189                         if (elem.parent().parent().eq(0).hasClass('b2b-ml-nav')) {
7190                             return true;
7191                         } else {
7192                             return false;
7193                         }
7194
7195                     }
7196                     //for any expandable tree item on click
7197                 var toggleState = function (e) {
7198                                     
7199                     if (angular.element(e.target).attr("b2b-ml-nav") !== "endNode") {
7200                         var eLink = element.find('a').eq(0);
7201                         if (eLink.hasClass('active')) {
7202                             eLink.removeClass('active');
7203                             eLink.parent().attr("aria-expanded", "false");
7204                             eLink.find('i').eq(0).removeClass('icon-primary-expanded');
7205                             eLink.find('i').eq(0).addClass('icon-primary-collapsed');
7206                         } else {
7207                             eLink.addClass('active');
7208                             eLink.parent().attr("aria-expanded", "true");
7209                             eLink.find('i').eq(0).removeClass('icon-primary-collapsed');
7210                             eLink.find('i').eq(0).addClass('icon-primary-expanded');
7211                         }
7212                     }
7213                 };
7214                 //function finds the main root-item from particular tree-group
7215                 var findRoot = function (elem) {
7216                     if (isRoot(elem)) {
7217                         rootE = elem;
7218                         return;
7219                     }
7220                     if (elem.attr("b2b-ml-nav") === "middleNode" || elem.attr("b2b-ml-nav") === "endNode") {
7221                         parentE = elem.parent().parent();
7222                     } else {
7223                         parentE = elem;
7224                     }
7225                     if (parentE.attr("b2b-ml-nav") === "rootNode") {
7226                         rootE = parentE;
7227                     } else {
7228                         findRoot(parentE);
7229                     }
7230                 };
7231                 //finds the last visible node of the previous tree-group
7232                 var findPreActive = function (elem) {
7233                     if (!(elem.hasClass("active"))) {
7234                         return;
7235                     } else {
7236                         var childElems = angular.element(elem[0].nextElementSibling.children);
7237                         lastE = angular.element(childElems[childElems.length - 1]);
7238                         if (lastE.attr("b2b-ml-nav") === "middleNode" && lastE.find('a').eq(0).hasClass('active')) {
7239                             findPreActive(lastE.find('a').eq(0));
7240                         }
7241                         upE = lastE;
7242                     }
7243                 };
7244                 //find above visible link
7245                 var findUp = function (elem) {
7246                     if (elem[0].previousElementSibling !== null) {
7247                         upE = angular.element(elem[0].previousElementSibling);
7248                     } else {
7249                         upE = elem.parent().parent();
7250                     }
7251                     if (isRoot(elem) || (upE.attr('b2b-ml-nav') === "middleNode" && upE[0] !== elem.parent().parent()[0])) {
7252                         findPreActive(upE.find('a').eq(0)); 
7253                     }
7254                 };
7255                 //find below visible link
7256                 var findDown = function (elem) {
7257                     if (elem.hasClass('active')) {
7258                         downE = elem.next().find('li').eq(0);
7259                     } else {
7260                         if (elem.parent().next().length !== 0) {
7261                             downE = elem.parent().next().eq(0);
7262                         } else {
7263                             if (elem.parent().parent().parent().next().length !== 0) {
7264                                 downE = elem.parent().parent().parent().next().eq(0);
7265                                 return;
7266                             }
7267                             downE = elem.parent().eq(0);
7268                         }
7269                     }
7270                 };
7271                 //finds last root-group element of the tree
7272                 var findEnd = function (elem) {
7273                     findRoot(elem);
7274                     endE = angular.element(rootE.parent()[0].children[rootE.parent()[0].children.length - 1]);
7275                 };
7276                 //finds first root element of tree
7277                 var findHome = function (elem) {
7278                     findRoot(elem);
7279                     homeE = angular.element(rootE.parent()[0].children[0]);
7280                 };
7281                 element.bind('click', function (e) {
7282                     if(element.attr("b2b-ml-nav") !== "endNode") { 
7283                         toggleState(e); 
7284                     }
7285                     if (rootE==undefined){
7286                         findRoot(element);
7287                     }
7288                     var currSelected = rootE.parent()[0].querySelector('.selected');
7289                     if(currSelected){
7290                         angular.element(currSelected).removeClass('selected');
7291                     }                    
7292                     element.find('a').eq(0).addClass('selected');
7293                     e.stopPropagation();
7294                 });
7295                 element.bind('focus', function (e) {
7296                     if(element.attr("b2b-ml-nav") !== "endNode") {
7297                         if(element.find('a').eq(0).hasClass('active')) {
7298                             element.attr("aria-expanded", true);
7299                         }
7300                         else {
7301                             element.attr("aria-expanded", false);
7302                         }
7303                         
7304                     }
7305                 })
7306                 //Keyboard functionality approach:
7307                 //find keycode
7308                 //set set tabindex -1 on the current focus element
7309                 //find the next element to be focussed, set tabindex 0 and throw focus
7310                 element.bind('keydown', function (evt) {
7311                     switch (evt.keyCode) {
7312                     case keymap.KEY.ENTER:
7313                     case keymap.KEY.SPACE:
7314                         element.triggerHandler('click');
7315                         evt.stopPropagation();
7316                         evt.preventDefault();
7317                         break;
7318                     case keymap.KEY.END:
7319                         evt.preventDefault();
7320                         element.attr('tabindex', -1);
7321                         findEnd(element);
7322                         endE.eq(0).attr('tabindex', 0);
7323                         endE[0].focus();
7324                         evt.stopPropagation();
7325                         break;
7326                     case keymap.KEY.HOME:
7327                         evt.preventDefault();
7328                         element.attr('tabindex', -1);
7329                         findHome(element);
7330                         homeE.eq(0).attr('tabindex', 0);
7331                         homeE[0].focus();
7332                         evt.stopPropagation();
7333                         break;
7334                     case keymap.KEY.LEFT:
7335                         evt.preventDefault();
7336                         if (!isRoot(element)) {
7337                             element.attr('tabindex', -1);
7338                             parentE = element.parent().parent();
7339                             parentE.eq(0).attr('tabindex', 0);
7340                             parentE[0].focus();
7341                             parentE.eq(0).triggerHandler('click');
7342                         } else {
7343                             if (element.find('a').eq(0).hasClass('active')) {
7344                                 element.triggerHandler('click');
7345                             }
7346                         }
7347                         evt.stopPropagation();
7348                         break;
7349                     case keymap.KEY.UP:
7350                         evt.preventDefault();
7351                         if (!(isRoot(element) && element[0].previousElementSibling === null)) {
7352                             element.attr('tabindex', -1);
7353                             findUp(element);
7354                             upE.eq(0).attr('tabindex', 0);
7355                             upE[0].focus();
7356                         }
7357                         evt.stopPropagation();
7358                         break;
7359                     case keymap.KEY.RIGHT:
7360                         evt.preventDefault();
7361                         if (element.attr("b2b-ml-nav") !== "endNode") {
7362                             if (!element.find('a').eq(0).hasClass('active')) {
7363                                 element.triggerHandler('click');
7364                             }
7365                             element.attr('tabindex', -1);
7366                             findDown(element.find('a').eq(0));
7367                             downE.eq(0).attr('tabindex', 0);
7368                             downE[0].focus();
7369                         }
7370                         evt.stopPropagation();
7371                         break;
7372                     case keymap.KEY.DOWN:
7373                         evt.preventDefault();
7374                         element.attr('tabindex', -1);
7375                         if (!(element.attr("b2b-ml-nav") === "middleNode" && element.find('a').eq(0).hasClass('active')) && (element.next().length === 0)) {
7376                             if(element.parent().parent().attr("b2b-ml-nav") !== "rootNode" && element.parent().parent()[0].nextElementSibling !== null)
7377                             {
7378                                 findDown(element.find('a').eq(0));
7379                                 downE.eq(0).attr('tabindex', 0);
7380                                 downE[0].focus();
7381                                 evt.stopPropagation();
7382                                 break;
7383                             }
7384                             findRoot(element);
7385                             if (!(rootE.next().length === 0)) {
7386                                 rootE.next().eq(0).attr('tabindex', 0);
7387                                 rootE.next()[0].focus();
7388                             } else {
7389                                 rootE.eq(0).attr('tabindex', 0);
7390                                 rootE[0].focus();
7391                             }
7392                             evt.stopPropagation();
7393                             break;
7394                         }
7395                         findDown(element.find('a').eq(0));
7396                         downE.eq(0).attr('tabindex', 0);
7397                         downE[0].focus();
7398                         evt.stopPropagation();
7399                         break;
7400                     default:
7401                         break;
7402                     }
7403                 });
7404             }
7405         };
7406     }]);
7407 /**
7408  * @ngdoc directive
7409  * @name Tabs, tables & accordions.att:multipurposeExpander
7410  *
7411  * @description
7412  *  <file src="src/multipurposeExpander/docs/readme.md" />
7413  *
7414  * @usage
7415  * <!--With Close Other -->
7416  * <b2b-expander-group close-others="true">
7417  *  <b2b-expanders class="mpc-expanders" is-open="testmpc">            
7418  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc, 'b2b-toggle-header-inactive': testmpc } ">Heading content goes here</b2b-expander-heading>               
7419  *      <b2b-expander-body>
7420             <p>body content goes here</p>
7421         </b2b-expander-body>
7422  *  </b2b-expanders>
7423  *  </b2b-expander-group>
7424  *  
7425  * <!-- Without Close Other -->
7426  *  <b2b-expanders class="mpc-expanders" is-open="testmpc2">            
7427  *      <b2b-expander-heading ng-class=" { 'b2b-toggle-header-active': !testmpc2, 'b2b-toggle-header-inactive': testmpc2 } ">Heading content goes here</b2b-expander-heading>               
7428  *      <b2b-expander-body>
7429             <p>body content goes here</p>
7430         </b2b-expander-body>
7431  *  </b2b-expanders>
7432  *  
7433  * @example
7434  *  <section id="code">
7435         <example module="b2b.att.multipurposeExpander">
7436             <file src="src/multipurposeExpander/docs/demo.html" />
7437             <file src="src/multipurposeExpander/docs/demo.js" />
7438         </example>
7439     </section>
7440  *
7441  */
7442
7443 angular.module('b2b.att.multipurposeExpander', ['b2b.att', 'b2b.att.collapse'])
7444 .directive('b2bExpanderGroup', function () {
7445     return {
7446         restrict: 'EA',
7447         transclude: true,
7448         template: "<ng-transclude></ng-transclude>",
7449         controller:['$scope','$attrs', function($scope,$attrs){
7450             this.groups = [];
7451             this.index = -1;            
7452             this.scope = $scope;
7453             
7454             this.addGroup = function (groupScope) {
7455                 var that = this;
7456                 groupScope.index = this.groups.length;
7457                 this.groups.push(groupScope);
7458                 if(this.groups.length > 0){
7459                     this.index = 0;
7460                 }
7461                 groupScope.$on('$destroy', function () {
7462                 that.removeGroup(groupScope);
7463             });
7464             };
7465
7466             this.closeOthers = function (openGroup) {
7467                 var closeOthers = angular.isDefined($attrs.closeOthers);
7468                 if (closeOthers && !$scope.forceExpand) {
7469                     angular.forEach(this.groups, function (group) {
7470                         if (group !== openGroup) {
7471                             group.isOpen = false;
7472                         }
7473                     });
7474                 }
7475                 if (this.groups.indexOf(openGroup) === (this.groups.length - 1) && $scope.forceExpand) {
7476                     $scope.forceExpand = false;
7477                 }
7478             };
7479             this.removeGroup = function (group) {
7480             var index = this.groups.indexOf(group);
7481             if (index !== -1) {
7482                 this.groups.splice(this.groups.indexOf(group), 1);
7483             }
7484         };
7485         }]
7486        
7487     };
7488     
7489 })
7490 .directive('b2bExpanders', function () {
7491     return{
7492         restrict: 'EA',
7493         replace: true,
7494         require:['b2bExpanders','?^b2bExpanderGroup'],
7495         transclude: true,
7496         scope:{isOpen:'=?'},
7497         template: "<div ng-transclude></div>",
7498         controller: ['$scope', function ($scope){
7499                 var bodyScope = null;
7500                 var expanderScope = null;
7501                 this.isOpened = function(){                
7502                     if($scope.isOpen)
7503                     {
7504                         return  true;
7505                     }else
7506                     {
7507                         return false;
7508                     }
7509                 };                
7510                 this.setScope = function (scope) {
7511                     bodyScope = scope; 
7512                     bodyScope.isOpen = $scope.isOpen;                   
7513                 };                
7514                 this.setExpanderScope = function (scope) {
7515                     expanderScope = scope;                                   
7516                 };
7517                 this.toggle = function () {
7518                     $scope.isOpen = bodyScope.isOpen = !bodyScope.isOpen;                    
7519                     return bodyScope.isOpen;
7520                     
7521                 };
7522                 this.watchToggle = function(io){ 
7523                     bodyScope.isOpen = io;
7524                     expanderScope.updateIcons(io);
7525                 };  
7526             }],
7527         link: function (scope, elem, attr, myCtrl)
7528         {
7529             //scope.isOpen = false; 
7530             if(myCtrl[1]){
7531                 myCtrl[1].addGroup(scope);
7532             }
7533             scope.$watch('isOpen', function(val){                               
7534                 myCtrl[0].watchToggle(scope.isOpen);
7535                 if(val && myCtrl[1]){
7536                     myCtrl[1].closeOthers(scope);
7537                 }
7538             });            
7539         }
7540     };
7541 })
7542
7543 .directive('b2bExpanderHeading', function () {
7544     return{
7545         require: "^b2bExpanders",
7546         restrict: 'EA',
7547         replace: true,
7548         transclude: true,
7549         scope: true,
7550         template: "<div style='padding:10px 10px 10px 0 !important' ng-transclude></div>"
7551     };
7552 })
7553
7554 .directive('b2bExpanderBody', function () {
7555     return{
7556         restrict: 'EA',
7557         require: "^b2bExpanders",
7558         replace: true,
7559         transclude: true,
7560         scope: {},
7561         template: "<div b2b-collapse='!isOpen' ><div ng-transclude></div></div>",
7562         link: function (scope, elem, attr, myCtrl) {
7563             scope.isOpen = false;
7564             myCtrl.setScope(scope);
7565         }
7566     };
7567 })
7568
7569 .directive('b2bExpanderToggle', function () {
7570     return{
7571         restrict: 'EA',
7572         require: "^b2bExpanders",
7573         scope: {
7574             expandIcon: '@',
7575             collapseIcon: '@'
7576         },
7577         
7578         link: function (scope, element, attr, myCtrl)
7579         {
7580             myCtrl.setExpanderScope(scope);
7581             var isOpen = myCtrl.isOpened();   
7582
7583             scope.setIcon = function () {
7584                 element.attr("role", "button");
7585
7586                 if (scope.expandIcon && scope.collapseIcon)
7587                 {
7588                     if (isOpen) {
7589                         element.removeClass(scope.expandIcon);
7590                         element.addClass(scope.collapseIcon);
7591
7592                         element.attr("aria-expanded", "true");
7593                     }
7594                     else {
7595                         element.removeClass(scope.collapseIcon);
7596                         element.addClass(scope.expandIcon);
7597
7598                         element.attr("aria-expanded", "false");
7599                     }
7600                 }                                                               
7601             };
7602             
7603             element.bind('click', function (){
7604                 scope.toggleit();
7605             });
7606             scope.updateIcons = function(nStat){
7607                 isOpen = nStat;
7608                 scope.setIcon();                
7609             };
7610             scope.toggleit = function (){
7611                 isOpen = myCtrl.toggle();
7612                 scope.setIcon();
7613                 scope.$apply();
7614             };                    
7615             scope.setIcon();
7616         }
7617     };
7618 });
7619 /**
7620  * @ngdoc directive
7621  * @name Messages, modals & alerts.att:notesMessagesAndErrors
7622  *
7623  * @description
7624  *  <file src="src/notesMessagesAndErrors/docs/readme.md" />
7625  *
7626  * @usage
7627  *  See Demo
7628  *
7629  * @example
7630  *  <section id="code">
7631         <example module="b2b.att">
7632             <file src="src/notesMessagesAndErrors/docs/demo.html" />
7633             <file src="src/notesMessagesAndErrors/docs/demo.js" />
7634        </example>
7635         </section>
7636  *
7637  */
7638 angular.module('b2b.att.notesMessagesAndErrors', []);
7639 /** 
7640  * @ngdoc directive 
7641  * @name Template.att:Notification Card
7642  * 
7643  * @description 
7644  *  <file src="src/notificationCardTemplate/docs/readme.md" /> 
7645  * 
7646  * @example 
7647  *  <section id="code"> 
7648         <b>HTML + AngularJS</b> 
7649         <example module="b2b.att"> 
7650             <file src="src/notificationCardTemplate/docs/demo.html" /> 
7651             <file src="src/notificationCardTemplate/docs/demo.js" /> 
7652        </example> 
7653     </section>    
7654  * 
7655  */
7656 angular.module('b2b.att.notificationCardTemplate', [])
7657   
7658 /** 
7659  * @ngdoc directive 
7660  * @name Template.att:Order Confirmation Template
7661  * 
7662  * @description 
7663  *  <file src="src/orderConfirmationTemplate/docs/readme.md" /> 
7664  * 
7665  * @example 
7666  *  <section id="code"> 
7667         <b>HTML + AngularJS</b> 
7668         <example module="b2b.att"> 
7669             <file src="src/orderConfirmationTemplate/docs/demo.html" /> 
7670             <file src="src/orderConfirmationTemplate/docs/demo.js" /> 
7671        </example> 
7672     </section>    
7673  * 
7674  */
7675 angular.module('b2b.att.orderConfirmationTemplate', []);
7676   
7677 /**
7678  * @ngdoc directive
7679  * @name Navigation.att:pagination
7680  *
7681  * @description
7682  *  <file src="src/pagination/docs/readme.md" />
7683  * @param {int} total-pages - Total # of pages, set in your controller $scope
7684  * @param {int} current-page - Current selected page, set in your controller $scope
7685  * @param {function} click-handler - Handler function on click of page number, defined in your controller $scope
7686  * @param {string} input-id - _UNIQUE ID_ __MUST__ be provided for 508 compliance, set in your HTML as static text
7687  * @param {string} input-class - optional class that can be given to use for the go to page container
7688  *
7689  * @usage
7690  *   <div b2b-pagination="" input-id="goto-page-2" total-pages="totalPages1" current-page="currentPage1" click-handler="customHandler"></div> 
7691  *
7692  * @example
7693  *  <section id="code">
7694         <example module="b2b.att">
7695             <file src="src/pagination/docs/demo.html" />
7696             <file src="src/pagination/docs/demo.js" />
7697        </example>
7698         </section>
7699  *
7700  */
7701 angular.module('b2b.att.pagination', ['b2b.att.utilities', 'ngTouch'])
7702     .directive('b2bPagination', ['b2bUserAgent', 'keymap', '$window', '$timeout', function (b2bUserAgent, keymap, $window, $timeout) {
7703         return {
7704             restrict: 'A',
7705             scope: {
7706                 totalPages: '=',
7707                 currentPage: '=',
7708                 clickHandler: '=?',
7709                 inputId: '=',
7710                 isDroppable: '=?'
7711             },
7712             replace: true,
7713             templateUrl: 'b2bTemplate/pagination/b2b-pagination.html',
7714             link: function (scope, elem, attr) {
7715                 scope.isMobile = b2bUserAgent.isMobile();
7716                 scope.notMobile = b2bUserAgent.notMobile();
7717                 scope.focusedPage;
7718                 scope.meanVal = 3;
7719                 scope.inputClass = attr.inputClass;
7720                 scope.droppableAttribute = scope.isDroppable ? true : false;
7721                 scope.$watch('totalPages', function (value) {
7722                     if (angular.isDefined(value) && value !== null) {
7723                         scope.pages = [];
7724                         if (value < 1) {
7725                             scope.totalPages = 1;
7726                             return;
7727                         }
7728                         if (value <= 10) {
7729                             for (var i = 1; i <= value; i++) {
7730                                 scope.pages.push(i);
7731                             }
7732                         } else if (value > 10) {
7733                             var midVal = Math.ceil(value / 2);
7734                             scope.pages = [midVal - 2, midVal - 1, midVal, midVal + 1, midVal + 2];
7735                         }
7736                         if(scope.currentPage === undefined || scope.currentPage === 1)
7737                         {
7738                             currentPageChanged(1);
7739                         }
7740                     }
7741                 });
7742                 scope.$watch('currentPage', function (value) {
7743                     currentPageChanged(value);
7744                     callbackHandler(value);
7745                 });
7746                 var callbackHandler = function (num) {
7747                     if (angular.isFunction(scope.clickHandler)) {
7748                         scope.clickHandler(num);
7749                     }
7750                 };
7751                 var getBoundary = function(value){
7752                     if ( value < 100 ) {
7753                         return 5;
7754                     } else if ( 100 <= value && value < 1000 ) {
7755                         return 4;
7756                     } else if ( 1000 <= value ) {
7757                         return 3;
7758                     } else {
7759                         return 5; // error
7760                     }
7761                 };
7762                 function currentPageChanged(value) {
7763                     if (angular.isDefined(value) && value !== null) {
7764                         if (!value || value < 1) {
7765                             value = 1;
7766                         }
7767                         if (value > scope.totalPages) {
7768                             value = scope.totalPages;
7769                         }
7770                         if (scope.currentPage !== value) {
7771                             scope.currentPage = value;
7772                             callbackHandler(scope.currentPage);
7773                         }
7774                         if (scope.totalPages > 10) {
7775                             var val = parseInt(value);
7776                             scope.boundary = getBoundary(val);
7777                             if (val <= 6) { // Left (first) section
7778                                 scope.pages = [1, 2, 3, 4, 5, 6, 7];
7779                             } else if ( val <= (scope.totalPages - scope.boundary) ) { // Middle section
7780                                 if ( 7 <= val && val < 9 ) {
7781                                     if(scope.totalPages < 100) {
7782                                         scope.pages = [val - 3, val - 2, val - 1, val, val + 1, val + 2];
7783                                     } else if(scope.totalPages < 1000) {
7784                                         scope.pages = [val - 2, val - 1, val, val + 1, val + 2];
7785                                     } else if(scope.totalPages < 1000) {
7786                                         scope.pages = [val - 2, val - 1, val, val + 1, val + 2];
7787                                     }
7788                                 } else if ( 9 <= val && val < 100 ) {
7789                                     scope.pages = [val - 3, val - 2, val - 1, val, val + 1, val + 2];
7790                                 } else if ( 100 <= val && val < 1000 ) {
7791                                     scope.pages = [val - 2, val - 1, val, val + 1];
7792                                 } else if ( 1000 <= val ) {
7793                                     scope.pages = [val - 1, val, val + 1];
7794                                 }
7795                             } else if ( (scope.totalPages - scope.boundary) < val ) { // Right (last) section
7796                                 if ( val < 100 ) {
7797                                     scope.pages = [scope.totalPages - 5, scope.totalPages - 4, scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
7798                                 } else if ( 100 <= val && val < 1000 ) {
7799                                     scope.pages = [scope.totalPages - 4, scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
7800                                 } else if ( 1000 <= val ) {
7801                                     scope.pages = [scope.totalPages - 3, scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
7802                                 }
7803                             }
7804                         }
7805                         if (scope.isMobile) {
7806                             var inWidth = $window.innerWidth;
7807                             var viewLimit = 7;
7808                             if (inWidth <= 400) {
7809                                 viewLimit = 7;
7810                             } else if (inWidth > 400 && inWidth < 500) {
7811                                 viewLimit = 9;
7812                             } else if (inWidth >= 500 && inWidth < 600) {
7813                                 viewLimit = 11;
7814                             } else if (inWidth >= 600 && inWidth < 700) {
7815                                 viewLimit = 13;
7816                             } else if (inWidth >= 700 && inWidth < 800) {
7817                                 viewLimit = 15;
7818                             }
7819
7820                             var val = parseInt(value);
7821
7822                             scope.meanVal = Math.floor(viewLimit / 2);
7823                             var lowerLimit = (val - scope.meanVal) < 1 ? 1 : val - scope.meanVal;
7824                             var upperLimit = (lowerLimit + viewLimit - 1) > scope.totalPages ? scope.totalPages : lowerLimit + viewLimit - 1;
7825                             scope.pages = [];
7826                             for (var i = lowerLimit; i <= upperLimit; i++) {
7827                                 scope.pages.push(i);
7828                             }
7829                         }
7830                     }
7831                 }
7832                 scope.gotoKeyClick = function (keyEvent) {
7833                   if (keyEvent.which === keymap.KEY.ENTER) {
7834                     scope.gotoBtnClick()
7835                   }
7836                 }
7837                 scope.gotoBtnClick = function () {
7838                     currentPageChanged(parseInt(scope.gotoPage)); 
7839                     callbackHandler(scope.currentPage);
7840                     var qResult = elem[0].querySelector('button');
7841                     angular.element(qResult).attr('disabled','true');
7842                     $timeout(function(){
7843                         elem[0].querySelector('.b2b-pager__item--active').focus();
7844                     }, 50); 
7845                     scope.gotoPage = null;               
7846                 }
7847                 scope.onfocusIn = function(evt)
7848                 {
7849                     var qResult = elem[0].querySelector('button');
7850                     angular.element(qResult).removeAttr('disabled');
7851                 }
7852                 scope.onfocusOut = function(evt)
7853                 {
7854                     if(evt.target.value === "")
7855                     {
7856                         var qResult = elem[0].querySelector('button');
7857                         angular.element(qResult).attr('disabled','true');
7858                     }                    
7859                 }
7860                 scope.next = function (event) {
7861                     if (event != undefined) {
7862                         event.preventDefault();
7863                     }
7864                     if (scope.currentPage < scope.totalPages) {
7865                         scope.currentPage += 1;
7866                         callbackHandler(scope.currentPage);
7867                     }
7868                 };
7869                 scope.prev = function (event) {
7870                     if (event != undefined) {
7871                         event.preventDefault();
7872                     }
7873                     if (scope.currentPage > 1) {
7874                         scope.currentPage -= 1;
7875                         callbackHandler(scope.currentPage);
7876                     }
7877                 };
7878                 scope.selectPage = function (value, event) {
7879                     event.preventDefault();
7880                     scope.currentPage = value;
7881                     scope.focusedPage = value;
7882                     callbackHandler(scope.currentPage);
7883                 };
7884                 scope.checkSelectedPage = function (value) {
7885                     if (scope.currentPage === value) {
7886                         return true;
7887                     }
7888                     return false;
7889                 };
7890                 scope.isFocused = function (page) {
7891                     return scope.focusedPage === page;
7892                 };
7893             }
7894         };
7895     }]);
7896
7897 /**
7898  * @ngdoc directive
7899  * @name Navigation.att:paneSelector
7900  *
7901  * @description
7902  *  <file src="src/paneSelector/docs/readme.md" />
7903  *
7904  * @usage
7905  *  Please refer demo.html tab in Example section below.
7906  *
7907  * @example
7908     <section id="code">
7909         <b>HTML + AngularJS</b>
7910         <example module="b2b.att">
7911             <file src="src/paneSelector/docs/demo.html" />
7912             <file src="src/paneSelector/docs/demo.js" />
7913         </example>
7914     </section>
7915  */
7916
7917 angular.module('b2b.att.paneSelector', ['b2b.att.tabs', 'b2b.att.utilities'])
7918
7919 .filter('paneSelectorSelectedItemsFilter', [function () {
7920     return function (listOfItemsArray) {
7921
7922         if (!listOfItemsArray) {
7923             listOfItemsArray = [];
7924         }
7925
7926         var returnArray = [];
7927
7928         for (var i = 0; i < listOfItemsArray.length; i++) {
7929             if (listOfItemsArray[i].isSelected) {
7930                 returnArray.push(listOfItemsArray[i]);
7931             }
7932         }
7933
7934         return returnArray;
7935     };
7936 }])
7937
7938 .filter('paneSelectorFetchChildItemsFilter', [function () {
7939     return function (listOfItemsArray) {
7940
7941         if (!listOfItemsArray) {
7942             listOfItemsArray = [];
7943         }
7944
7945         var returnArray = [];
7946
7947         for (var i = 0; i < listOfItemsArray.length; i++) {
7948             for (var j = 0; j < listOfItemsArray[i].childItems.length; j++) {
7949                 returnArray.push(listOfItemsArray[i].childItems[j]);
7950             }
7951         }
7952
7953         return returnArray;
7954     };
7955 }])
7956
7957 .directive('b2bPaneSelector', [function () {
7958     return {
7959         restrict: 'AE',
7960         replace: true,
7961         templateUrl: 'b2bTemplate/paneSelector/paneSelector.html',
7962         transclude: true,
7963         scope: {}
7964     };
7965 }])
7966
7967 .directive('b2bPaneSelectorPane', [ function () {
7968     return {
7969         restrict: 'AE',
7970         replace: true,
7971         templateUrl: 'b2bTemplate/paneSelector/paneSelectorPane.html',
7972         transclude: true,
7973         scope: {}
7974     };
7975 }])
7976
7977 .directive('b2bTabVertical', ['$timeout', 'keymap', function ($timeout, keymap) {
7978     return {
7979         restrict: 'A',
7980         require: '^b2bTab',
7981         link: function (scope, element, attr, b2bTabCtrl) {
7982
7983             if (!b2bTabCtrl) {
7984                 return;
7985             }
7986
7987             // retreive the isolateScope
7988             var iScope = angular.element(element).isolateScope();
7989
7990             $timeout(function () {
7991                 angular.element(element[0].querySelector('a')).unbind('keydown');
7992                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {
7993
7994                     if (!(evt.keyCode)) {
7995                         evt.keyCode = evt.which;
7996                     }
7997
7998                     switch (evt.keyCode) {
7999                         case keymap.KEY.DOWN:
8000                             evt.preventDefault();
8001                             iScope.nextKey();
8002                             break;
8003
8004                         case keymap.KEY.UP:
8005                             evt.preventDefault();
8006                             iScope.previousKey();
8007                             break;
8008
8009                         default:;
8010                     }
8011                 });
8012             });
8013         }
8014     };
8015 }]);
8016 /**
8017  * @ngdoc directive
8018  * @name Forms.att:phoneNumberInput
8019  *
8020  * @description
8021  *  <file src="src/phoneNumberInput/docs/readme.md" />
8022  *
8023  * @usage
8024 <form name="userForm1">
8025     <div class="form-row" ng-class="{'error':!userForm1.text.$valid && userForm1.text.$dirty}">
8026         <label>Phone Mask<span style="color:red">*</span>: (npa) nxx-line &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Model Value: {{mask.text}}</label>
8027         <div>
8028             <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 />
8029             <div ng-messages="userForm1.text.$error" class="error-msg" aria-live="polite" aria-atomic="true">
8030                 <span ng-message="required" role="alert">This field is mandatory!</span>
8031                 <span ng-message="invalidPhoneNumber" role="alert">Please enter valid phone number!</span>
8032                 <span ng-message="mask" role="alert">Please enter valid phone number!</span>
8033             </div>
8034         </div>
8035     </div>
8036 </form>
8037  *
8038  * @example
8039  *  <section id="code">
8040         <example module="b2b.att">
8041             <file src="src/phoneNumberInput/docs/demo.html" />
8042             <file src="src/phoneNumberInput/docs/demo.js" />
8043        </example>
8044     </section>
8045  *
8046  */
8047 angular.module('b2b.att.phoneNumberInput', ['ngMessages', 'b2b.att.utilities'])
8048     .constant("CoreFormsUiConfig", {
8049         phoneMask: '(___) ___-____',
8050         phoneMaskDot: '___.___.____',
8051         phoneMaskHyphen: '___-___-____'
8052     })
8053     .directive('b2bPhoneMask', ['$parse', 'CoreFormsUiConfig', 'keymap', 'b2bUserAgent', function ($parse, CoreFormsUiConfig, keymap, b2bUserAgent) {
8054         return {
8055             require: 'ngModel',
8056             scope: {
8057                 ngModel: '='
8058             },
8059             link: function (scope, iElement, iAttrs, ctrl) {
8060                 
8061                 var mask = '';
8062                 var validPhoneNumber = false;
8063                 var currentKey = '';
8064                 if (b2bUserAgent.isMobile()) {
8065                     mask = "__________";
8066                 } else {
8067                     switch (iAttrs.b2bPhoneMask) {
8068                     case "phoneMask":
8069                         mask = CoreFormsUiConfig.phoneMask;
8070                         break;
8071                     case "phoneMaskDot":
8072                         mask = CoreFormsUiConfig.phoneMaskDot;
8073                         break;
8074                     case "phoneMaskHyphen":
8075                         mask = CoreFormsUiConfig.phoneMaskHyphen;
8076                         break;
8077                     default:
8078                         mask = CoreFormsUiConfig.phoneMask;
8079                     }
8080                 }
8081                 iElement.attr("maxlength", mask.length);
8082                 var checkValidity = function (unmaskedValue, rawValue) {
8083                     var valid = false;
8084                     if (angular.isUndefined(rawValue) || rawValue === '') {
8085                         valid = true;
8086                     } else if (unmaskedValue) {
8087                         valid = (unmaskedValue.length === 10);
8088                     }
8089                     ctrl.$setValidity('invalidPhoneNumber', validPhoneNumber);
8090                     ctrl.$setValidity('mask', valid);
8091                     return valid;
8092                 };
8093                 var handleKeyup = function (evt) {
8094
8095                     if (evt && evt.keyCode === keymap.KEY.SHIFT) {
8096                         return;
8097                     }
8098
8099                     var index, formattedNumber;
8100                     if (ctrl.$modelValue) {
8101                         formattedNumber = ctrl.$modelValue;
8102                     } else {
8103                         formattedNumber = iElement.val();
8104                     }
8105                     if (!formattedNumber.length && currentKey === '') {
8106                         return;
8107                     }
8108                     var maskLength, inputNumbers, maskArray, tempArray, maskArrayLength;
8109                     tempArray = [];
8110                     maskArray = mask.split("");
8111                     maskArrayLength = maskArray.length;
8112                     maskLength = formattedNumber.substring(0, mask.length);
8113                     inputNumbers = formattedNumber.replace(/[^0-9]/g, "").split("");
8114                     for (index = 0; index < maskArrayLength; index++) {
8115                         tempArray.push(maskArray[index] === "_" ? inputNumbers.shift() : maskArray[index]);
8116                         if (inputNumbers.length === 0) {
8117                             break;
8118                         }
8119                     }
8120                     formattedNumber = tempArray.join("");
8121                     if (formattedNumber === '(') {
8122                         formattedNumber = '';
8123                     }
8124
8125                     if ( (angular.isDefined(evt) && evt.which) && currentKey !== '') {
8126                         if (maskArray[0] === currentKey && formattedNumber === '') {
8127                             formattedNumber = '(';
8128                         } else if (evt.which === keymap.KEY.SPACE && currentKey === ' ') {
8129                             formattedNumber = formattedNumber + ') ';
8130                         } else if (maskArray[0] === currentKey && formattedNumber === '') {
8131                             formattedNumber = formattedNumber + currentKey;
8132                         } else if (maskArray[formattedNumber.length] === currentKey) {
8133                             formattedNumber = formattedNumber + currentKey;
8134                         }
8135                         currentKey = '';
8136                     }
8137
8138                     ctrl.$setViewValue(formattedNumber);
8139                     ctrl.$render();
8140                     return formattedNumber;
8141                 };
8142
8143
8144                 // since we are only allowing 0-9, why even let the keypress go forward?
8145                 // also added in delete... in case they want to delete :)
8146                 var handlePress = function (e) {
8147                     if (e.which) {
8148                         if ((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105)) {
8149                             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 &&
8150                                 // Allow: Ctrl+V/v
8151                                 (!(e.ctrlKey) && (e.which !== '118' || e.which !== '86')) &&
8152                                 // Allow: Ctrl+C/c
8153                                 (!(e.ctrlKey) && (e.which !== '99' || e.which !== '67')) &&
8154                                 // Allow: Ctrl+X/x
8155                                 (!(e.ctrlKey) && (e.which !== '120' || e.which !== '88')) &&
8156                                 /* 229 key code will sent as placeholder key for andriod devices */
8157                                 (e.which != 229 )) {
8158                                 e.preventDefault ? e.preventDefault() : e.returnValue = false;
8159                                 validPhoneNumber = false;
8160                             }
8161                         } else {
8162                             validPhoneNumber = true;
8163                         }
8164
8165                         setCurrentKey(e);
8166                     }
8167                     scope.$apply();
8168                 };
8169                 // i moved this out because i thought i might need focus as well..
8170                 // to handle setting the model as the view changes
8171                 var parser = function (fromViewValue) {
8172                     var letters = /^[A-Za-z]+$/;
8173                     var numbers = /^[0-9]+$/;
8174                     if (angular.isUndefined(fromViewValue) || fromViewValue === '') {
8175                         validPhoneNumber = true;
8176                     } else {
8177                         if (fromViewValue.match(letters)) {
8178                             validPhoneNumber = false;
8179                         }
8180                         if (fromViewValue.match(numbers)) {
8181                             validPhoneNumber = true;
8182                         }
8183                     }
8184                     var clean = "";
8185                     if (fromViewValue && fromViewValue.length > 0) {
8186                         clean = fromViewValue.replace(/[^0-9]/g, '');
8187                     }
8188                     checkValidity(clean, fromViewValue);
8189                     return clean;
8190                 };
8191
8192                 //to handle reading the model and formatting it
8193                 var formatter = function (fromModelView) {
8194                     var input = '';
8195                     checkValidity(fromModelView);
8196                     if (fromModelView) {
8197                         input = handleKeyup();
8198                     }
8199                     return input;
8200                 };
8201
8202                 var setCurrentKey = function (e) {
8203                     switch (e.which) {
8204                     case 189:
8205                     case 109:
8206                         currentKey = '-';
8207                         break;
8208                     case 190:
8209                     case 110:
8210                         currentKey = '.';
8211                         break;
8212                     case 57:
8213                         if (e.shiftKey === true) {
8214                             currentKey = '(';
8215                         }
8216                         break;
8217                     case 48:
8218                         if (e.shiftKey === true) {
8219                             currentKey = ')';
8220                         }
8221                         break;
8222                     case 32:
8223                         currentKey = ' ';
8224                         break;
8225                     }
8226                 };
8227
8228                 if (angular.isDefined(scope.ngModel)) {
8229                     parser(scope.ngModel);
8230                 }
8231
8232                 ctrl.$parsers.push(parser);
8233                 ctrl.$formatters.push(formatter);
8234                 iElement.bind('keyup', handleKeyup);
8235                 iElement.bind('keydown', handlePress);
8236             }
8237         };
8238 }]);
8239 /** 
8240  * @ngdoc directive 
8241  * @name Template.att:Profile Blocks 
8242  * 
8243  * @description 
8244  *  <file src="src/profileBlockTemplate/docs/readme.md" /> 
8245  * @example 
8246  *  <section id="code">  
8247         <example module="b2b.att"> 
8248             <file src="src/profileBlockTemplate/docs/demo.html" /> 
8249             <file src="src/profileBlockTemplate/docs/demo.js" /> 
8250        </example>  
8251     </section>  
8252  *  
8253  */   
8254
8255 angular.module('b2b.att.profileBlockTemplate', [])
8256     
8257      
8258   
8259 /**
8260  * @ngdoc directive
8261  * @name Layouts.att:profileCard
8262  *
8263  * @description
8264  *  <file src="src/profileCard/docs/readme.md" />
8265  *
8266  * @usage
8267  *  <b2b-profile-card></b2b-profile-card>
8268  *
8269  * @example
8270     <section id="code">   
8271         <example module="b2b.att">
8272             <file src="src/profileCard/docs/demo.html" />
8273             <file src="src/profileCard/docs/demo.js" />
8274         </example>
8275     </section>
8276  */
8277
8278 angular.module('b2b.att.profileCard', ['b2b.att'])
8279 .constant('profileStatus',{
8280     status: {
8281         ACTIVE: {
8282             status: "Active",
8283             color: "green"
8284         },
8285         DEACTIVATED: {
8286             status: "Deactivated",
8287             color: "red"
8288         },
8289         LOCKED: {
8290             status: "Locked",
8291             color: "red"
8292         },
8293         IDLE: {
8294             status: "Idle",
8295             color: "yellow"
8296         },
8297         PENDING: {
8298             status: "Pending",
8299             color: "blue"
8300         }
8301     },
8302     role: "COMPANY ADMINISTRATOR"
8303
8304 })
8305 .directive('b2bProfileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {
8306    return {
8307         restrict: 'EA',
8308         replace: 'true',
8309         templateUrl: function(element, attrs){
8310             if(!attrs.addUser){
8311                 return 'b2bTemplate/profileCard/profileCard.html';
8312             }
8313             else{
8314                 return 'b2bTemplate/profileCard/profileCard-addUser.html';
8315             }
8316         },
8317         scope: {
8318             profile:'=',
8319             characterLimit: '@'
8320         },
8321         link: function(scope, elem, attr){
8322                 scope.characterLimit = parseInt(attr.characterLimit, 10) || 25;
8323                 scope.shouldClip = function(str) {
8324                         return str.length > scope.characterLimit;
8325                 };
8326
8327                 scope.showEmailTooltip = false;
8328
8329             scope.image=true;
8330             function isImage(src) {
8331                 var deferred = $q.defer();
8332                 var image = new Image();
8333                 image.onerror = function() {
8334                     deferred.reject(false);
8335                 };
8336                 image.onload = function() {
8337                     deferred.resolve(true);
8338                 };
8339                 if(src !== undefined && src.length>0 ){
8340                     image.src = src;
8341                 } else {
8342                      deferred.reject(false);
8343                 }
8344                 return deferred.promise;
8345             }
8346             if(!attr.addUser){
8347             scope.image=false;
8348             isImage(scope.profile.img).then(function(img) {
8349                 scope.image=img;
8350             });
8351             var splitName=(scope.profile.name).split(' ');
8352             scope.initials='';
8353             for(var i=0;i<splitName.length;i++){
8354                 scope.initials += splitName[i][0];
8355             }
8356             if(scope.profile.role.toUpperCase() === profileStatus.role){
8357                 scope.badge=true;
8358             }
8359             var profileState=profileStatus.status[scope.profile.state.toUpperCase()];
8360             if(profileState) {
8361                 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;
8362                 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;
8363                 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){
8364                         scope.profile.lastLogin=scope.profile.state;
8365                 }
8366             }
8367             var today=new Date().getTime();
8368             var lastlogin=new Date(scope.profile.lastLogin).getTime();
8369             var diff=(today-lastlogin)/(1000*60*60*24);
8370             if(diff<=1){
8371                 scope.profile.lastLogin="Today";
8372             }
8373             else if(diff<=2){
8374                 scope.profile.lastLogin="Yesterday";
8375             }
8376         }
8377     }
8378 };
8379 }]);
8380 /**
8381  * @ngdoc directive
8382  * @name Forms.att:radios
8383  *
8384  * @description
8385  *  <file src="src/radios/docs/readme.md" />
8386  *
8387  * @usage
8388  *  See demo section
8389  *
8390  * @param {boolean} refreshRadioGroup - A trigger that recalculates and updates the accessibility roles on radios in a group.
8391  * 
8392  * @example
8393     <section id="code">
8394                <b>HTML + AngularJS</b>
8395                <example module="b2b.att">
8396                 <file src="src/radios/docs/demo.html" />
8397                 <file src="src/radios/docs/demo.js" />
8398                </example>
8399             </section>
8400  */
8401 angular.module('b2b.att.radios', ['b2b.att.utilities'])
8402 .directive('b2bRadioGroupAccessibility', ['$timeout', 'b2bUserAgent', function($timeout, b2bUserAgent) {
8403     return {
8404         restrict: "A",
8405         scope: {
8406             refreshRadioGroup: "=",
8407         },
8408         link: function(scope, ele, attr) {
8409
8410             var roleRadioElement, radioProductSelectElement, radioInputTypeElement;
8411
8412             $timeout(calculateNumberOfRadio);
8413
8414             scope.$watch('refreshRadioGroup', function(value) {
8415                 if (value === true) {
8416                     addingRoleAttribute();
8417                     $timeout(calculateNumberOfRadio);
8418                     scope.refreshRadioGroup = false;
8419                 } else {
8420                     return;
8421                 }
8422             })
8423
8424
8425             function calculateNumberOfRadio() {
8426                 roleRadioElement = ele[0].querySelectorAll('[role="radio"]');
8427
8428                 radioProductSelectElement = ele[0].querySelectorAll('[role="radiogroup"] li.radio-box');
8429
8430                 radioInputTypeElement = ele[0].querySelectorAll('input[type="radio"]');
8431
8432                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8433                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';
8434                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';
8435                     var numOfx = i + 1 + ' of ' + radioInputTypeElement.length;
8436                     angular.element(roleRadioElement[i]).attr({
8437                         'aria-checked': isChecked,
8438                         'aria-disabled': isDisabled,
8439                         'data-opNum': numOfx
8440                     });
8441                     if (b2bUserAgent.notMobile()) {
8442                         angular.element(roleRadioElement[i]).removeAttr("role");
8443                     }
8444
8445                     if (radioProductSelectElement.length) {
8446                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');
8447                     }
8448
8449                     if (/Android/i.test(navigator.userAgent)) {
8450                         angular.element(roleRadioElement[i]).append('<span class="hidden-spoken">. ' + numOfx + '.</span>');
8451                     }
8452
8453
8454                     angular.element(radioInputTypeElement[i]).bind('click', radioStateChangeonClick);
8455
8456                 }
8457             }
8458
8459             function addingRoleAttribute() {
8460                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8461                     if (b2bUserAgent.notMobile()) {
8462                         angular.element(roleRadioElement[i]).attr("role", "radio");
8463                     }
8464                 }
8465             }
8466
8467             function radioStateChangeonClick() {
8468                 for (var i = 0; i < radioInputTypeElement.length; i++) {
8469                     var isChecked = radioInputTypeElement[i].checked ? 'true' : 'false';
8470                     var isDisabled = radioInputTypeElement[i].disabled ? 'true' : 'false';
8471                     if (radioProductSelectElement.length) {
8472                         isChecked === 'true' ? angular.element(radioProductSelectElement[i]).addClass('active') : angular.element(radioProductSelectElement[i]).removeClass('active');
8473                     }
8474                     angular.element(roleRadioElement[i]).attr({
8475                         'aria-checked': isChecked,
8476                         'aria-disabled': isDisabled
8477                     });
8478                 }
8479
8480             }
8481         }
8482     }
8483
8484 }]);
8485
8486 /**
8487  * @ngdoc directive
8488  * @name Forms.att:searchField
8489  *
8490  * @description
8491  *  <file src="src/searchField/docs/readme.md" />
8492  *
8493  * @usage
8494  *  <div b2b-search-field dropdown-list="listdata" on-click-callback="clickFn(value)" class="span12" input-model='typedString' config-obj='keyConfigObj'></div>
8495  *
8496  * @example
8497  <section id="code">
8498     <example module="b2b.att">
8499     <file src="src/searchField/docs/demo.html" />
8500     <file src="src/searchField/docs/demo.js" />
8501     </example>
8502 </section>
8503  */
8504
8505 angular.module('b2b.att.searchField', ['b2b.att.utilities', 'b2b.att.position'])
8506     .filter('b2bFilterInput', [function() {
8507         return function(list, str, keyArray, displayListKey, isContainsSearch, searchSeperator) {
8508             var res = [];
8509             var searchLabel;
8510             var searchCondition;
8511             var conditionCheck = function(searchSeperator, listItem, displayListKey, splitString) {
8512                 var displayTitle = null;
8513                 if (splitString) {
8514                     for (var i = 0; i < displayListKey.length; i++) {
8515                         if (i <= 0) {
8516                             displayTitle = listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase()) > -1;
8517                         } else {
8518                             displayTitle = (splitString[i]) ? displayTitle && listItem[displayListKey[i]].toLowerCase().indexOf(splitString[i].toLowerCase().trim()) > -1 : displayTitle;
8519                         }
8520                     }
8521                 } else {
8522                     angular.forEach(displayListKey, function(value) {
8523                         if (!displayTitle) {
8524                             displayTitle = listItem[value];
8525                         } else {
8526                             displayTitle = displayTitle + (listItem[value] ? searchSeperator + ' ' + listItem[value] : '');
8527                         }
8528                     });
8529                 }
8530                 return displayTitle;
8531             }
8532             angular.forEach(list, function(listItem) {
8533                 var splitString = str.indexOf(searchSeperator) > -1 ? str.split(searchSeperator) : false;
8534                 var displayList = conditionCheck(searchSeperator, listItem, displayListKey, splitString)
8535                 for (var i = 0; i < keyArray.length; i++) {
8536                     searchLabel = keyArray[i];
8537                     if (listItem[searchLabel]) {
8538                         if (isContainsSearch) {
8539                             var displaySearchList = listItem[searchLabel].toLowerCase().indexOf(str.toLowerCase()) > -1;
8540                             if (splitString.length > 1) {
8541                                 displaySearchList = (splitString.length <= keyArray.length) ? displayList : false;
8542                             }
8543                             searchCondition = displaySearchList;
8544                         } else {
8545                             searchCondition = listItem[searchLabel].match(new RegExp('^' + str, 'gi'));
8546                         }
8547                         if (searchCondition) {
8548                             res.push({
8549                                 'title': conditionCheck(searchSeperator, listItem, displayListKey),
8550                                 'valueObj': listItem
8551                             });
8552                             break;
8553                         }
8554                     }
8555                 }
8556             });
8557             return res;
8558         };
8559     }]).directive('b2bSearchField', ['$filter', 'b2bFilterInputFilter', 'keymap', '$documentBind', '$isElement', '$document', 'events', '$timeout', function($filter, b2bFilterInput, keymap, $documentBind, $isElement, $document, events, $timeout) {
8560         return {
8561             restrict: 'A',
8562             scope: {
8563                 dataList: '=dropdownList',
8564                 onClickCallback: '&',
8565                 inputModel: '=',
8566                 configObj: '=',
8567                 objModel: '=',
8568                 inputDeny: '=?',
8569                 disabled: '=?'
8570             },
8571             replace: true,
8572             templateUrl: 'b2bTemplate/searchField/searchField.html',
8573             controller: ['$scope', function($scope) {
8574                 this.searchKeyArray = [];
8575                 if ($scope.configObj.searchKeys) {
8576                     this.searchKeyArray = $scope.configObj.searchKeys;
8577                 }
8578                 if (angular.isUndefined($scope.disabled)) {
8579                     $scope.disabled = false;
8580                 }
8581                 this.triggerInput = function(searchString) {
8582                     $scope.originalInputModel = searchString;
8583                     if (searchString === '') {
8584                         $scope.currentIndex = -1;
8585                         $scope.filterList = [];
8586                         $scope.showListFlag = false;
8587                     } else if (searchString !== '' && !$scope.isFilterEnabled) {
8588                         $scope.filterList = $filter('b2bFilterInput')($scope.dataList, searchString, this.searchKeyArray, $scope.configObj.displayListDataKey, $scope.configObj.isContainsSearch, $scope.configObj.searchSeperator);
8589                         $scope.showListFlag = true;
8590                     }
8591                 };
8592                 this.denyRegex = function() {
8593                     return $scope.inputDeny;
8594                 };
8595             }],
8596             link: function(scope, elem) {
8597                 scope.isFilterEnabled = false;
8598                 scope.showListFlag = false;
8599                 scope.currentIndex = -1;
8600                 scope.setCurrentIdx = function(idx) {
8601                     scope.currentIndex = idx;
8602                     if (idx > -1) {
8603                         scope.inputModel = scope.filterList[idx].title;
8604                         scope.objModel = scope.filterList[idx];
8605                     }
8606                 };
8607                 scope.isActive = function(index, dropdownLength) {
8608                     scope.dropdownLength = dropdownLength;
8609                     return scope.currentIndex === index;
8610                 };
8611                 scope.selectItem = function(idx) {
8612                     scope.setCurrentIdx(idx);
8613                     scope.onClickCallback({
8614                         value: scope.inputModel,
8615                         objValue: scope.objModel
8616                     });
8617                     scope.showListFlag = false;
8618                     $timeout(function() {
8619                         elem.find('div').find('input')[0].focus();
8620                     }, 150);
8621                 };
8622                 scope.startSearch = function() {
8623                     scope.onClickCallback({
8624                         value: scope.inputModel,
8625                         objValue: scope.objModel
8626                     });
8627                 };
8628                 scope.selectPrev = function() {
8629                     if (scope.currentIndex > 0 && scope.filterList.length > 0) {
8630                         scope.currentIndex = scope.currentIndex - 1;
8631                         scope.setCurrentIdx(scope.currentIndex);
8632                     } else if (scope.currentIndex === 0) {
8633                         scope.currentIndex = scope.currentIndex - 1;
8634                         scope.inputModel = scope.originalInputModel;
8635                         scope.isFilterEnabled = true;
8636                     }
8637                 };
8638                 scope.selectNext = function() {
8639                     if (scope.currentIndex < scope.configObj.noOfItemsDisplay - 1) {
8640                         if (scope.currentIndex < scope.filterList.length - 1) {
8641                             scope.currentIndex = scope.currentIndex + 1;
8642                             scope.setCurrentIdx(scope.currentIndex);
8643                         }
8644                     }
8645                 };
8646                 scope.selectCurrent = function() {
8647                     scope.selectItem(scope.currentIndex);
8648                 };
8649                 scope.selectionIndex = function(e) {
8650                     switch (e.keyCode) {
8651                         case keymap.KEY.DOWN:
8652                             events.preventDefault(e);
8653                             scope.isFilterEnabled = true;
8654                             scope.selectNext();
8655                             break;
8656                         case keymap.KEY.UP:
8657                             events.preventDefault(e);
8658                             scope.isFilterEnabled = true;
8659                             scope.selectPrev();
8660                             break;
8661                         case keymap.KEY.ENTER:
8662                             events.preventDefault(e);
8663                             scope.isFilterEnabled = true;
8664                             scope.selectCurrent();
8665                             break;
8666                         case keymap.KEY.ESC:
8667                             events.preventDefault(e);
8668                             scope.isFilterEnabled = false;
8669                             scope.showListFlag = false;
8670                             scope.inputModel = '';
8671                             break;
8672                         default:
8673                             scope.isFilterEnabled = false;
8674                             break;
8675                     }
8676                     if (elem[0].querySelector('.filtercontainer')) {
8677                         elem[0].querySelector('.filtercontainer').scrollTop = (scope.currentIndex - 1) * 35;
8678                     }
8679                 };
8680                 scope.$watch('filterList', function(newVal, oldVal) {
8681                     if (newVal !== oldVal) {
8682                         scope.currentIndex = -1;
8683                     }
8684                 });
8685                 scope.blurInput = function() {
8686                     $timeout(function() {
8687                         scope.showListFlag = false;
8688                     }, 150);
8689                 };
8690                 var outsideClick = function(e) {
8691                     var isElement = $isElement(angular.element(e.target), elem.find('ul').eq(0), $document);
8692                     if (!isElement && document.activeElement.tagName.toLowerCase() !== 'input') {
8693                         scope.showListFlag = false;
8694                         scope.$apply();
8695                     }
8696                 };
8697                 $documentBind.click('showListFlag', outsideClick, scope);
8698             }
8699         };
8700     }])
8701     .directive('b2bSearchInput', [function() {
8702         return {
8703             restrict: 'A',
8704             require: ['ngModel', '^b2bSearchField'],
8705             link: function(scope, elem, attr, ctrl) {
8706                 var ngModelCtrl = ctrl[0];
8707                 var attSearchBarCtrl = ctrl[1];
8708                 var REGEX = ctrl[1].denyRegex();
8709                 var parser = function(viewValue) {
8710                     attSearchBarCtrl.triggerInput(viewValue);
8711                     return viewValue;
8712                 };
8713                 ngModelCtrl.$parsers.push(parser);
8714
8715                 if (REGEX !== undefined || REGEX !== '') {
8716                     elem.bind('input', function() {
8717                         var inputString = ngModelCtrl.$viewValue && ngModelCtrl.$viewValue.replace(REGEX, '');
8718                         if (inputString !== ngModelCtrl.$viewValue) {
8719                             ngModelCtrl.$setViewValue(inputString);
8720                             ngModelCtrl.$render();
8721                             scope.$apply();
8722                         }
8723                     });
8724                 }
8725             }
8726         };
8727     }]);
8728
8729 /**
8730  * @ngdoc directive
8731  * @name Buttons, links & UI controls.att:Seek bar
8732  *
8733  * @description
8734  *  <file src="src/seekBar/docs/readme.md" />
8735  *
8736  * @usage
8737  *  Horizontal Seek Bar
8738  *      <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>
8739
8740  *      Vertical Seek Bar
8741  *      <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>
8742  *
8743  * @example
8744     <section id="code">   
8745         <b>HTML + AngularJS</b>
8746         <example module="b2b.att">
8747             <file src="src/seekBar/docs/demo.html" />
8748             <file src="src/seekBar/docs/demo.js" />
8749         </example>
8750     </section>
8751  */
8752
8753 angular.module('b2b.att.seekBar', ['b2b.att.utilities','b2b.att.position'])
8754         .constant('b2bSeekBarConfig', {
8755             'min': 0,
8756             'max': 100,
8757             'step': 1,
8758             'skipInterval': 1
8759         })
8760         .directive('b2bSeekBar', ['$documentBind', 'events', 'b2bSeekBarConfig', 'keymap', '$compile', function($documentBind, events, b2bSeekBarConfig, keymap, $compile) {
8761                 return {
8762                     restrict: 'AE',
8763                     replace: true,
8764                     require: 'ngModel',
8765                     templateUrl: 'b2bTemplate/seekBar/seekBar.html',
8766                     scope: {
8767                         onDragEnd: '&?',
8768                         onDragInit: '&?'
8769                     },
8770                     link: function(scope, elm, attr, ngModelCtrl) {
8771                         scope.isDragging = false;
8772                         scope.verticalSeekBar = false;
8773                         var min;
8774                         var max;
8775                         var step = b2bSeekBarConfig.step;
8776                         var skipInterval = b2bSeekBarConfig.skipInterval;
8777                         var knob = angular.element(elm[0].querySelector('.b2b-seek-bar-knob-container'));
8778                         var seekBarKnob = angular.element(knob[0].querySelector('.b2b-seek-bar-knob'));
8779                         var trackContainer = angular.element(elm[0].querySelector('.b2b-seek-bar-track-container'));
8780                         var trackFill = angular.element(elm[0].querySelector('.b2b-seek-bar-track-fill'));
8781                         var trackContainerRect = {};
8782                         var axisPosition;
8783                         var trackFillOrderPositioning;
8784
8785                         if (angular.isDefined(attr.vertical)) {
8786                             scope.verticalSeekBar = true;
8787                             axisPosition = "clientY";
8788                         }
8789                         else {
8790                             scope.verticalSeekBar = false;
8791                             axisPosition = "clientX";
8792                         }
8793                         var getValidStep = function(val) {
8794                             val = parseFloat(val);
8795                             // in case $modelValue came in string number
8796                             if (angular.isNumber(val)) {
8797                                 val = Math.round((val - min) / step) * step + min;
8798                                 return Math.round(val * 1000) / 1000;
8799                             }
8800                         };
8801
8802                         var getPositionToPercent = function(x) {
8803                             if (scope.verticalSeekBar) {
8804                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));
8805                             }
8806                             else {
8807                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));
8808                             }
8809                         };
8810
8811                         var getPercentToValue = function(percent) {
8812                             return (min + percent * (max - min));
8813                         };
8814
8815                         var getValueToPercent = function(val) {
8816                             return (val - min) / (max - min);
8817                         };
8818
8819                         var getValidMinMax = function(val) {
8820                             return Math.max(min, Math.min(max, val));
8821                         };
8822
8823                         var updateTrackContainerRect = function() {
8824                             trackContainerRect = trackContainer[0].getBoundingClientRect();
8825                             if (scope.verticalSeekBar) {
8826                                 if (!trackContainerRect.height) {
8827                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;
8828                                 } else {
8829                                     trackFillOrderPositioning = trackContainerRect.height;
8830                                 }
8831                             }
8832                             else {
8833                                 if (!trackContainerRect.width) {
8834                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;
8835                                 } else {
8836                                     trackFillOrderPositioning = trackContainerRect.width;
8837                                 }
8838
8839                             }
8840
8841                         };
8842
8843                         var updateKnobPosition = function(percent) {
8844                             var percentStr = (percent * 100) + '%';
8845                             if (scope.verticalSeekBar) {
8846                                 knob.css('bottom', percentStr);
8847                                 trackFill.css('height', percentStr);
8848                             }
8849                             else {
8850                                 knob.css('left', percentStr);
8851                                 trackFill.css('width', percentStr);
8852                             }
8853                         };
8854
8855                         var modelRenderer = function() {
8856                             if (isNaN(ngModelCtrl.$viewValue)) {
8857                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;
8858                             }
8859
8860                             var viewVal = ngModelCtrl.$viewValue;
8861                             scope.currentModelValue = viewVal;
8862
8863                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation
8864                             if ((min || min === 0) && max && step) {
8865                                 updateKnobPosition(getValueToPercent(viewVal));
8866                             }
8867                         };
8868
8869                         var setModelValue = function(val) {
8870                             scope.currentModelValue = getValidMinMax(getValidStep(val));
8871                             ngModelCtrl.$setViewValue(scope.currentModelValue);
8872                         };
8873
8874                         var updateMin = function(val) {
8875                             min = parseFloat(val);
8876                             if(isNaN(min)){
8877                                min = b2bSeekBarConfig.min; 
8878                             }
8879                             modelRenderer();
8880                         };
8881
8882                         var updateMax = function(val) {
8883                             max = parseFloat(val);
8884                             if(isNaN(max)){
8885                                max = b2bSeekBarConfig.max; 
8886                             }
8887                             modelRenderer();
8888                         };
8889
8890                         var updateStep = function(val) {
8891                             step = parseFloat(val);
8892                             if (!attr['skipInterval']) {
8893                                 skipInterval = step;
8894                             }
8895                         };
8896
8897                         var updateSkipInterval = function(val) {
8898                             skipInterval = step * Math.ceil(val / (step!==0?step:1));
8899                         };
8900
8901                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(b2bSeekBarConfig.min);
8902                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(b2bSeekBarConfig.max);
8903                         if (angular.isDefined(attr.step)) {
8904                             attr.$observe('step', updateStep);
8905                         }
8906                         if (angular.isDefined(attr.skipInterval)) {
8907                             attr.$observe('skipInterval', updateSkipInterval);
8908                         }
8909                         scope.currentModelValue = getValidMinMax(getValidStep(min));
8910                         var onMouseDown = function(e) {
8911                             switch (e.which) {
8912                                 case 1:
8913                                     // left mouse button
8914                                     break;
8915                                 case 2:
8916                                 case 3:
8917                                     // right or middle mouse button
8918                                     return;
8919                             }
8920                             ;
8921
8922                             scope.isDragging = true;
8923                             seekBarKnob[0].focus();
8924                             updateTrackContainerRect();
8925                             if (attr['onDragInit']) {
8926                                 scope.onDragInit();
8927                             }
8928                             events.stopPropagation(e);
8929                             events.preventDefault(e);
8930                              scope.$apply(function() {
8931                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
8932                             });
8933                         };
8934
8935                         var onMouseUp = function() {
8936
8937                             if (attr['onDragEnd']) {
8938                                 scope.onDragEnd();
8939                             }
8940                             scope.isDragging = false;
8941                             scope.$digest();
8942                         };
8943
8944                         var onMouseMove = function(e) {
8945                             if (scope.isDragging) {
8946                                 events.stopPropagation(e);
8947                                 events.preventDefault(e);
8948
8949                                 scope.$apply(function() {
8950                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
8951                                 });
8952                             }
8953                         };
8954
8955                         function onKeyDown(e) {
8956                             if (!(e.keyCode)) {
8957                                 e.keyCode = e.which;
8958                             }
8959                             var updateStep;
8960                             switch (e.keyCode) {
8961                                 case keymap.KEY.LEFT:
8962                                     if (!scope.verticalSeekBar) {
8963                                         updateStep = -skipInterval;
8964                                     }
8965                                     break;
8966                                 case keymap.KEY.RIGHT:
8967                                     if (!scope.verticalSeekBar) {
8968                                         updateStep = skipInterval;
8969                                     }
8970                                     break;
8971                                 case keymap.KEY.UP:
8972                                     if (scope.verticalSeekBar) {
8973                                         updateStep = skipInterval;
8974                                     }
8975                                     break;
8976                                 case keymap.KEY.DOWN:
8977                                     if (scope.verticalSeekBar) {
8978                                         updateStep = -skipInterval;
8979                                     }
8980                                     break;
8981                                 default:
8982                                     return;
8983                             }
8984
8985                             if (updateStep) {
8986                                 events.stopPropagation(e);
8987                                 events.preventDefault(e);
8988                                 scope.$apply(function() {
8989                                     setModelValue(ngModelCtrl.$viewValue + updateStep);
8990                                 });
8991                                 if (attr['onDragEnd']) {
8992                                 scope.onDragEnd();
8993                             }
8994                             }
8995                         }
8996
8997                         elm.on('keydown', onKeyDown);
8998                         elm.on('mousedown', onMouseDown);
8999
9000                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);
9001                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);
9002
9003                         ngModelCtrl.$render = function() {
9004                             if (!scope.isDragging) {
9005                                 modelRenderer();
9006                             }
9007                         };
9008                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);
9009                         ngModelCtrl.$formatters.push(getValidMinMax);
9010                         ngModelCtrl.$formatters.push(getValidStep);
9011                     }
9012                 };
9013             }]);
9014 /**
9015  * @ngdoc directive
9016  * @name Layouts.att:separators
9017  *
9018  * @description
9019  *  <file src="src/separators/docs/readme.md" />
9020  *
9021  * @usage
9022
9023  *
9024  * @example
9025  *  <section id="code">   
9026  <b>HTML + AngularJS</b>
9027  <example module="b2b.att">
9028  <file src="src/separators/docs/demo.html" />
9029  <file src="src/separators/docs/demo.js" />
9030  </example>
9031  </section>
9032  *
9033  */
9034
9035 angular.module('b2b.att.separators', []);
9036 /**
9037  * @ngdoc directive
9038  * @name Buttons, links & UI controls.att:slider
9039  *
9040  * @description
9041  *  <file src="src/slider/docs/readme.md" />
9042  *
9043  * @usage
9044  *  <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>
9045  *
9046  * @example
9047     <section id="code">   
9048         <b>HTML + AngularJS</b>
9049         <example module="b2b.att">
9050             <file src="src/slider/docs/demo.html" />
9051             <file src="src/slider/docs/demo.js" />
9052         </example>
9053     </section>
9054  */
9055
9056 angular.module('b2b.att.slider', ['b2b.att.utilities'])
9057         .constant('SliderConfig', {
9058             'min': 0,
9059             'max': 100,
9060             'step': 1,
9061             'skipInterval': 1
9062         })
9063         .directive('b2bSlider', ['$documentBind', 'SliderConfig', 'keymap', '$compile', '$log', function($documentBind, SliderConfig, keymap, $compile, $log) {
9064                 return {
9065                     restrict: 'AE',
9066                     replace: true,
9067                     require: 'ngModel',
9068                     templateUrl: 'b2bTemplate/slider/slider.html',
9069                     scope: {
9070                         onDragEnd: '&?',
9071                         onDragInit: '&?',
9072                         trackFillColor: '=?',
9073                         preAriaLabel: '=?',
9074                         postAriaLabel: '=?',
9075                         onRenderEnd: '&?',
9076                         sliderSnapPoints: '=?',
9077                         customAriaLabel: '=?',
9078                         labelId: '@?'
9079                     },
9080                     link: function(scope, elm, attr, ngModelCtrl) {
9081                         scope.isDragging = false;
9082                         scope.verticalSlider = false;
9083                         var min;
9084                         var max;
9085                         var step = SliderConfig.step;
9086                         var skipInterval = SliderConfig.skipInterval;
9087                         var knob = angular.element(elm[0].querySelector('.slider-knob-container'));
9088                         var sliderKnob = angular.element(knob[0].querySelector('.slider-knob'));
9089                         var trackContainer = angular.element(elm[0].querySelector('.slider-track-container'));
9090                         var trackFill = angular.element(elm[0].querySelector('.slider-track-fill'));
9091                         var trackContainerRect = {};
9092                         var axisPosition = "clientX";
9093                         var trackFillOrderPositioning;
9094
9095                         //Forcefully disabling the vertical Slider code.
9096                         if (angular.isDefined(attr.vertical)) {
9097                             scope.verticalSlider = true;
9098                             axisPosition = "clientY";
9099                         }
9100
9101                         if (angular.isDefined(scope.noAriaLabel) && scope.noAriaLabel !== '') {
9102                             $log.warn('no-aria-label has been deprecated. This will be removed in v0.6.0.');
9103                         }
9104                         if (angular.isDefined(scope.preAriaLabel) && scope.preAriaLabel !== '') {
9105                             $log.warn('pre-aria-label has been deprecated. Please use label-id instead. This will be removed in v0.6.0.');
9106                         }
9107                         if (angular.isDefined(scope.customAriaLabel) && scope.customAriaLabel !== '') {
9108                             $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.');
9109                         }
9110
9111                         var binarySearchNearest = function (num, arr) {
9112                             var mid;
9113                             var lo = 0;
9114                             var hi = arr.length - 1;
9115                             
9116                             while (hi - lo > 1) {
9117                                 mid = Math.floor((lo + hi) / 2);
9118                                 if (arr[mid] < num) {
9119                                     lo = mid;
9120                                 } else {
9121                                     hi = mid;
9122                                 }
9123                             }
9124                             if (num - arr[lo] < arr[hi] - num) {
9125                                 return arr[lo];
9126                             }
9127                             return arr[hi];
9128                         };
9129                         
9130                         var getValidStep = function(val) {
9131                             val = parseFloat(val);
9132                             // in case $modelValue came in string number
9133                             if (!isNaN(val)) {
9134                                 
9135                                 if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9136                                     val = binarySearchNearest(val, scope.sliderSnapPoints);
9137                                 }
9138                                 else {
9139                                     val = Math.round((val - min) / step) * step + min;
9140                                 }
9141                                 
9142                                 return Math.round(val * 1000) / 1000;
9143                             }
9144                         };
9145
9146                         var getPositionToPercent = function(x) {
9147                             if (scope.verticalSlider) {
9148                                 return Math.max(0, Math.min(1, (trackContainerRect.bottom - x) / (trackFillOrderPositioning)));
9149                             }
9150                             else {
9151                                 return Math.max(0, Math.min(1, (x - trackContainerRect.left) / (trackFillOrderPositioning)));
9152                             }
9153                         };
9154
9155                         var getPercentToValue = function(percent) {
9156                             return (min + percent * (max - min));
9157                         };
9158
9159                         var getValueToPercent = function(val) {
9160                             return (val - min) / (max - min);
9161                         };
9162
9163                         var getValidMinMax = function(val) {
9164                             return Math.max(min, Math.min(max, val));
9165                         };
9166
9167                         var updateTrackContainerRect = function() {
9168                             trackContainerRect = trackContainer[0].getBoundingClientRect();
9169                             if (scope.verticalSlider) {
9170                                 if (!trackContainerRect.height) {
9171                                     trackFillOrderPositioning = trackContainer[0].scrollHeight;
9172                                 } else {
9173                                     trackFillOrderPositioning = trackContainerRect.height;
9174                                 }
9175                             }
9176                             else {
9177                                 if (!trackContainerRect.width) {
9178                                     trackFillOrderPositioning = trackContainer[0].scrollWidth;
9179                                 } else {
9180                                     trackFillOrderPositioning = trackContainerRect.width;
9181                                 }
9182
9183                             }
9184
9185                         };
9186
9187                         var updateKnobPosition = function(percent) {
9188                             var percentStr = (percent * 100) + '%';
9189                             if (scope.verticalSlider) {
9190                                 knob.css('bottom', percentStr);
9191                                 trackFill.css('height', percentStr);
9192                             }
9193                             else {
9194                                 knob.css('left', percentStr);
9195                                 trackFill.css('width', percentStr);
9196                             }
9197                         };
9198
9199                         var modelRenderer = function() {
9200
9201                             if(attr['disabled']){
9202                                 return;
9203                             }
9204
9205                             if (isNaN(ngModelCtrl.$viewValue)) {
9206                                 ngModelCtrl.$viewValue = ngModelCtrl.$modelValue || min;
9207                             }
9208
9209                             var viewVal = ngModelCtrl.$viewValue;
9210                             scope.currentModelValue = viewVal;
9211
9212                             //wait for min, max and step to be set then only update UI to avoid NaN on percent calculation
9213                             if ((min || min === 0) && max && step) {
9214                                 updateKnobPosition(getValueToPercent(viewVal));
9215                             }
9216                         };
9217
9218                         var setModelValue = function(val) {
9219                             scope.currentModelValue = getValidMinMax(getValidStep(val));
9220                             ngModelCtrl.$setViewValue(scope.currentModelValue);
9221                         };
9222
9223                         var updateMin = function(val) {
9224                             min = parseFloat(val);
9225                             if(isNaN(min)){
9226                                min = SliderConfig.min; 
9227                             }
9228                             scope.min = min;
9229                             modelRenderer();
9230                         };
9231
9232                         var updateMax = function(val) {
9233                             max = parseFloat(val);
9234                             if(isNaN(max)){
9235                                max = SliderConfig.max; 
9236                             }
9237                             scope.max = max;
9238                             modelRenderer();
9239                         };
9240
9241                         var updateStep = function(val) {
9242                             step = parseFloat(val);
9243                             if (!attr['skipInterval']) {
9244                                 skipInterval = step;
9245                             }
9246                         };
9247
9248                         var updateSkipInterval = function(val) {
9249                             skipInterval = step * Math.ceil(val / (step!==0?step:1));
9250                         };
9251
9252                         angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(SliderConfig.min);
9253                         angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(SliderConfig.max);
9254                         if (angular.isDefined(attr.step)) {
9255                             attr.$observe('step', updateStep);
9256                         }
9257                         if (angular.isDefined(attr.skipInterval)) {
9258                             attr.$observe('skipInterval', updateSkipInterval);
9259                         }
9260                         scope.currentModelValue = getValidMinMax(getValidStep(min));
9261                         var onMouseDown = function(e) {
9262
9263                             if(attr['disabled']){
9264                                 return;
9265                             }
9266
9267                             switch (e.which) {
9268                                 case 1:
9269                                     // left mouse button
9270                                     break;
9271                                 case 2:
9272                                 case 3:
9273                                     // right or middle mouse button
9274                                     return;
9275                             }
9276
9277                             scope.isDragging = true;
9278                             sliderKnob[0].focus();
9279                             updateTrackContainerRect();
9280                             if (attr['onDragInit']) {
9281                                 scope.onDragInit();
9282                             }
9283                             e.stopPropagation();
9284                             e.preventDefault();
9285                              scope.$apply(function() {
9286                                 setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
9287                             });
9288                         };
9289
9290                         var onMouseUp = function() {
9291
9292                             if (attr['onDragEnd']) {
9293                                 scope.onDragEnd();
9294                             }
9295                             scope.isDragging = false;
9296                             scope.$digest();
9297                         };
9298
9299                         var onMouseMove = function(e) {
9300                             if (scope.isDragging) {
9301                                 e.stopPropagation();
9302                                 e.preventDefault();
9303
9304                                 scope.$apply(function() {
9305                                     setModelValue(getPercentToValue(getPositionToPercent(e[axisPosition])));
9306                                 });
9307                             }
9308                         };
9309
9310                         function onKeyDown(e) {
9311                             if (!(e.keyCode)) {
9312                                 e.keyCode = e.which;
9313                             }
9314                             var updateStep;
9315                             switch (e.keyCode) {
9316                                 case keymap.KEY.DOWN:
9317                                 case keymap.KEY.LEFT:
9318                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9319                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);
9320                                         if (currentIndex > 0) {
9321                                             currentIndex--;
9322                                         }
9323                                         updateStep = scope.sliderSnapPoints[currentIndex];
9324                                     }
9325                                     else {
9326                                         updateStep = ngModelCtrl.$viewValue - skipInterval;
9327                                     }
9328                                     break;
9329                                 case keymap.KEY.UP:
9330                                 case keymap.KEY.RIGHT:
9331                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9332                                         var currentIndex = scope.sliderSnapPoints.indexOf(ngModelCtrl.$viewValue);
9333                                         if (currentIndex < scope.sliderSnapPoints.length-1) {
9334                                             currentIndex++;
9335                                         }
9336                                         updateStep = scope.sliderSnapPoints[currentIndex];
9337                                     }
9338                                     else {
9339                                         updateStep = ngModelCtrl.$viewValue + skipInterval;
9340                                     }
9341                                     break;
9342                                 case keymap.KEY.END:
9343                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9344                                         currentIndex = scope.sliderSnapPoints.length-1;
9345                                         updateStep = scope.sliderSnapPoints[currentIndex];
9346                                     } else {
9347                                         setModelValue(scope.max);
9348                                     }
9349                                     e.preventDefault();
9350                                     e.stopPropagation();
9351                                     break;
9352                                 case keymap.KEY.HOME:
9353                                     if(attr['sliderSnapPoints'] && scope.sliderSnapPoints.length > 0) {
9354                                         currentIndex = 0;
9355                                         updateStep = scope.sliderSnapPoints[currentIndex];
9356                                     } else {
9357                                         setModelValue(scope.min);
9358                                     }
9359                                     e.preventDefault();
9360                                     e.stopPropagation();
9361                                     break;
9362                                 default:
9363                                     return;
9364                             }
9365
9366                             if (angular.isNumber(updateStep) && !attr['disabled']) {
9367                                 e.stopPropagation();
9368                                 e.preventDefault();
9369                                 scope.$apply(function() {
9370                                     setModelValue(updateStep);
9371                                 });
9372                                 if (attr['onDragEnd']) {
9373                                     scope.onDragEnd();
9374                                 }
9375                             }
9376                         }
9377
9378                         elm.on('keydown', onKeyDown);
9379                         elm.on('mousedown', onMouseDown);
9380
9381                         $documentBind.event('mousemove', 'isDragging', onMouseMove, scope, true, 0);
9382                         $documentBind.event('mouseup', 'isDragging', onMouseUp, scope, true, 0);
9383
9384                         attr.$observe('disabled', function (disabled) {
9385                             if (disabled) {
9386                                 sliderKnob.removeAttr('tabindex');
9387                             } else {
9388                                 sliderKnob.attr('tabindex', '0');
9389                                 disabled = false;
9390                             }
9391
9392                             elm.toggleClass("slider-disabled", disabled);
9393
9394                             if (angular.isDefined(attr.hideDisabledKnob)) {
9395                                 scope.hideKnob = disabled;
9396                             }
9397                         });
9398
9399                         ngModelCtrl.$render = function() {
9400                             if (!scope.isDragging) {
9401                                 modelRenderer();
9402                                 if (attr['onRenderEnd'] && !attr['disabled']) {
9403                                     scope.onRenderEnd({currentModelValue: scope.currentModelValue});
9404                                 }
9405                             }
9406                         };
9407                         ngModelCtrl.$viewChangeListeners.push(modelRenderer);
9408                         ngModelCtrl.$formatters.push(getValidMinMax);
9409                         ngModelCtrl.$formatters.push(getValidStep);
9410                     }
9411                 };
9412             }]);
9413 /**
9414  * @ngdoc directive
9415  * @name Forms.att:spinButton
9416  *
9417  * @param {String} spin-button-id - An ID for the input field
9418  * @param {Integer} min - Minimum value for the input
9419  * @param {Integer} max - Maximum value for the input
9420  * @param {Integer} step - Value by which input field increments or decrements on up/down arrow keys
9421  * @param {Integer} page-step - Value by which input field increments or decrements on page up/down keys
9422  * @param {boolean} input-model-key - Default value for input field
9423  * @param {boolean} disabled-flag - A boolean that triggers directive once the min or max value has reached
9424  *
9425  * @description
9426  *  <file src="src/spinButton/docs/readme.md" />
9427  *
9428  * @example
9429  *      <section id="code">
9430             <example module="b2b.att">
9431             <file src="src/spinButton/docs/demo.html" />
9432             <file src="src/spinButton/docs/demo.js" />
9433        </example>
9434         </section>
9435  * 
9436  */
9437 angular.module('b2b.att.spinButton', ['b2b.att.utilities'])
9438     .constant('b2bSpinButtonConfig', {
9439         min: 1,
9440         max: 10,
9441         step: 1,
9442         pageStep: 10,
9443         inputModelKey: 'value',
9444         disabledFlag: false
9445     })
9446     .directive('b2bSpinButton', ['keymap', 'b2bSpinButtonConfig', 'b2bUserAgent', function (keymap, b2bSpinButtonConfig, userAgent) {
9447         return {
9448             restrict: 'EA',
9449             require: '?ngModel',
9450             transclude: false,
9451             replace: true,
9452             scope: {
9453                 min: '=min',
9454                 max: '=max',
9455                 step: '=step',
9456                 pageStep: '=pageStep',
9457                 spinButtonId: '@',
9458                 inputValue: '=ngModel',
9459                 inputModelKey: '@',
9460                 disabledFlag: "=?"
9461             },
9462             templateUrl: 'b2bTemplate/spinButton/spinButton.html',
9463             controller: ['$scope', '$element', '$attrs', function (scope, element, attrs) {
9464
9465                 scope.isMobile = userAgent.isMobile();
9466                 scope.notMobile = userAgent.notMobile();
9467
9468                 scope.min = attrs.min ? scope.min : b2bSpinButtonConfig.min;
9469                 scope.max = attrs.max ? scope.max : b2bSpinButtonConfig.max;
9470                 scope.step = attrs.step ? scope.step : b2bSpinButtonConfig.step;
9471                 scope.pageStep = attrs.pageStep ? scope.pageStep : b2bSpinButtonConfig.pageStep;
9472                 scope.inputModelKey = attrs.inputModelKey ? scope.inputModelKey : b2bSpinButtonConfig.inputModelKey;
9473                 scope.disabledFlag = attrs.disabledFlag ? scope.disabledFlag : b2bSpinButtonConfig.disabledFlag;
9474                 
9475                 if (scope.min < 0) {
9476                     scope.min = 0;
9477                 }
9478                 if (scope.max > 999) {
9479                     scope.max = 999;
9480                 }
9481
9482                 scope.isPlusDisabled = function () {
9483                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] >= scope.max);
9484                 };
9485                 scope.isMinusDisabled = function () {
9486                     return (scope.disabledFlag || scope.inputValue[scope.inputModelKey] <= scope.min);
9487                 };
9488
9489                 scope.getValidateInputValue = function (value) {
9490                     if (value <= scope.min) {
9491                         return scope.min;
9492                     } else if (value >= scope.max) {
9493                         return scope.max;
9494                     } else {
9495                         return value;
9496                     }
9497                 };
9498
9499                 scope.plus = function () {
9500                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.step);
9501                 };
9502                 scope.minus = function () {
9503                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.step);
9504                 };
9505                 scope.pagePlus = function () {
9506                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) + scope.pageStep);
9507                 };
9508                 scope.pageMinus = function () {
9509                     scope.inputValue[scope.inputModelKey] = scope.getValidateInputValue(parseInt(scope.inputValue[scope.inputModelKey], 10) - scope.pageStep);
9510                 };
9511
9512             }],
9513             link: function (scope, elem) {
9514
9515                 if (scope.notMobile) {
9516                     angular.element(elem).find('input').attr('aria-live', 'off');
9517                     angular.element(elem).find('input').attr('role', 'spinbutton');
9518                 }
9519
9520                 elem.find('input').bind('keydown', function (e) {
9521                     if (e.keyCode === keymap.KEY.UP) {
9522                         scope.plus();
9523                     } else if (e.keyCode === keymap.KEY.DOWN){
9524                         scope.minus();
9525                     } else if (e.keyCode === keymap.KEY.HOME) {
9526                         scope.inputValue[scope.inputModelKey] = parseInt(scope.min);
9527                     } else if (e.keyCode === keymap.KEY.END) {
9528                         scope.inputValue[scope.inputModelKey] = parseInt(scope.max);
9529                     } else if (e.keyCode === keymap.KEY.PAGE_UP) {
9530                         scope.pagePlus();
9531                     } else if (e.keyCode === keymap.KEY.PAGE_DOWN) {
9532                         scope.pageMinus();
9533                     }
9534                     scope.$apply();
9535                 });
9536
9537                 elem.find('input').bind('keyup', function () {
9538                     if (scope.inputValue[scope.inputModelKey] === null ||
9539                         scope.inputValue[scope.inputModelKey] === '' ||
9540                         scope.inputValue[scope.inputModelKey] < scope.min) {
9541                         scope.inputValue[scope.inputModelKey] = scope.min;
9542                         scope.$apply();
9543                     } else if (angular.isUndefined(scope.inputValue[scope.inputModelKey]) || 
9544                                scope.inputValue[scope.inputModelKey] > scope.max) {
9545                         scope.inputValue[scope.inputModelKey] = scope.max;
9546                         scope.$apply();
9547                     }
9548                 });
9549
9550                 scope.focusInputSpinButton = function (evt) {
9551                     evt.preventDefault();
9552                     if (scope.notMobile) {
9553                         elem[0].querySelector('input').focus();
9554                     }
9555                 };
9556
9557             }
9558         };  
9559     }]);
9560 /** 
9561  * @ngdoc directive 
9562  * @name Template.att:Static Route
9563  * 
9564  * @description 
9565  *  <file src="src/staticRouteTemplate/docs/readme.md" /> 
9566  * 
9567  * @example 
9568  *  <section id="code"> 
9569         <example module="b2b.att"> 
9570             <file src="src/staticRouteTemplate/docs/demo.html" /> 
9571             <file src="src/staticRouteTemplate/docs/demo.js" /> 
9572        </example> 
9573     </section>    
9574  * 
9575  */
9576 angular.module('b2b.att.staticRouteTemplate', ['b2b.att.utilities'])
9577   
9578 /**
9579  * @ngdoc directive
9580  * @name Progress & usage indicators.att:statusTracker
9581  *
9582  * @scope
9583  * @param {array} statusObject - An array of status objects that accept heading, estimate, description and state
9584  * @description
9585  * <file src="src/statusTracker/docs/readme.md" />
9586  *
9587  * @usage
9588  *
9589 <div ng-controller="statusTrackerController">
9590     <b2b-status-tracker statuses="statusObject"></b2b-status-tracker>
9591 </div>
9592
9593  * @example
9594     <section id="code">   
9595         <example module="b2b.att">
9596             <file src="src/statusTracker/docs/demo.html" />
9597             <file src="src/statusTracker/docs/demo.js" />
9598         </example>
9599     </section>
9600  */
9601
9602 angular.module('b2b.att.statusTracker', ['b2b.att.utilities'])
9603 .constant('b2bStatusTrackerConfig', {
9604     'maxViewItems': 3,
9605     'icons': {
9606         'complete': 'icoControls-approval',
9607         'current': 'icon-misc-time',
9608         'pending': 'icoControls-statusokay',
9609         'actionRequired': 'icon-primary-securityalerts-alert',
9610         'notAvailable': 'icoControls-restricted'
9611     }
9612 })
9613 .directive('b2bStatusTracker', ['b2bStatusTrackerConfig', function(b2bStatusTrackerConfig) {
9614         return {
9615             restrict: 'EA',
9616             transclude: false,
9617             replace: true,
9618             scope:{
9619                 statuses: '='
9620             },
9621             templateUrl: function(scope) {
9622                 return 'b2bTemplate/statusTracker/statusTracker.html';
9623             },
9624             link: function(scope, element, attr) {
9625                 scope.currentViewIndex = 0;
9626                 scope.b2bStatusTrackerConfig = b2bStatusTrackerConfig;
9627
9628                 scope.nextStatus = function() {
9629                     if (scope.currentViewIndex+1 <= scope.statuses.length) {
9630                         scope.currentViewIndex++;
9631                     }
9632                 };
9633                 scope.previousStatus = function() {
9634                     if (scope.currentViewIndex-1 >= 0) {
9635                         scope.currentViewIndex--;
9636                     }
9637                 };
9638                 scope.isInViewport = function(index) {
9639                     return (index < scope.currentViewIndex+3 && index >= scope.currentViewIndex);  // && index > scope.currentViewIndex-2
9640                 };
9641
9642                 scope.removeCamelCase = function(str) {
9643                     return str.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase();
9644                 }
9645             }
9646         };
9647     }]);
9648 /**
9649  * @ngdoc directive
9650  * @name Progress & usage indicators.att:stepTracker
9651  *
9652  * @scope
9653  * @param {array} stepsItemsObject - An array of step objects
9654  * @param {Integer} currenIindex - This indicates the current running step
9655  * @param {Integer} viewportIndex - This is optional. This can used to start the view port rather than 1 item.
9656  * @description
9657  * <file src="src/stepTracker/docs/readme.md" />
9658  *
9659  * @usage
9660  *
9661  *      <b2b-step-tracker steps-items-object="stepsObject" current-index="currentStepIndex" step-indicator-heading="stepHeading"></b2b-step-tracker>
9662  *
9663
9664  * @example
9665     <section id="code">   
9666         <b>HTML + AngularJS</b>
9667         <example module="b2b.att">
9668             <file src="src/stepTracker/docs/demo.html" />
9669             <file src="src/stepTracker/docs/demo.js" />
9670         </example>
9671     </section>
9672  */
9673 angular.module('b2b.att.stepTracker', ['b2b.att.utilities'])
9674         .constant('b2bStepTrackerConfig', {
9675                 'maxViewItems': 5
9676         })
9677         .directive('b2bStepTracker', ['b2bStepTrackerConfig', function(b2bStepTrackerConfig) {
9678                 return {
9679                         restrict: 'EA',
9680                         transclude: true,
9681                         scope:{
9682                                 stepsItemsObject:"=",
9683                                 currentIndex:"=",
9684                 viewportIndex:"=?"
9685                         },
9686                         templateUrl: 'b2bTemplate/stepTracker/stepTracker.html',
9687                         link: function(scope, ele, attr) {
9688                 if (angular.isDefined(scope.viewportIndex)) {
9689                     scope.currentViewIndex = scope.viewportIndex - 1;   
9690                 }else{
9691                     scope.currentViewIndex = 0;
9692                 }
9693                            
9694                            scope.b2bStepTrackerConfig = b2bStepTrackerConfig;
9695                            scope.nextStatus = function() {
9696                                         if (scope.currentViewIndex+1 <= scope.stepsItemsObject.length) {
9697                                                 scope.currentViewIndex++;
9698                                         }
9699                                 };
9700                                 scope.previousStatus = function() {
9701                                         if (scope.currentViewIndex-1 >= 0) {
9702                                                 scope.currentViewIndex--;
9703                                         }
9704                                 };
9705                                 scope.isInViewport = function(index) {
9706                                         return (index < scope.currentViewIndex+b2bStepTrackerConfig.maxViewItems && index >= scope.currentViewIndex);
9707                                 };
9708                         }
9709                 };
9710         }]);
9711      
9712 /**
9713  * @ngdoc directive
9714  * @name Buttons, links & UI controls.att:switches
9715  *
9716  * @description
9717  *  <file src="src/switches/docs/readme.md" />
9718  *
9719  * @usage
9720  *  
9721  *  <!-- On / Off Toggle switch -->
9722  *  <label for="switch1" class="controlled-text-wrap"> This is ON
9723  *      <input type="checkbox" role="checkbox" b2b-switches id="switch1" ng-model="switch1.value">
9724  *  </label>
9725  *
9726  *  <!-- On / Off Toggle switch and DISABLED -->
9727  *  <label for="switch2" class="controlled-text-wrap"> This is ON (disabled)
9728  *      <input type="checkbox" role="checkbox" b2b-switches id="switch2" ng-model="switch1.value" ng-disabled="true" >
9729  *  </label> 
9730  *
9731  *
9732  * @example
9733  *  <section id="code">
9734         <b>HTML + AngularJS</b>
9735         <example module="b2b.att">
9736             <file src="src/switches/docs/demo.js" />
9737             <file src="src/switches/docs/demo.html" />
9738         </example>
9739     </section>
9740  */
9741 angular.module('b2b.att.switches', ['b2b.att.utilities'])
9742     .directive('b2bSwitches', ['$compile', '$templateCache', 'keymap', 'events', function ($compile, $templateCache, keymap, events) {
9743         return {
9744             restrict: 'EA',
9745             require: ['ngModel'],
9746             link: function (scope, element, attrs, ctrl) {
9747                 var ngModelController = ctrl[0];
9748         
9749                 element.parent().bind("keydown", function (e) {
9750                     if (!attrs.disabled && (e.keyCode === keymap.KEY.ENTER || e.keyCode === keymap.KEY.SPACE)) {
9751                         events.preventDefault(e);
9752                         ngModelController.$setViewValue(!ngModelController.$viewValue);
9753                         element.prop("checked", ngModelController.$viewValue);
9754                     }
9755                 });
9756
9757                 element.wrap('<div class="btn-switch">');
9758                 //element.attr("tabindex", -1);
9759                 if (navigator.userAgent.match(/iphone/i)){
9760                     element.attr("aria-live", "polite");
9761                 }
9762                 else {
9763                     element.removeAttr('aria-live');
9764                 }
9765
9766                 var templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches.html"));
9767                 if (angular.isDefined(attrs.typeSpanish)) {
9768                     templateSwitch = angular.element($templateCache.get("b2bTemplate/switches/switches-spanish.html"));
9769                 }
9770
9771                 templateSwitch = $compile(templateSwitch)(scope);
9772                 element.parent().append(templateSwitch);
9773
9774                 element.bind("focus", function (e) {
9775                     element.parent().addClass('focused');
9776                 });
9777
9778                 element.bind("blur", function (e) {
9779                     element.parent().removeClass('focused');
9780                 });
9781             }
9782         };
9783     }]);
9784 /** 
9785  * @ngdoc directive 
9786  * @name Template.att:Table with Drag and Drop
9787  * 
9788  * @description 
9789  *  <file src="src/tableDragAndDrop/docs/readme.md" /> 
9790  * 
9791  * @example 
9792  *  <section id="code"> 
9793         <example module="b2b.att"> 
9794             <file src="src/tableDragAndDrop/docs/demo.html" /> 
9795             <file src="src/tableDragAndDrop/docs/demo.js" /> 
9796        </example> 
9797     </section>    
9798  * 
9799  */
9800 angular.module('b2b.att.tableDragAndDrop', ['b2b.att.utilities','b2b.att.tables'])
9801   
9802 /**
9803  * @ngdoc directive
9804  * @name Messages, modals & alerts.att:tableMessages
9805  *
9806  * @description
9807  *  <file src="src/tableMessages/docs/readme.md" />
9808  *
9809  * @usage
9810     <!-- no matching results -->
9811     <b2b-table-message msg-type="'noMatchingResults'">
9812        <p>No Matching Results</p>
9813     </b2b-table-message>
9814   
9815     <!-- info could not load -->
9816     <b2b-table-message msg-type="'infoCouldNotLoad'" on-refresh-click="refreshClicked()">
9817     </b2b-table-message>
9818    
9819     <!-- magnify search -->
9820     <b2b-table-message msg-type="'magnifySearch'">
9821     </b2b-table-message>
9822    
9823     <!-- loading data -->
9824     <b2b-table-message msg-type="'loadingTable'">
9825           <!-- custom html -->
9826           <p>The data is currently loading...</p>
9827     </b2b-table-message>
9828
9829  * @example
9830     <section id="code">   
9831         <b>HTML + AngularJS</b>
9832         <example module="b2b.att">
9833             <file src="src/tableMessages/docs/demo.html" />
9834             <file src="src/tableMessages/docs/demo.js" />
9835         </example>
9836     </section>
9837  */
9838 angular.module('b2b.att.tableMessages', [])
9839     .directive('b2bTableMessage', [function() {
9840         return {
9841             restrict: 'AE',
9842             replace: true,
9843             transclude: true,
9844             scope: {
9845                 msgType: '=',
9846                 onRefreshClick: '&'
9847             },
9848             templateUrl: 'b2bTemplate/tableMessages/tableMessage.html',
9849             link: function(scope) {
9850                 scope.refreshAction = function(evt) {
9851                     scope.onRefreshClick(evt);
9852                 };
9853             }
9854         };
9855     }]);
9856
9857 /**
9858  * @ngdoc directive
9859  * @name Tabs, tables & accordions.att:tableScrollbar
9860  *
9861  * @description
9862  *  <file src="src/tableScrollbar/docs/readme.md" />
9863  *
9864  * @usage
9865  * 
9866 <b2b-table-scrollbar>
9867     <table>
9868         <thead type="header">
9869             <tr>
9870                 <th role="columnheader" scope="col" key="Id" id="col1">Id</th>
9871                 .....
9872             </tr>
9873         </thead>
9874         <tbody type="body">
9875             <tr>
9876                 <td id="rowheader0" headers="col1">1002</td>
9877                 .....
9878             </tr>
9879         </tbody>
9880     </table>
9881 </b2b-table-scrollbar>
9882  *
9883  * @example
9884  *  <section id="code">
9885         <example module="b2b.att">
9886             <file src="src/tableScrollbar/docs/demo.html" />
9887             <file src="src/tableScrollbar/docs/demo.js" />
9888        </example>
9889     </section>
9890  *
9891  */
9892 angular.module('b2b.att.tableScrollbar', [])
9893     .directive('b2bTableScrollbar', ['$timeout', function ($timeout) {
9894         return {
9895             restrict: 'E',
9896             scope: true,
9897             transclude: true,
9898             templateUrl: 'b2bTemplate/tableScrollbar/tableScrollbar.html',
9899             link: function (scope, element, attrs, ctrl) {
9900                 var firstThWidth, firstTdWidth, firstColumnWidth, firstColumnHeight, trHeight = 0;
9901                 var pxToScroll = '';
9902                 var tableElement = element.find('table');
9903                 var thElements = element.find('th');
9904                 var tdElements = element.find('td');
9905                 var innerContainer = angular.element(element[0].querySelector('.b2b-table-inner-container'));
9906                 var outerContainer = angular.element(element[0].querySelector('.b2b-table-scrollbar'));
9907
9908                 scope.disableLeft = true;
9909                 scope.disableRight = false;
9910
9911                 if (angular.isDefined(thElements[0])) {
9912                     firstThWidth = thElements[0].offsetWidth;
9913                 }
9914                 if (angular.isDefined(tdElements[0])) {
9915                     firstTdWidth = tdElements[0].offsetWidth;
9916                 }
9917                 firstColumnWidth = (firstThWidth > firstTdWidth) ? firstThWidth : firstTdWidth;
9918
9919                 innerContainer.css({
9920                     'padding-left': (firstColumnWidth + 2) + 'px'
9921                 });
9922
9923                 angular.forEach(element.find('tr'), function (eachTr, index) {
9924                     trObject = angular.element(eachTr);
9925                     firstColumn = angular.element(trObject.children()[0]);
9926
9927                     angular.element(firstColumn).css({
9928                         'left': '0px',
9929                         'width': (firstColumnWidth + 2) + 'px',
9930                         'position': 'absolute'
9931                     });
9932
9933                     trHeight = trObject[0].offsetHeight;
9934                     firstColumnHeight = firstColumn[0].offsetHeight;
9935                     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
9936                         firstColumnHeight += 1;
9937                     }
9938
9939                     if (trHeight !== firstColumnHeight - 1) {
9940                         if (trHeight > firstColumnHeight) {
9941                             if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
9942                                 trHeight -= 1;
9943                             }
9944                             angular.element(firstColumn).css({
9945                                 'height': (trHeight + 1) + 'px'
9946                             });
9947                         } else {
9948                             angular.element(trObject).css({
9949                                 'height': (firstColumnHeight - 1) + 'px'
9950                             });
9951                         }
9952                     }
9953
9954                 });
9955
9956                 pxToScroll = outerContainer[0].offsetWidth - firstColumnWidth;
9957
9958                 scope.scrollLeft = function () {
9959                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + 20 - pxToScroll;
9960                 };
9961
9962                 scope.scrollRight = function () {
9963                     innerContainer[0].scrollLeft = innerContainer[0].scrollLeft + pxToScroll - 20;
9964                 };
9965
9966                 scope.checkScrollArrows = function () {
9967                     if (innerContainer[0].scrollLeft == 0) {
9968                         scope.disableLeft = true;
9969                     } else {
9970                         scope.disableLeft = false;
9971                     }
9972
9973                     if (((innerContainer[0].offsetWidth - firstColumnWidth) + innerContainer[0].scrollLeft) >= tableElement[0].offsetWidth) {
9974                         scope.disableRight = true;
9975                     } else {
9976                         scope.disableRight = false;
9977                     }
9978                 };
9979
9980
9981                 innerContainer.bind('scroll', function () {
9982                     $timeout(function () {
9983                         scope.checkScrollArrows();
9984                     }, 1);
9985                 });
9986
9987             }
9988         };
9989     }]);
9990 /**
9991  * @ngdoc directive
9992  * @name Tabs, tables & accordions.att:tables
9993  *
9994  * @description
9995  *  <file src="src/tables/docs/readme.md" />
9996  *
9997  * @usage
9998  *   
9999  Table
10000  <table b2b-table table-data="tableData" search-string="searchString">
10001     <thead b2b-table-row type="header">
10002         <tr>
10003             <th b2b-table-header key="requestId" default-sort="a" id="col1">Header 1</th>
10004             <th b2b-table-header key="requestType" sortable="false" id="col2">Header 2</th>
10005         </tr>
10006     </thead>
10007     <tbody b2b-table-row type="body" row-repeat="rowData in tableData">
10008         <tr>
10009             <td b2b-table-body id="rowheader{{$index}}" headers="col1" ng-bind="rowData['requestId']"> </td>
10010             <td b2b-table-body ng-bind="rowData['requestType']"></td>
10011         </tr>
10012     </tbody>
10013  </table>
10014  *
10015  * @example
10016  *  <section id="code">
10017         <example module="b2b.att">
10018             <file src="src/tables/docs/demo.html" />
10019             <file src="src/tables/docs/demo.js" />
10020        </example>
10021     </section>
10022  *
10023  */
10024 angular.module('b2b.att.tables', ['b2b.att.utilities'])
10025     .constant('b2bTableConfig', {
10026         defaultSortPattern: false, // true for descending & false for ascending
10027         highlightSearchStringClass: 'tablesorter-search-highlight',
10028         zebraStripCutOff: 6, // > zebraStripCutOff
10029         tableBreakpoints: [ // breakpoints are >= min and < max
10030             {
10031                 min: 0,
10032                 max: 480,
10033                 columns: 2
10034             },
10035             {
10036                 min: 480,
10037                 max: 768,
10038                 columns: 3
10039             },
10040             {
10041                 min: 768,
10042                 max: 1025,
10043                 columns: 5
10044             },
10045             {
10046                 min: 1025,
10047                 max: 1920,
10048                 columns: 7
10049             }
10050         ]
10051     })
10052     .directive('b2bTable', ['$filter', '$window', 'b2bTableConfig', '$timeout', function ($filter, $window, b2bTableConfig, $timeout) {
10053         return {
10054             restrict: 'EA',
10055             replace: true,
10056             transclude: true,
10057             scope: {
10058                 tableData: "=",
10059                 viewPerPage: "=",
10060                 currentPage: "=",
10061                 totalPage: "=",
10062                 searchCategory: "=",
10063                 searchString: "=",
10064                 nextSort: '='
10065             },
10066             require: 'b2bTable',
10067             templateUrl: 'b2bTemplate/tables/b2bTable.html',
10068             controller: ['$scope', '$attrs', function ($scope, $attrs) {
10069                 this.headers = [];
10070                 this.currentSortIndex = null;
10071                 this.responsive = $scope.responsive = $attrs.responsive;
10072                 this.maxTableColumns = -1;
10073                 this.totalTableColums = 0;
10074                 this.active = $scope.active = false;
10075                 this.responsiveRowScopes = [];
10076                 this.hideColumnPriority = [];
10077                 this.hiddenColumn = [];
10078                 this.setIndex = function (headerScope, priority) {
10079                     this.headers.push(headerScope);
10080                     if (this.responsive) {
10081                         this.totalTableColums++;
10082                         if (!isNaN(priority)) {
10083                             this.hideColumnPriority[priority] = this.totalTableColums - 1;
10084                         } else {
10085                             this.hideColumnPriority[this.totalTableColums - 1] = this.totalTableColums - 1;
10086                         }
10087                     }
10088                     return this.totalTableColums - 1;
10089                 };
10090                 this.getIndex = function (headerName) {
10091                     for (var i = 0; i < this.headers.length; i++) {
10092                         if (this.headers[i].headerName === headerName) {
10093                             return this.headers[i].index;
10094                         }
10095                     }
10096                     return null;
10097                 };
10098                 this.setResponsiveRow = function (responsiveRowScope) {
10099                     this.responsiveRowScopes.push(responsiveRowScope);
10100                 }
10101                 $scope.nextSort = '';
10102                 this.sortData = function (columnIndex, reverse, externalSort) {
10103                     if ($scope.$parent && $scope.$parent !== undefined) {
10104                         $scope.$parent.columnIndex = columnIndex;
10105                         $scope.$parent.reverse = reverse;
10106                     }
10107                     this.currentSortIndex = columnIndex;
10108                     if (externalSort === true) {
10109                         if (!reverse) {
10110                             $scope.nextSort = 'd'
10111                         } else {
10112                             $scope.nextSort = 'a'
10113                         }
10114                     }
10115                     $scope.currentPage = 1;
10116                     this.resetSortPattern();
10117                 };
10118                 this.getSearchString = function () {
10119                     return $scope.searchString;
10120                 };
10121                 this.resetSortPattern = function () {
10122                     for (var i = 0; i < this.headers.length; i++) {
10123                         var currentScope = this.headers[i];
10124                         if (currentScope.index !== this.currentSortIndex) {
10125                             currentScope.resetSortPattern();
10126                         }
10127                     }
10128                 };
10129
10130                 $scope.$watch('nextSort', function (val) {
10131                     if ($scope.$parent && $scope.$parent !== undefined) {
10132                         $scope.$parent.nextSort = val;
10133                     }
10134
10135                 });
10136             }],
10137             link: function (scope, elem, attr, ctrl) {
10138                 scope.searchCriteria = {};
10139                 scope.tableBreakpoints = attr.tableConfig ? scope.$parent.$eval(attr.tableConfig) : angular.copy(b2bTableConfig.tableBreakpoints);
10140                 scope.$watchCollection('tableData', function (value) {
10141                     if (value && !isNaN(value.length)) {
10142                         scope.totalRows = value.length;
10143                     }
10144                 });
10145                 scope.$watch('currentPage', function (val) {
10146                     if (scope.$parent && scope.$parent !== undefined) {
10147                         scope.$parent.currentPage = val;
10148                     }
10149
10150                 });
10151                 scope.$watch('viewPerPage', function (val) {
10152                     if (scope.$parent && scope.$parent !== undefined) {
10153                         scope.$parent.viewPerPage = val;
10154                     }
10155                 });
10156                 scope.$watch('totalRows', function (val) {
10157                     if (scope.$parent && scope.$parent !== undefined) {
10158                         if (val > b2bTableConfig.zebraStripCutOff) {
10159                             scope.$parent.zebraStripFlag = true;
10160                         } else {
10161                             scope.$parent.zebraStripFlag = false;
10162                         }
10163                     }
10164                 });
10165                 scope.$watch(function () {
10166                     return scope.totalRows / scope.viewPerPage;
10167                 }, function (value) {
10168                     if (!isNaN(value)) {
10169                         scope.totalPage = Math.ceil(value);
10170                         scope.currentPage = 1;
10171                     }
10172                 });
10173                 var searchValCheck = function (val) {
10174                     if (angular.isDefined(val) && val !== null && val !== "") {
10175                         return true;
10176                     }
10177                 };
10178                 var setSearchCriteria = function (v1, v2) {
10179                     if (searchValCheck(v1) && searchValCheck(v2)) {
10180                         var index = ctrl.getIndex(v2);
10181                         scope.searchCriteria = {};
10182                         if (index !== null) {
10183                             scope.searchCriteria[index] = v1;
10184                         }
10185                     } else if (searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")) {
10186                         scope.searchCriteria = {
10187                             $: v1
10188                         };
10189                     } else {
10190                         scope.searchCriteria = {};
10191                     }
10192                 };
10193                 scope.$watch('searchCategory', function (newVal, oldVal) {
10194                     if (newVal !== oldVal) {
10195                         setSearchCriteria(scope.searchString, newVal);
10196                     }
10197                 });
10198                 scope.$watch('searchString', function (newVal, oldVal) {
10199                     if (newVal !== oldVal) {
10200                         setSearchCriteria(newVal, scope.searchCategory);
10201                     }
10202                 });
10203                 scope.$watchCollection('searchCriteria', function (val) {
10204                     if (scope.$parent && scope.$parent !== undefined) {
10205                         scope.$parent.searchCriteria = val;
10206                     }
10207                     scope.totalRows = scope.tableData && ($filter('filter')(scope.tableData, val, false)).length || 0;
10208                     scope.currentPage = 1;
10209                 });
10210                 var window = angular.element($window);
10211                 var findMaxTableColumns = function () {
10212                     var windowWidth;
10213                     windowWidth = $window.innerWidth;
10214                     ctrl.maxTableColumns = -1;
10215                     for (var i in scope.tableBreakpoints) {
10216                         if (windowWidth >= scope.tableBreakpoints[i].min && windowWidth < scope.tableBreakpoints[i].max) {
10217                             ctrl.maxTableColumns = scope.tableBreakpoints[i].columns;
10218                             break;
10219                         }
10220                     }
10221                     if (ctrl.maxTableColumns > -1 && ctrl.totalTableColums > ctrl.maxTableColumns) {
10222                         ctrl.active = true;
10223                     } else {
10224                         ctrl.active = false;
10225                     }
10226                     for (var i in ctrl.responsiveRowScopes) {
10227                         ctrl.responsiveRowScopes[i].setActive(ctrl.active);
10228                     }
10229                 };
10230                 var findHiddenColumn = function () {
10231                     var columnDiffenence = ctrl.maxTableColumns > -1 ? ctrl.totalTableColums - ctrl.maxTableColumns : 0;
10232                     ctrl.hiddenColumn = [];
10233                     if (columnDiffenence > 0) {
10234                         var tempHideColumnPriority = angular.copy(ctrl.hideColumnPriority);
10235                         for (var i = 0; i < columnDiffenence; i++) {
10236                             ctrl.hiddenColumn.push(tempHideColumnPriority.pop());
10237                         }
10238                     }
10239                 };
10240                 var resizeListener = function () {
10241                     findMaxTableColumns();
10242                     findHiddenColumn();
10243                 };
10244                 if (ctrl.responsive) {
10245                     window.bind('resize', function () {
10246                         resizeListener();
10247                         scope.$apply();
10248                     });
10249                     $timeout(function () {
10250                         resizeListener();
10251                     }, 100);
10252                 }
10253             }
10254         };
10255     }])
10256     .directive('b2bTableRow', [function () {
10257         return {
10258             restrict: 'EA',
10259             compile: function (elem, attr) {
10260                 if (attr.type === 'header') {
10261                     angular.noop();
10262                 } else if (attr.type === 'body') {
10263                     var html = elem.children();
10264                     if (attr.rowRepeat) {
10265                         html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : (reverse?'-':'')+ columnIndex  | filter : searchCriteria : false "));
10266                     }
10267                     html.attr('ng-class', "{'odd': $odd && zebraStripFlag}");
10268                     html.attr('class', 'data-row');
10269                     html.attr('b2b-responsive-row', '{{$index}}');
10270                     elem.append(html);
10271                 }
10272             }
10273         };
10274     }])
10275     .directive('b2bTableHeader', ['b2bTableConfig', function (b2bTableConfig) {
10276         return {
10277             restrict: 'EA',
10278             replace: true,
10279             transclude: true,
10280             scope: {
10281                 sortable: '@',
10282                 defaultSort: '@',
10283                 index: '@key'
10284             },
10285             require: '^b2bTable',
10286             templateUrl: function (elem, attr) {
10287                 if (attr.sortable === 'false') {
10288                     return 'b2bTemplate/tables/b2bTableHeaderUnsortable.html';
10289                 } else {
10290                     return 'b2bTemplate/tables/b2bTableHeaderSortable.html';
10291                 }
10292             },
10293             link: function (scope, elem, attr, ctrl) {
10294                 var reverse = b2bTableConfig.defaultSortPattern;
10295                 scope.headerName = elem.text();
10296                 scope.headerId = elem.attr('id');
10297                 scope.sortPattern = null;
10298                 var priority = parseInt(attr.priority, 10);
10299                 scope.columnIndex = ctrl.setIndex(scope, priority);
10300
10301                 scope.isHidden = function () {
10302                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10303                 };
10304
10305                 scope.$watch(function () {
10306                     return elem.text();
10307                 }, function (value) {
10308                     scope.headerName = value;
10309                 });
10310                 scope.sort = function (sortType) {
10311                     if (typeof sortType === 'boolean') {
10312                         reverse = sortType;
10313                     }
10314                     ctrl.sortData(scope.index, reverse, false);
10315                     scope.sortPattern = reverse ? 'descending' : 'ascending';
10316                     reverse = !reverse;
10317                 };
10318                 scope.$watch(function () {
10319                     return ctrl.currentSortIndex;
10320                 }, function (value) {
10321                     if (value !== scope.index) {
10322                         scope.sortPattern = null;
10323                     }
10324                 });
10325
10326                 if (scope.sortable === undefined || scope.sortable === 'true' || scope.sortable === true) {
10327                     scope.sortable = 'true';
10328                 } else if (scope.sortable === false || scope.sortable === 'false') {
10329                     scope.sortable = 'false';
10330                 }
10331
10332                 if (scope.sortable !== 'false') {
10333                     if (scope.defaultSort === 'A' || scope.defaultSort === 'a') {
10334                         scope.sort(false);
10335                     } else if (scope.defaultSort === 'D' || scope.defaultSort === 'd') {
10336                         scope.sort(true);
10337                     }
10338                 }
10339                 scope.resetSortPattern = function () {
10340                     reverse = b2bTableConfig.defaultSortPattern;
10341                 };
10342             }
10343         };
10344     }])
10345     .directive('b2bResponsiveRow', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {
10346         return {
10347             restrict: 'EA',
10348             require: '^b2bTable',
10349             controller: ['$scope', function ($scope) {
10350                 this.rowValues = $scope.rowValues = [];
10351                 this.setRowValues = function (rowValue) {
10352                     this.rowValues.push(rowValue);
10353                 };
10354                 var columnIndexCounter = -1;
10355                 this.getIndex = function () {
10356                     columnIndexCounter++;
10357                     return columnIndexCounter;
10358                 };
10359             }],
10360             link: function (scope, elem, attr, ctrl) {
10361                 if (ctrl.responsive) {
10362                     scope.rowIndex = attr.b2bResponsiveRow;
10363                     scope.active = false;
10364                     scope.expandFlag = false;
10365                     scope.headerValues = ctrl.headers;
10366                     ctrl.setResponsiveRow(scope);
10367                     var firstTd = elem.find('td').eq(0);
10368                     scope.setActive = function (activeFlag) {
10369                         scope.active = activeFlag;
10370                         if (scope.active) {
10371                             elem.addClass('has-button');
10372                             firstTd.attr('role', 'rowheader');
10373                             firstTd.parent().attr('role', 'row');
10374                         } else {
10375                             elem.removeClass('has-button');
10376                             firstTd.removeAttr('role');
10377                             firstTd.parent().removeAttr('role');
10378                         }
10379                     };
10380                     scope.toggleExpandFlag = function (expandFlag) {
10381                         if (angular.isDefined(expandFlag)) {
10382                             scope.expandFlag = expandFlag;
10383                         } else {
10384                             scope.expandFlag = !scope.expandFlag;
10385                         }
10386                         if (scope.expandFlag) {
10387                             elem.addClass('opened');
10388                         } else {
10389                             elem.removeClass('opened');
10390                         }
10391                     };
10392
10393                     firstTd.attr('scope', 'row');
10394                     firstTd.addClass('col-1');
10395                     scope.$on('$destroy', function () {
10396                         elem.next().remove();
10397                     });
10398                     $timeout(function () {
10399                         scope.firstTdId = firstTd.attr('id');
10400                         var firstTdContent = firstTd.html();
10401                         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>';
10402                         toggleButtonTemplate = $compile(toggleButtonTemplate)(scope);
10403                         firstTd.html('');
10404                         firstTd.prepend(toggleButtonTemplate);
10405
10406                         var template = $templateCache.get('b2bTemplate/tables/b2bResponsiveRow.html');
10407                         template = $compile(template)(scope);
10408                         elem.after(template);
10409                     }, 100);
10410                 }
10411             }
10412         };
10413     }])
10414     .directive('b2bResponsiveList', ['$templateCache', '$timeout', '$compile', function ($templateCache, $timeout, $compile) {
10415         return {
10416             restrict: 'EA',
10417             require: '^b2bTable',
10418             link: function (scope, elem, attr, ctrl) {
10419                 scope.columnIndex = parseInt(attr.b2bResponsiveList, 10);
10420                 scope.isVisible = function () {
10421                     return (ctrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10422                 };
10423             }
10424         };
10425     }])
10426     .directive('b2bTableBody', ['$filter', '$timeout', 'b2bTableConfig', function ($filter, $timeout, b2bTableConfig) {
10427         return {
10428             restrict: 'EA',
10429             require: ['^b2bTable', '?^b2bResponsiveRow'],
10430             scope: true,
10431             replace: true,
10432             transclude: true,
10433             templateUrl: 'b2bTemplate/tables/b2bTableBody.html',
10434             link: function (scope, elem, attr, ctrl) {
10435                 var b2bTableCtrl = ctrl[0];
10436                 var b2bResponsiveRowCtrl = ctrl[1];
10437                 var highlightSearchStringClass = b2bTableConfig.highlightSearchStringClass;
10438                 var searchString = "";
10439                 var wrapElement = function (elem) {
10440                     var text = elem.text();
10441                     elem.html($filter('b2bHighlight')(text, searchString, highlightSearchStringClass));
10442                 };
10443                 var traverse = function (elem) {
10444                     var innerHtml = elem.children();
10445                     if (innerHtml.length > 0) {
10446                         for (var i = 0; i < innerHtml.length; i++) {
10447                             traverse(innerHtml.eq(i));
10448                         }
10449                     } else {
10450                         wrapElement(elem);
10451                         return;
10452                     }
10453                 };
10454                 var clearWrap = function (elem) {
10455                     var elems = elem.find('*');
10456                     for (var i = 0; i < elems.length; i++) {
10457                         if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {
10458                             var text = elems.eq(i).text();
10459                             elems.eq(i).replaceWith(text);
10460                         }
10461                     }
10462                 };
10463                 if (b2bResponsiveRowCtrl) {
10464                     scope.columnIndex = b2bResponsiveRowCtrl.getIndex();
10465                     scope.isHidden = function () {
10466                         return (b2bTableCtrl.hiddenColumn.indexOf(scope.columnIndex) > -1);
10467                     };
10468                 }
10469                 $timeout(function () {
10470                     var actualHtml = elem.children();
10471                     scope.$watch(function () {
10472                         return b2bTableCtrl.getSearchString();
10473                     }, function (val) {
10474                         searchString = val;
10475                         clearWrap(elem);
10476                         if (actualHtml.length > 0) {
10477                             traverse(elem);
10478                         } else {
10479                             wrapElement(elem);
10480                         }
10481                     });
10482                     if (b2bResponsiveRowCtrl) {
10483                         b2bResponsiveRowCtrl.setRowValues(elem.html());
10484                     }
10485                 }, 50);
10486             }
10487         };
10488     }])
10489     .directive('b2bTableSort', ['b2bTableConfig','$timeout', function (b2bTableConfig,$timeout) {
10490         return {
10491             restrict: 'EA',
10492             replace: true,
10493             require: '^b2bTable',
10494             link: function (scope, elem, attr, ctrl) {
10495                 var initialSort = '',
10496                     nextSort = '',
10497                     tempsort = '';
10498                 initialSort = attr.initialSort;
10499
10500                 scope.sortTable = function (msg,trigger) {
10501                     if(trigger == 'dropdown'){
10502                         if (nextSort === 'd' || nextSort === 'D') {                        
10503                          ctrl.sortData(msg, false, false);
10504                         }else{
10505                          ctrl.sortData(msg, true, false);
10506                         }
10507                         return;                        
10508                     }
10509                     $timeout(function(){
10510                         if (nextSort.length > 0) {
10511
10512                         if (nextSort === 'd' || nextSort === 'D') {
10513                             tempsort = nextSort
10514                             ctrl.sortData(msg, true, true);
10515                             nextSort = 'a';
10516                              $timeout(function(){
10517                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10518                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10519                                 }   
10520                             },100);
10521                             
10522                         } else {
10523                             tempsort = nextSort
10524                             ctrl.sortData(msg, false, true);
10525                             nextSort = 'd';
10526                              $timeout(function(){
10527                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10528                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10529                                 }   
10530                             },100);
10531                         }
10532                     } else if (initialSort.length > 0) {
10533
10534                         if (initialSort === 'd' || initialSort === 'D') {
10535                             tempsort = nextSort
10536                             ctrl.sortData(msg, true, true);
10537                             nextSort = 'a';
10538                             $timeout(function(){
10539                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10540                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10541                                 }   
10542                             },100);
10543                              
10544                         } else {
10545                             tempsort = nextSort
10546                             ctrl.sortData(msg, false, true);
10547                             nextSort = 'd';
10548                              $timeout(function(){
10549                                 if(!angular.isUndefined(elem[0].querySelector('.sortButton')) || elem[0].querySelector('.sortButton') !== null ){
10550                                     angular.element(elem[0].querySelector('.sortButton'))[0].focus();
10551                                 }   
10552                             },100);
10553
10554                              
10555                         }
10556                     }
10557                     },10)
10558
10559                 };
10560
10561                 scope.sortDropdown = function(msg) {
10562
10563                     if(tempsort==='') {
10564
10565                         tempsort='a'
10566                     }
10567                     if(tempsort === 'd' || tempsort === 'D' ) {
10568                         ctrl.sortData(msg, true, false);       
10569                     } else {
10570                        ctrl.sortData(msg, false, false);
10571                     }
10572
10573                 };
10574             }
10575         };
10576     }]);
10577 /**
10578  * @ngdoc directive
10579  * @name Tabs, tables & accordions.att:tabs
10580  *
10581  * @description
10582  *  <file src="src/tabs/docs/readme.md" />
10583  *
10584  * @usage
10585  *  <b2b-tabset tab-id-selected="activeTabsId">
10586         <b2b-tab ng-repeat="tab in gTabs" tab-item="tab" 
10587                  id="{{tab.uniqueId}}" aria-controls="{{tab.tabPanelId}}"
10588                  ng-disabled="tab.disabled">
10589             {{tab.title}}
10590         </b2b-tab>
10591     </b2b-tabset>
10592  *
10593  * @example
10594  *  <section id="code">
10595         <example module="b2b.att">
10596             <file src="src/tabs/docs/demo.html" />
10597             <file src="src/tabs/docs/demo.js" />
10598         </example>
10599     </section>
10600  *
10601  */
10602
10603 angular.module('b2b.att.tabs', ['b2b.att.utilities'])
10604     .directive('b2bTabset', function () {
10605         return {
10606             restrict: 'EA',
10607             transclude: true,
10608             replace: true,
10609             scope: {
10610                 tabIdSelected: '='
10611             },
10612             templateUrl: 'b2bTemplate/tabs/b2bTabset.html',
10613             controller: ['$scope', function ($scope) {
10614
10615                 this.setTabIdSelected = function (tab) {
10616                     $scope.tabIdSelected = tab.id;
10617                 };
10618
10619                 this.getTabIdSelected = function () {
10620                     return $scope.tabIdSelected;
10621                 };
10622             }]
10623         };
10624     })
10625     .directive('b2bTab', ['keymap', function (keymap) {
10626         return {
10627             restrict: 'EA',
10628             transclude: true,
10629             replace: true,
10630             require: '^b2bTabset',
10631             scope: {
10632                 tabItem: "="
10633             },
10634             templateUrl: 'b2bTemplate/tabs/b2bTab.html',
10635             controller: [function(){}],
10636             link: function (scope, element, attr, b2bTabsetCtrl) {
10637
10638                 if (scope.tabItem && !scope.tabItem.disabled) {
10639                     scope.tabItem.disabled = false;
10640                 }
10641
10642                 scope.isTabActive = function () {
10643                     return (scope.tabItem.id === b2bTabsetCtrl.getTabIdSelected());
10644                 };
10645
10646                 scope.clickTab = function () {
10647                     if (attr.disabled) {
10648                         return;
10649                     }
10650                     b2bTabsetCtrl.setTabIdSelected(scope.tabItem);
10651                 };
10652
10653                 scope.nextKey = function () {
10654                     var el = angular.element(element[0])[0];
10655                     var elementToFocus = null;
10656                     while (el && el.nextElementSibling) {
10657                         el = el.nextElementSibling;
10658                         if (!el.querySelector('a').disabled) {
10659                             elementToFocus = el.querySelector('a');
10660                             break;
10661                         }
10662                     }
10663
10664                     if (!elementToFocus) {
10665                         var childTabs = element.parent().children();
10666                         for (var i = 0; i < childTabs.length; i++) {
10667                             if (!childTabs[i].querySelector('a').disabled) {
10668                                 elementToFocus = childTabs[i].querySelector('a');
10669                                 break;
10670                             }
10671                         }
10672                     }
10673
10674                     if (elementToFocus) {
10675                         elementToFocus.focus();
10676                     }
10677                 };
10678
10679                 scope.previousKey = function () {
10680                     var el = angular.element(element[0])[0];
10681                     var elementToFocus = null;
10682
10683                     while (el && el.previousElementSibling) {
10684                         el = el.previousElementSibling;
10685                         if (!el.querySelector('a').disabled) {
10686                             elementToFocus = el.querySelector('a');
10687                             break;
10688                         }
10689                     }
10690
10691                     if (!elementToFocus) {
10692                         var childTabs = element.parent().children();
10693                         for (var i = childTabs.length - 1; i > 0; i--) {
10694                             if (!childTabs[i].querySelector('a').disabled) {
10695                                 elementToFocus = childTabs[i].querySelector('a');
10696                                 break;
10697                             }
10698                         }
10699                     }
10700
10701                     if (elementToFocus) {
10702                         elementToFocus.focus();
10703                     }
10704                 };
10705
10706                 angular.element(element[0].querySelector('a')).bind('keydown', function (evt) {
10707
10708                     if (!(evt.keyCode)) {
10709                         evt.keyCode = evt.which;
10710                     }
10711
10712                     switch (evt.keyCode) {
10713                         case keymap.KEY.RIGHT:
10714                             evt.preventDefault();
10715                             scope.nextKey();
10716                             break;
10717
10718                         case keymap.KEY.LEFT:
10719                             evt.preventDefault();
10720                             scope.previousKey();
10721                             break;
10722
10723                         default:;
10724                     }
10725                 });
10726             }
10727         };
10728     }]);
10729 /**
10730  * @ngdoc directive
10731  * @name Messages, modals & alerts.att:tagBadges
10732  *
10733  * @description
10734  *  <file src="src/tagBadges/docs/readme.md" />
10735  *
10736  * @example
10737  *  <section id="code">
10738         <example module="b2b.att">
10739             <file src="src/tagBadges/docs/demo.html" />
10740             <file src="src/tagBadges/docs/demo.js" />
10741         </example>
10742     </section>
10743  *
10744  */
10745 angular.module('b2b.att.tagBadges', ['b2b.att.utilities'])
10746         .directive('b2bTagBadge',['$timeout',function($timeout){
10747             return{
10748                 restrict: 'EA',
10749                 link: function(scope,elem,attr,ctrl){
10750                     elem.addClass('b2b-tags');
10751                     if(angular.element(elem[0].querySelector('.icon-primary-close')).length>0) {
10752                         var item = angular.element(elem[0].querySelector('.icon-primary-close'));
10753                         item.bind('click',function(){
10754                         elem.css({'height':'0','width':'0','padding':'0','border':'0'});
10755                         elem.attr('tabindex','0');
10756                         elem[0].focus();
10757                         item.parent().remove();
10758                         elem[0].bind('blur',function(){
10759                             elem[0].remove();
10760                         });
10761                     });  
10762                     }
10763                   
10764
10765
10766
10767                 }
10768             };   
10769 }]);
10770 /**
10771  * @ngdoc directive
10772  * @name Forms.att:textArea
10773  *
10774  * @description
10775  *  <file src="src/textArea/docs/readme.md" />
10776  *
10777  * @usage
10778  *  <textarea b2b-reset b2b-reset-textarea ng-model="textAreaModel" ng-disabled="disabled" ng-trim="false" placeholder="{{placeholderText}}" rows="{{textAreaRows}}" maxlength="{{textAreaMaxlength}}" role="textarea"></textarea>
10779  *
10780  * @example
10781     <section id="code">
10782         <b>HTML + AngularJS</b>
10783         <example module="b2b.att">
10784             <file src="src/textArea/docs/demo.html" />
10785             <file src="src/textArea/docs/demo.js" />
10786         </example>
10787     </section>
10788  */
10789 angular.module('b2b.att.textArea', ['b2b.att.utilities'])
10790
10791 .directive('b2bResetTextarea', [ function () {
10792     return {
10793         restrict: 'A',
10794         require: 'b2bReset',
10795         link: function (scope, element, attrs, ctrl) {
10796
10797             var resetButton = ctrl.getResetButton();
10798             
10799             var computeScrollbarAndAddClass = function () {
10800                 if (element.prop('scrollHeight') > element[0].clientHeight) {
10801                     element.addClass('hasScrollbar');
10802                 } else {
10803                     element.removeClass('hasScrollbar');
10804                 }
10805             };
10806             
10807             computeScrollbarAndAddClass();
10808
10809             element.on('focus keyup', function(){
10810                 computeScrollbarAndAddClass();
10811             });
10812         }
10813     };
10814 }]);
10815
10816 /**
10817  * @ngdoc directive
10818  * @name Forms.att:timeInputField
10819  *
10820  * @description
10821  *  <file src="src/timeInputField/docs/readme.md" />
10822  *
10823  
10824  * @example
10825  *  <section id="code">
10826         <example module="b2b.att">
10827             <file src="src/timeInputField/docs/demo.html" />
10828             <file src="src/timeInputField/docs/demo.js" />
10829        </example>
10830     </section>
10831  *
10832  */
10833 angular.module('b2b.att.timeInputField',['ngMessages', 'b2b.att.utilities']).directive('b2bTimeFormat',function(){
10834     return{
10835         restrict : 'A',
10836         require : '^ngModel',
10837         link : function(scope,elem,attr,ctrl){
10838             elem.on('keyup',function(evt){
10839                 var modelValue = ctrl.$modelValue;
10840                 var format = attr.b2bTimeFormat;
10841                  modelValue = modelValue.split(':');
10842                 if(format == "12"){
10843                     if(!(modelValue[0] <= 12 && modelValue[0] > 0 ) || !(modelValue[1] <= 59)){
10844                         ctrl.$setValidity('inValidTime',false);   
10845                     }else{
10846                         ctrl.$setValidity('inValidTime',true);
10847                     }
10848                 }else if(format =="24"){
10849                     if(!(modelValue[0] <= 23) || !(modelValue[1] <= 59)){
10850                         ctrl.$setValidity('inValidTime',false);
10851                     }else{
10852                         ctrl.$setValidity('inValidTime',true);
10853                     }
10854                 }                
10855                scope.$apply();
10856             });
10857         }
10858     }
10859 });
10860
10861 /**
10862  * @ngdoc directive
10863  * @name Forms.att:tooltipsForForms
10864  *
10865  * @description
10866  *  <file src="src/tooltipsForForms/docs/readme.md" />
10867  *
10868  * @example
10869  <example module="b2b.att">
10870  <file src="src/tooltipsForForms/docs/demo.html" />
10871  <file src="src/tooltipsForForms/docs/demo.js" />
10872  </example>
10873  */
10874 angular.module('b2b.att.tooltipsForForms', ['b2b.att.utilities'])
10875         .directive('b2bTooltip', ['$document', '$window', '$isElement', function ($document, $window, $isElement) {
10876                 return  {
10877                     restrict: 'A',
10878                     link: function (scope, elem, attr, ctrl) {
10879                         var icon = elem[0].querySelector('a.tooltip-element');
10880                         var btnIcon = elem[0].querySelector('.btn.tooltip-element');
10881                         var tooltipText = elem[0].querySelector('.helpertext');
10882                         var tooltipWrapper = elem[0].querySelector('.tooltip-size-control');
10883                         if (elem.hasClass('tooltip-onfocus')) {
10884                             var inputElm = angular.element(elem[0].querySelector("input"));
10885                             var textAreaElm = angular.element(elem[0].querySelector("textarea"));
10886                         }
10887                         angular.element(icon).attr({'aria-expanded': false});
10888                         angular.element(btnIcon).attr({'aria-expanded': false});
10889                         var calcTooltip = function () {
10890                             if (!elem.hasClass('tooltip active')) {
10891                                 if (elem.hasClass('tooltip-onfocus')) {
10892                                     angular.element(elem[0].querySelector("input")).triggerHandler('focusout');
10893                                 }
10894                                 if (elem.hasClass('tooltip-onclick')) {
10895                                     return false;
10896                                 }
10897                                 angular.element(icon).removeClass('active');
10898                                 angular.element(icon).attr({'aria-expanded': true});
10899                                 angular.element(icon).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
10900                                 angular.element(tooltipText).attr({'aria-hidden': false});
10901                                 elem.addClass('active');
10902
10903                                 var tooltipIconPos = angular.element(icon).prop('offsetLeft'),
10904                                         tooltipPosition = angular.element(tooltipText).prop('offsetWidth') / 2,
10905                                         tipOffset = (tooltipIconPos - 30) - tooltipPosition,
10906                                         maxRightPos = (($window.innerWidth - 72) - (tooltipPosition * 2)) - 14.5;
10907
10908                                 if ($window.innerWidth >= '768') {
10909                                     if (tipOffset < 0) {// if icon on far left side of page
10910                                         tipOffset = 15;
10911                                     }
10912                                     else if (tooltipIconPos > maxRightPos) {// if icon is far right side of page
10913                                         tipOffset = maxRightPos;
10914                                     }
10915                                     else {// if tooltip in the middle somewhere
10916                                         tipOffset = tipOffset;
10917                                     }
10918                                     angular.element(tooltipWrapper).css({left: tipOffset + 'px'});
10919                                 }
10920                             }
10921                         };
10922                         
10923                         // TOOLTIP LINK ONCLICK AND FOCUS
10924                         angular.element(icon).on('click mouseover mouseout focus blur', function (e) {
10925                             if (e.type == 'mouseover') {
10926                                 calcTooltip();
10927                             }
10928                             else if (e.type == 'mouseout' && elem.hasClass('active')) {
10929                                 if (!elem.hasClass('activeClick')) {
10930                                     angular.element(tooltipText).attr({
10931                                         'aria-hidden': true,
10932                                         'tabindex': '-1'
10933                                     });
10934                                     elem.removeClass('active');
10935                                 } else if (elem.hasClass('activeClick') && navigator.userAgent.match(/iphone/i)) {
10936                                     elem.removeClass('active activeClick');
10937                                 }
10938                             }
10939
10940                             else {
10941                                 if (elem.hasClass('activeClick')) {
10942                                     angular.element(icon).attr({'aria-expanded': false});
10943                                     angular.element(tooltipText).attr({'aria-hidden': true});
10944                                     angular.element(icon).removeAttr('aria-describedby');
10945                                     elem.removeClass('activeClick active');
10946                                     e.preventDefault();
10947                                 }
10948                                 else if (e.type == 'click') {
10949                                     elem.addClass('activeClick');
10950                                     calcTooltip();
10951                                     e.preventDefault();
10952                                 }
10953                                 else {
10954                                     angular.element(icon).on('keydown', function (e) {
10955                                         if (e.keyCode == '32') {
10956                                             (elem.hasClass('active')) ? elem.removeClass('active') : elem.addClass('value');
10957                                             angular.element(icon).triggerHandler('click');
10958                                             e.preventDefault();
10959                                         } else if (e.keyCode == '27') {
10960                                             (elem.hasClass('active')) ? elem.removeClass('active activeClick') : elem.addClass('value');
10961                                         }
10962                                     });
10963                                     e.preventDefault();
10964                                 }
10965                             }
10966                             e.preventDefault();
10967                         });
10968
10969                         // TOOLTIP BUTTON INSIDE A TEXT FIELD
10970                         angular.element(btnIcon).on('click', function (e) {
10971                             var $this = angular.element(this);
10972                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
10973                                 elem.removeClass('active');
10974                                 $this.removeClass('active');
10975                                 angular.element(tooltipText).removeAttr('aria-live');
10976                                 $this.attr({'aria-expanded': 'false'});
10977                                 $this.removeAttr('aria-describedby');
10978                             } else {
10979                                 elem.addClass('active');
10980                                 $this.addClass('active');
10981                                 $this.attr({'aria-expanded': 'true', 'aria-describedby': angular.element(tooltipText).attr('id')});
10982                                 angular.element(tooltipText).attr({'aria-live': 'polite'});
10983                             }
10984                         });
10985
10986                         angular.element(btnIcon).on('blur', function (e) {
10987                             var $this = angular.element(this);
10988                             if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
10989                                 elem.removeClass('active');
10990                                 $this.removeClass('active');
10991                                 angular.element(tooltipText).removeAttr('aria-live');
10992                                 $this.attr({'aria-expanded': 'false'});
10993                                 $this.removeAttr('aria-describedby');
10994                             }
10995                         });  
10996
10997                         angular.element(btnIcon).on('keydown', function (e) {
10998                             var $this = angular.element(this);
10999                             if (e.keyCode == '27') {
11000                                 var $this = angular.element(this);
11001                                 if ($this.hasClass('active') && elem.hasClass('tooltip-onclick')) {
11002                                     elem.removeClass('active');
11003                                     $this.removeClass('active');
11004                                     angular.element(tooltipText).removeAttr('aria-live');
11005                                     $this.attr({'aria-expanded': 'false'});
11006                                     $this.removeAttr('aria-describedby');
11007                                 }
11008                             }
11009                         });
11010
11011                         // close all tooltips if clicking something else
11012                         $document.bind('click', function (e) {
11013                             var isElement = $isElement(angular.element(e.target), elem, $document);
11014                             if (!isElement) {
11015                                 elem.removeClass('active');
11016                                 angular.element(elem[0].querySelector('.tooltip-element')).removeClass('active');
11017                                 angular.element(tooltipText).removeAttr('aria-live');
11018                                 angular.element(elem[0].querySelector('.tooltip-element')).attr({'aria-expanded': 'false'});
11019                                 angular.element(elem[0].querySelector('.tooltip-element')).removeAttr('aria-describedby');
11020                             };
11021                         });
11022
11023                         angular.element(inputElm).on('keydown', function (e) {
11024                             if (e.keyCode == '27'){
11025                                 elem.removeClass('active');
11026                                 angular.element(tooltipText).css('display', 'none');
11027                                 angular.element(tooltipText).removeAttr('aria-live');
11028
11029                                 if (angular.element(this).attr('aria-describedby') === undefined){
11030
11031                                 }
11032
11033                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){
11034
11035                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);
11036
11037                                     angular.element(this).attr('aria-describedby', describedByValue);
11038
11039                                 }
11040                                 else {
11041                                     angular.element(this).removeAttr('aria-describedby');
11042                                 }
11043                             }
11044                         });
11045
11046                         angular.element(textAreaElm).on('keydown', function (e) {
11047                             if (e.keyCode == '27'){
11048                                 elem.removeClass('active');
11049                                 angular.element(tooltipText).css('display', 'none');
11050                                 angular.element(tooltipText).removeAttr('aria-live');
11051                                 if (angular.element(this).attr('aria-describedby') === undefined){
11052
11053                                 }
11054
11055                                 else if ((spaceIndex = angular.element(this).attr('aria-describedby').lastIndexOf(' ')) >= 0){
11056
11057                                     var describedByValue = angular.element(this).attr('aria-describedby').slice(0, spaceIndex);
11058
11059                                     angular.element(this).attr('aria-describedby', describedByValue);
11060
11061                                 }
11062                                 else {
11063                                     angular.element(this).removeAttr('aria-describedby');
11064                                 }
11065                             }
11066                         });
11067
11068                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXT FIELD
11069                         angular.element(inputElm).on('focus', function (e) {
11070                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');
11071                             for (var i = 0; i < allTooltip.length; i++) {
11072                                 if (angular.element(allTooltip[i]).hasClass('active')) {
11073                                     angular.element(allTooltip[i]).triggerHandler('click');
11074                                 }
11075                             };
11076                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
11077                             angular.element(tooltipText).css('display', 'block');
11078                             angular.element(tooltipText).attr({'aria-live': 'polite'});
11079                             elem.addClass('active');
11080                         });
11081                         angular.element(inputElm).on('blur', function (e) {
11082                             elem.removeClass('active');
11083                             angular.element(tooltipText).css('display', 'none');
11084                             angular.element(tooltipText).removeAttr('aria-live');
11085                             angular.element(this).removeAttr('aria-describedby');
11086                         });
11087
11088                         // TOOLTIP TRIGGERED AUTOMATICALLY INSIDE A TEXTAREA
11089                         angular.element(textAreaElm).on('focus', function (e) {
11090                             var allTooltip = $document[0].querySelectorAll('[class*="tooltip"]');
11091                             for (var i = 0; i < allTooltip.length; i++) {
11092                                 if (angular.element(allTooltip[i]).hasClass('active')) {
11093                                     angular.element(allTooltip[i]).triggerHandler('click');
11094                                 }
11095                             };
11096                             elem.addClass('active');
11097                             angular.element(tooltipText).css('display', 'block');
11098                             angular.element(tooltipText).attr({'aria-live': 'polite'});
11099                             angular.element(this).attr({'aria-describedby': angular.element(tooltipText).attr('id')});
11100                         });
11101                         angular.element(textAreaElm).on('blur', function (e) {
11102                             elem.removeClass('active');
11103                             angular.element(tooltipText).css('display', 'none');
11104                             angular.element(tooltipText).removeAttr('aria-live');
11105                             angular.element(this).removeAttr('aria-describedby');
11106                         });
11107                     }
11108                 };
11109             }]); 
11110 /**
11111  * @ngdoc directive
11112  * @name Navigation.att:TreeNavigation
11113  *
11114  *
11115  * @scope
11116  * @param {String} setRole - This value needs to be "tree". This is required to incorporate CATO requirements.
11117  * @param {Boolean} groupIt - This value needs to be "false" for top-level tree rendered.
11118  *
11119  * @description
11120  *  <file src="src/treeNav/docs/readme.md" />
11121  *
11122  * @usage
11123  *      <div class="b2b-tree">
11124  *                <b2b-tree-nav collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-nav>
11125  *            </div>
11126  * @example
11127  *  <section id="code">
11128         <example module="b2b.att">
11129             <file src="src/treeNav/docs/demo.html" />
11130             <file src="src/treeNav/docs/demo.js" />
11131        </example>
11132     </section>
11133  *
11134  */
11135 angular.module('b2b.att.treeNav', ['b2b.att.utilities'])
11136     .directive('b2bTreeNav', function () {
11137         return {
11138             restrict: "E",
11139             replace: true,
11140             scope: {
11141                 collection: '=',
11142                 groupIt: '=',
11143                 setRole: '@'
11144             },
11145             templateUrl: function (element, attrs) {
11146                 if (attrs.groupIt === 'true') {
11147                     return "b2bTemplate/treeNav/groupedTree.html";
11148                 } else {
11149                     return "b2bTemplate/treeNav/ungroupedTree.html";
11150                 }
11151             },
11152             link: function (scope) {               
11153                 if (!(scope.setRole === 'tree')) {
11154                     scope.setRole = 'group';
11155                 }             
11156             }
11157         }
11158     })
11159     .directive('b2bMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {
11160         return {
11161             restrict: "E",
11162             replace: true,
11163             scope: {
11164                 member: '=',
11165                 groupIt: '='
11166             },
11167             templateUrl: 'b2bTemplate/treeNav/treeMember.html',
11168             link: function (scope, element, attrs) {
11169                 scope.elemArr = [];
11170                 var removeRootTabIndex = function (elem) {
11171                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {
11172                         elem.attr('tabindex', -1);                        
11173                         return;
11174                     }
11175                     removeRootTabIndex(elem.parent());
11176                 };
11177                                 scope.$watch('member.child', function(newVal, oldVal){                                  
11178                                         if(newVal !== oldVal){
11179                                                 scope.showChild();
11180                                         };
11181                                 });
11182                 scope.showChild = function () {
11183                         if (!element.hasClass('grouped')) {
11184                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {
11185                                 scope.groupIt = false;
11186                                 element.addClass('grouped');
11187                                 element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
11188                                 $compile(element.contents())(scope);
11189                                 if(scope.member.active && scope.member.active === true){
11190                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');
11191                                 };
11192                                 if(scope.member.selected && scope.member.selected === true){
11193                                     element.attr('aria-selected', true);
11194                                     element.attr('tabindex', 0);
11195                                     removeRootTabIndex(element);
11196                                 };
11197                                 if(scope.member.active && scope.member.active == undefined){
11198                                     element.find('i').eq(0).addClass('icon-primary-collapsed');
11199                                 };
11200                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {
11201                                 element.addClass('grouped');
11202                                 scope.groupIt = true;
11203                                 // FILTER - GROUPBY - APPROACH 
11204                                 var j = 0;
11205                                 var grpName = '';
11206                                 if(scope.member.child[0].groupName !== undefined){
11207                                     grpName = scope.member.child[0].groupName;
11208                                 }
11209                                 else{
11210                                     var toSlice = scope.member.child[0].name.search(' ');
11211                                     grpName = scope.member.child[0].name.slice(0, toSlice);
11212                                 }
11213
11214                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {
11215                                     j = 0;
11216                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        
11217                                         if (j === scope.member.child.length) {
11218                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11219                                             break;
11220                                             
11221                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){
11222                                                 scope.member.child[j-1].activeGrp = true;
11223                                             };
11224                                             
11225                                         }
11226                                         if (i + scope.member.divide > scope.member.child.length) {
11227                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11228                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
11229                                                 scope.member.child[j].activeGrp = true;
11230                                             };
11231
11232                                         } else {
11233                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);
11234                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
11235                                                 scope.member.child[j].activeGrp = true;
11236                                             };
11237                                         }
11238                                     }
11239                                 }
11240                                                                 if(scope.member.divide){
11241                                                                         element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
11242                                                                 } else {
11243                                                                         element.append("<b2b-tree-nav collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-nav>");
11244                                                                 }
11245                                 $compile(element.contents())(scope);
11246                                 if(scope.member.active && scope.member.active === true){
11247                                     element.find('i').eq(0).removeClass('icon-primary-collapsed');
11248                                 };
11249                                 if(scope.member.selected && scope.member.selected === true){
11250                                     element.attr('aria-selected', true);
11251                                 };
11252                                 if( scope.member.active && scope.member.active == undefined){
11253                                     element.find('i').eq(0).addClass('icon-primary-collapsed');
11254                                 };
11255                             }
11256                         }
11257                 };
11258                                 //Below condition opens node for opening on json load.
11259                 if(scope.member.active && scope.member.active == true){
11260                     scope.showChild();
11261                 };
11262                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){
11263                     element.find('i').eq(0).addClass('icon-primary-collapsed');
11264                 }
11265                 else if(scope.member.child == undefined){
11266                     element.find('i').eq(0).addClass('icon-primary-circle');
11267                 };
11268                 element.bind('keydown', function (evt) {
11269                     switch (evt.keyCode) {
11270                         case keymap.KEY.ENTER:
11271                             if (element.hasClass('bg') && scope.member.onSelect !== undefined) {
11272                                 scope.member.onSelect(scope.member);
11273                             }
11274                             evt.stopPropagation();
11275                             break;
11276                         default: 
11277                             break;                            
11278                     }
11279                     
11280                 });
11281                 //else getting true in every case .. so better use switch case .. that makes more sense you dumb.
11282                 element.bind('click', function (evt) {
11283                                         scope.showChild();
11284                                         var expandFunc = scope.member.onExpand;
11285                                         
11286                     //onSelect
11287                         if (element.hasClass('bg') && scope.member.onSelect !== undefined) {
11288                                     scope.member.onSelect(scope.member);
11289                                 }
11290                         if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {
11291                            var eValue = scope.member.onExpand(scope.member);
11292                         }
11293                         if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {
11294                             scope.member.onCollapse(scope.member);
11295                         }
11296                 });
11297             }
11298         }
11299 }])
11300     .directive('b2bTreeLink', ['keymap', '$timeout', function (keymap, $timeout) {
11301         return {
11302             restrict: 'A',
11303             link: function (scope, element, attr, ctrl) {
11304                 var rootE, parentE, upE, downE;
11305                 var closeOthersUp = function (elem,isKeyPress,passiveClose) {
11306                     //For accordion functionality on sibling nodes
11307                     if (elem.find('a').eq(0).hasClass('active')) {
11308                         activeToggle(elem,isKeyPress,passiveClose);
11309                         return;
11310                     }
11311                     if (elem.hasClass('bg') && !isKeyPress) {
11312                         elem.removeClass('bg');
11313                         if (elem.attr('aria-selected')) {
11314                             elem.attr('aria-selected', 'false');
11315                         }                        
11316                     }
11317                     if (elem[0].previousElementSibling !== null) {
11318                         closeOthersUp(angular.element(elem[0].previousElementSibling),isKeyPress);
11319                     }
11320                 };
11321                 var closeOthersDown = function (elem,isKeyPress,passiveClose) {
11322                     //For accordion functionality on sibling nodes
11323                     if (elem.find('a').eq(0).hasClass('active')) {
11324                         activeToggle(elem,isKeyPress,passiveClose);
11325                         return;
11326                     }
11327                     if (elem.hasClass('bg') && !isKeyPress) {
11328                         elem.removeClass('bg');
11329                         if (elem.attr('aria-selected')) {
11330                             elem.attr('aria-selected', 'false');
11331                         }                        
11332                     }
11333                     if (elem[0].nextElementSibling !== null) {
11334                         closeOthersDown(angular.element(elem[0].nextElementSibling),isKeyPress);
11335                     }
11336                 };
11337
11338                
11339                 var removeBackground = function(elem){
11340
11341                     if(elem.hasClass('b2b-tree')){
11342                         angular.element(elem[0].getElementsByClassName('bg')).removeClass('bg');
11343                         return;
11344                     }else{
11345                         removeBackground(elem.parent().parent());
11346                     }
11347
11348                 };
11349
11350 /**
11351 * These two functions used for setting heights on parent nodes as the child node closes
11352 * Retaining this code for future reference
11353
11354                 var addParentHeight = function(e, h) {
11355                     var parentLi = e.parent().parent();
11356                     var parentUl = e.parent();
11357                     if(!parentLi.hasClass('b2b-tree')) {
11358                         var addHeight = parentUl[0].offsetHeight + h;
11359                         parentLi.find('ul').eq(0).css({
11360                             height: addHeight+'px'
11361                         })
11362                         addParentHeight(parentLi, h);
11363                     }                    
11364                 };
11365
11366                 var removeParentHeight = function(e, h) {
11367                     var parentLi = e.parent().parent();
11368                     var parentUl = e.parent();
11369                     if(!parentLi.hasClass('b2b-tree')) {
11370                         var addHeight = parentUl[0].offsetHeight - h;
11371                         parentLi.find('ul').eq(0).css({
11372                             height: addHeight+'px'
11373                         })
11374                         removeParentHeight(parentLi, h);
11375                     }
11376                 };
11377 */          
11378
11379             // isKeyPress - to notify that the function is called by Right Key press
11380             // passiveClose -  prevents firing of oncollapse events during the action
11381             // of expand function(check the function definition)
11382
11383                 var activeToggle = function (elem,isKeyPress,passiveClose) {
11384                     var element = elem.find('a').eq(0);
11385                     if (element.hasClass('active')) {
11386                         if(!isKeyPress){
11387                             elem.removeClass('bg');
11388                         }
11389                         
11390                         if (elem.attr('aria-selected') && !isKeyPress) {
11391                             elem.attr('aria-selected', 'false');
11392                         }
11393                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11394                             if(isKeyPress && scope.member){
11395                                 if (scope.member.onCollapse !== undefined && !passiveClose) {
11396                                     scope.member.onCollapse(scope.member);
11397                                 }
11398                             }
11399                             element.removeClass('active');
11400                             elem.attr('aria-expanded', 'false');
11401                             element.find('i').eq(0).removeClass('icon-primary-expanded');
11402                             element.find('i').eq(0).addClass('icon-primary-collapsed');
11403                             //For Animation: below commented code is used to manually set height of UL to zero 
11404                             //retaining code for future reference
11405                             /*
11406                             var totalHeight = elem.find('ul')[0].scrollHeight;
11407                             removeParentHeight(elem, totalHeight);
11408                             elem.find('ul').eq(0).css({
11409                                 height: null
11410                             });*/
11411                         }
11412                     } else {
11413                         if(!isKeyPress){
11414                             elem.addClass('bg');
11415                             elem.attr('aria-selected', 'true');
11416                         }
11417                         
11418                         if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11419                             if(isKeyPress){
11420                                 if(typeof scope.showChild === 'function' ){
11421                                 scope.showChild();
11422                                 }
11423                                 if(scope.member){
11424                                     if (scope.member.onExpand !== undefined) {
11425                                         scope.member.onExpand(scope.member);
11426                                     }
11427                                 }
11428                             }
11429                             element.addClass('active');
11430                             elem.attr('aria-expanded', 'true');
11431                             element.find('i').eq(0).removeClass('icon-primary-collapsed');
11432                             element.find('i').eq(0).addClass('icon-primary-expanded');
11433                             //For Animation: below commented code is used to manually set height of the ul generatedon the click of parent LI.
11434                             //retaining code for future reference
11435                             /*                            
11436                             var totalHeight = elem.find('ul')[0].scrollHeight;
11437                             addParentHeight(elem, totalHeight);
11438                             elem.find('ul').eq(0).css({
11439                                 height: totalHeight+'px'
11440                             });*/
11441                             
11442                         }
11443                     }
11444                 };
11445                 element.bind('click', function (evt) {
11446                     //first we close others and then we open the clicked element
11447                                         if (element[0].previousElementSibling) {
11448                                                 closeOthersUp(angular.element(element[0].previousElementSibling));
11449                                         }
11450                                         if (element[0].nextElementSibling) {
11451                                                 closeOthersDown(angular.element(element[0].nextElementSibling));
11452                                         }
11453                     removeBackground(element);
11454                                         activeToggle(element);                    
11455                     
11456                     evt.stopPropagation();                    
11457                 });
11458                 //default root tree element tabindex set zero
11459                 if (element.parent().parent().hasClass('b2b-tree') && (element.parent()[0].previousElementSibling === null)) {
11460                     element.attr('tabindex', 0);
11461                 }
11462                 //check root via class
11463                 var isRoot = function (elem) {
11464                     if (elem.parent().parent().eq(0).hasClass('b2b-tree')) {
11465                         return true;
11466                     } else {
11467                         return false;
11468                     }
11469                 };
11470                 var findRoot = function (elem) {
11471                     if (isRoot(elem)) {
11472                         rootE = elem;
11473                         return;
11474                     }
11475                     findRoot(elem.parent());
11476                 };
11477
11478                 var findPreActive = function (elem) {
11479
11480                     if (!(elem.hasClass("active"))) {
11481                         return;
11482                     } else {
11483                         var childElems = angular.element(elem[0].nextElementSibling.children);
11484                         lastE = angular.element(childElems[childElems.length - 1]);
11485                         if (lastE.find('a').eq(0).hasClass('active')) {
11486                             findPreActive(lastE.find('a').eq(0));
11487                         }
11488                         upE = lastE;
11489                     }
11490                 };
11491
11492                 var findUp = function (elem) {
11493                     if (isRoot(elem)) {
11494                         upE = elem;
11495                         return;
11496                     }
11497                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {
11498                         upE = angular.element(elem[0].previousElementSibling);
11499                         if (upE.find('a').eq(0).hasClass('active')) {
11500                             findPreActive(upE.find('a').eq(0));
11501                         }
11502                     } else {
11503                         upE = elem.parent().parent();
11504                     }
11505                 };
11506
11507                 var downElement = function (elem) {
11508                     if (elem.next().hasClass('tree-hide')) {
11509                         downElement(elem.next());
11510                     } else {
11511                         downE = elem.next();
11512                     }
11513                 }
11514                 var isBottomElem = false;
11515                 var downParent = function(liElem){
11516                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree')){
11517                         isBottomElem = true;
11518                         return;
11519                     }
11520                     if(liElem.next().length !== 0){
11521                         downE = liElem.next().eq(0);
11522                         return;
11523                     }
11524                     else {
11525                         downParent(liElem.parent().parent());
11526                     }
11527                 }
11528                 
11529                 var findDown = function (elem) {
11530                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {
11531                         downE = elem.parent();
11532                         return;
11533                     }
11534                     if (elem.hasClass('active')) {
11535                         downE = elem.next().find('li').eq(0);
11536                         if (downE.hasClass('tree-hide')) {
11537                             downElement(downE);
11538                         }
11539
11540                     } else {
11541                         downParent(elem.parent());
11542                         if(isBottomElem === true){
11543                             downE = elem.parent();
11544                             isBottomElem = false;
11545                         }
11546                     }
11547                 };
11548
11549
11550                 var resetTabPosition = function(element){
11551                     findRoot(element);
11552                     angular.element(rootE.parent().parent()[0].querySelector("li[tabindex='0']")).attr('tabindex','-1');
11553                     var elemToFocus =  rootE.parent().parent()[0].querySelector(".bg")|| rootE;
11554
11555                     angular.element(elemToFocus).attr('tabindex','0');
11556                 };
11557                 // Function to control the expansion of nodes when the user tabs into the tree and
11558                 // the slected node is not visible
11559                 var expand = function(elemArr){
11560                     var elem= elemArr.pop();
11561                     var element = elem.find('a').eq(0);                    
11562                     var selectedNode = elem.parent().parent()[0].querySelector(".bg");
11563                     if(selectedNode != null){
11564                         while(elem){
11565                              element = elem.find('a').eq(0);
11566                     if(!element.hasClass('active') ){
11567
11568
11569                     if (elem[0].previousElementSibling) {
11570                         closeOthersUp(angular.element(elem[0].previousElementSibling),true,true);
11571                         }
11572                         if (elem[0].nextElementSibling) {
11573                             closeOthersDown(angular.element(elem[0].nextElementSibling),true,true);
11574                         }
11575
11576                          if (!element.find('i').eq(0).hasClass('icon-primary-circle')) {
11577                             if(typeof scope.showChild === 'function' ){
11578                                 scope.showChild();
11579                             }
11580                             element.addClass('active');
11581                             elem.attr('aria-expanded', 'true');
11582                             element.find('i').eq(0).removeClass('icon-primary-collapsed');
11583                             element.find('i').eq(0).addClass('icon-primary-expanded');
11584                             }
11585                           
11586                           }   
11587                           elem = elemArr.pop();
11588                         }                      
11589                         
11590                     }else{
11591                         return;
11592                     }                   
11593                 };
11594
11595                 element.find('a').eq(0).bind('mouseenter', function (evt) {
11596                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {
11597                         angular.element(value).removeClass('activeTooltip') 
11598                     });
11599                     element.addClass('activeTooltip');
11600                 });
11601                 element.find('a').eq(0).bind('mouseleave', function (evt) {
11602                     element.removeClass('activeTooltip');
11603                 });
11604                 element.bind('focus', function (evt) {
11605                     angular.forEach(document.querySelectorAll('.activeTooltip'), function(value, key) {
11606                         angular.element(value).removeClass('activeTooltip') 
11607                     });
11608                     element.addClass('activeTooltip');
11609                 });
11610                 element.bind('blur', function (evt) {
11611                     element.removeClass('activeTooltip');
11612                 });
11613                 element.bind('keydown', function (evt) {
11614                     switch (evt.keyCode) {
11615                     case keymap.KEY.HOME:
11616                         evt.preventDefault();
11617                         evt.stopPropagation();
11618                         element.attr('tabindex', -1);
11619                         findRoot(element);
11620                         rootE.eq(0).attr('tabindex', 0);
11621                         rootE[0].focus();
11622                         break;
11623                     case keymap.KEY.LEFT:
11624                         evt.preventDefault();
11625                         evt.stopPropagation(); 
11626                       
11627                         if(element.find('a').eq(0).hasClass('active')){
11628                             if (element[0].previousElementSibling) {
11629                                 closeOthersUp(angular.element(element[0].previousElementSibling),true);
11630                             }
11631                             if (element[0].nextElementSibling) {
11632                                 closeOthersDown(angular.element(element[0].nextElementSibling),true);
11633                              }
11634                              activeToggle(element,true);
11635                                 return;
11636                         }
11637                             element.attr('tabindex', -1);
11638                             parentE = element.parent().parent();
11639                             parentE.attr('tabindex', 0);
11640                             parentE[0].focus();
11641                         break;
11642                     case keymap.KEY.UP:
11643                         evt.preventDefault();
11644                         evt.stopPropagation();
11645                         element.attr('tabindex', -1);
11646                         findUp(element);
11647                         upE.eq(0).attr('tabindex', 0);
11648                         upE[0].focus();
11649                         break;
11650                     case keymap.KEY.RIGHT:
11651                         evt.preventDefault();
11652                         evt.stopPropagation();
11653                         if(element.find('i').eq(0).hasClass('icon-primary-circle')){
11654                             break;
11655                         }    
11656                         if (!element.find('a').eq(0).hasClass('active')) {
11657                             if (element[0].previousElementSibling) {
11658                         closeOthersUp(angular.element(element[0].previousElementSibling),true);
11659                         }
11660                         if (element[0].nextElementSibling) {
11661                             closeOthersDown(angular.element(element[0].nextElementSibling),true);
11662                         }
11663                         activeToggle(element,true);
11664                     
11665                         }
11666                         else {
11667                             element.attr('tabindex', -1);
11668                             findDown(element.find('a').eq(0));
11669                             downE.eq(0).attr('tabindex', 0);
11670                             downE[0].focus();                            
11671                         }                        
11672                         break;
11673                     case keymap.KEY.DOWN:
11674                         evt.preventDefault();
11675                         element.attr('tabindex', -1);
11676                         findDown(element.find('a').eq(0));
11677                         downE.eq(0).attr('tabindex', 0);
11678                         downE[0].focus();
11679                         evt.stopPropagation();
11680                         break;
11681                     case keymap.KEY.ENTER:
11682                         var isSelectedElem = element.hasClass('bg');
11683                         var enterFunc = function(element){
11684                             if (isSelectedElem) {
11685                                 element.removeClass('bg');
11686                                 if (element.attr('aria-selected')) {
11687                                     element.attr('aria-selected', 'false');
11688                                 }                        
11689                             }
11690                             else {
11691                                 element.addClass('bg');
11692                                 element.attr('aria-selected', 'true');                                   
11693                             }  
11694                         };                            
11695                         if (element[0].previousElementSibling) {
11696                             closeOthersUp(angular.element(element[0].previousElementSibling));
11697                         }
11698                         if (element[0].nextElementSibling) {
11699                             closeOthersDown(angular.element(element[0].nextElementSibling));
11700                         }                   
11701                         
11702                         removeBackground(element);
11703                         enterFunc(element);
11704                         evt.stopPropagation();                                                      
11705                         break;
11706                     case keymap.KEY.TAB:
11707                         $timeout(function(){
11708                             resetTabPosition(element);
11709                         },0);
11710                          evt.stopPropagation(); 
11711                         
11712                         break;
11713                     default:
11714                         break;
11715                     }
11716                 });
11717             element.bind('keyup',function(evt){
11718                 if(evt.keyCode === keymap.KEY.TAB){
11719                   
11720                         var tempElem = element;
11721                         var elemArr = [];
11722                         while(!tempElem.hasClass('b2b-tree')){
11723                             elemArr.push(tempElem);
11724                             tempElem = tempElem.parent().parent();
11725                         }
11726                         elemArr.push(tempElem);
11727                       
11728                         expand(elemArr);                    
11729                 }
11730                  evt.stopPropagation(); 
11731             });
11732             }
11733         };
11734     }]);
11735 /**
11736  * @ngdoc directive
11737  * @name Navigation.att:Tree nodes with checkboxes
11738  *
11739  * @param {String} setRole - The value needs to be "tree". This is required to incorporate CATO requirements.
11740  * @param {boolean} groupIt - The value needs to be "false" for top-level tree rendered. 
11741  * @param {Object} collection -  The JSON object of tree to be rendered.
11742  * @description
11743  *  <file src="src/treeNodeCheckbox/docs/readme.md" />
11744  *
11745  * @usage
11746  *      <div class="b2b-tree-checkbox">
11747  *                <b2b-tree-node-checkbox collection="treeStructure" set-role="tree" group-it="false"></b2b-tree-node-checkbox>
11748  *            </div>
11749  * @example
11750  *  <section id="code">
11751         <example module="b2b.att">
11752             <file src="src/treeNodeCheckbox/docs/demo.html" />
11753             <file src="src/treeNodeCheckbox/docs/demo.js" />
11754        </example>
11755     </section>
11756  *
11757  */
11758 angular.module('b2b.att.treeNodeCheckbox', ['b2b.att.utilities'])
11759     .directive('b2bTreeNodeCheckbox', function () {
11760         return {
11761             restrict: "E",
11762             replace: true,
11763             scope: {
11764                 collection: '=',
11765                 groupIt: '=',
11766                 setRole: '@'
11767             },
11768             templateUrl: function (element, attrs) {
11769                 if (attrs.groupIt === 'true') {
11770                     return "b2bTemplate/treeNodeCheckbox/groupedTree.html";
11771                 } else {
11772                     return "b2bTemplate/treeNodeCheckbox/ungroupedTree.html";
11773                 }
11774             },
11775             link: function (scope) {
11776                 if (!(scope.setRole === 'tree')) {
11777                     scope.setRole = 'group';
11778                 }
11779             }
11780         }
11781     })
11782     .directive('b2bTreeMember', ['$compile', '$timeout', 'keymap', function ($compile, $timeout, keymap) {
11783         return {
11784             restrict: "E",
11785             replace: true,
11786             scope: {
11787                 member: '=',
11788                 groupIt: '='
11789             },
11790             templateUrl: 'b2bTemplate/treeNodeCheckbox/treeMember.html',
11791             link: function (scope, element, attrs) {
11792                 scope.elemArr = [];
11793                 var removeRootTabIndex = function (elem) {
11794                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {
11795                         elem.attr('tabindex', -1);                        
11796                         return;
11797                     }
11798                     removeRootTabIndex(elem.parent());
11799                 };
11800                 scope.$watch('member.child', function(newVal, oldVal){                  
11801                     if(newVal !== oldVal){
11802                         scope.showChild();
11803                     };
11804                 });
11805
11806                 var checkedCount = 0;
11807                 var nonCheckedCount = 0;
11808                 var checkBoxesCount = 0;
11809
11810                 if(element.find('a').eq(0).find('input')){
11811                     if(scope.member.indeterminate){
11812                         element.find('a').eq(0).find('input').prop('indeterminate', true);
11813                         element.attr('aria-checked',"mixed");
11814                     }
11815                     element.attr('aria-checked',scope.member.isSelected);
11816                 }
11817
11818                 element.find('a').eq(0).find('input').bind('change',function(){
11819                     scope.member.indeterminate = false;
11820                     downwardModalUpdate(scope.member);
11821                     downwardSelection(element);
11822                     upwardSelection(element);
11823                     element.attr('aria-checked',scope.member.isSelected);
11824                      if (scope.member.onSelect !== undefined) {
11825                         scope.member.onSelect(scope.member);
11826                     }
11827                 });
11828
11829                 element.find('a').eq(0).find('input').bind('click',function(){
11830                     var elem = angular.element(this);
11831                     if(scope.member.indeterminate){
11832                         scope.member.indeterminate = false;
11833                         scope.member.isSelected = true;
11834                         elem.prop('indeterminate', false);
11835                         elem.prop('checked', true);
11836                         elem.triggerHandler('change');
11837                     }
11838                 });
11839
11840                 var groupNode = false;
11841                 var checkedTreeNode = false;
11842
11843                 var isCheckboxSelected = function(elem){
11844                     checkedTreeNode = false;
11845                     checkedTreeNode = angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked;
11846                 }
11847
11848                 var findCheckbox = function(elem){
11849                     return angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox');
11850                 }
11851
11852                 var updateGrpNodeCheckboxes = function(elem, checked){
11853                     angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.treeCheckBox').checked = checked;
11854                 }
11855
11856                 
11857                 var isGroupNode = function(elem){
11858                     groupNode = false;
11859                     if(angular.element(angular.element(elem).find('a').eq(0))[0].querySelector('input.grpTreeCheckbox')){
11860                         groupNode = true;
11861                     }
11862                 }
11863
11864                 var downwardModalUpdate = function(curMember){
11865                     angular.forEach(curMember.child, function(childMember, key) {
11866                         childMember.isSelected = curMember.isSelected;
11867                         childMember.indeterminate = false;
11868                         if(angular.isArray(childMember.child) && scope.member.child.length > 0){
11869                             downwardModalUpdate(childMember);
11870                         }
11871                     });
11872                 }
11873
11874                 var downwardSelection = function(elem){
11875                     if(findCheckbox(elem)){
11876                         isCheckboxSelected(elem)
11877                     } 
11878                     if(angular.element(elem).find('ul').length > 0){
11879                         var childNodes = angular.element(elem).find('ul').eq(0).children('li');
11880                         for(var i=0; i<childNodes.length; i++){
11881                             if(findCheckbox(childNodes[i])){
11882                                 isGroupNode(childNodes[i]);
11883                                 angular.element(findCheckbox(childNodes[i])).prop('indeterminate', false);
11884                                 angular.element(childNodes[i]).attr('aria-checked',checkedTreeNode);
11885                                 if(groupNode){
11886                                     updateGrpNodeCheckboxes(childNodes[i],checkedTreeNode);
11887                                 }else{
11888                                     angular.element(childNodes[i]).scope().member.isSelected = checkedTreeNode;
11889                                     angular.element(childNodes[i]).scope().member.indeterminate = false
11890                                     angular.element(childNodes[i]).scope().$apply();
11891                                 }
11892                                 downwardSelection(childNodes[i]);
11893                             }
11894                         }
11895
11896                     }
11897                 }
11898                 var upwardSelection = function(elem){
11899                                         if(!elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')){
11900                                                 var childNodes = elem.parent().parent().find('ul').eq(0).children('li');
11901                                                 checkedCount = 0;
11902                                                 nonCheckedCount = 0;
11903                                                 checkBoxesCount = 0;    
11904                                                 for(i=0; i<childNodes.length; i++){
11905                                                         if(findCheckbox(childNodes[i])){
11906                                                                 isGroupNode(childNodes[i]);
11907                                                                 isCheckboxSelected(childNodes[i]);
11908                                                                 checkBoxesCount++;
11909                                                                 if(checkedTreeNode){
11910                                                                         checkedCount++;
11911                                                                 }else if(!angular.element(angular.element(angular.element(childNodes[i]).find('a').eq(0))[0].querySelector('input.treeCheckBox')).prop('indeterminate')){
11912                                                                         nonCheckedCount++;
11913                                                                 }
11914                                                         }
11915                                                 }
11916                                                 var parentNodeScope;
11917                                                 parentNodeScope = angular.element(elem.parent().parent()).scope();
11918                                                 if(findCheckbox(elem.parent().parent())){
11919                                                         if(nonCheckedCount == checkBoxesCount){
11920                                                                 angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11921                                                                 if(parentNodeScope &&  parentNodeScope.member){
11922                                                                         parentNodeScope.member.isSelected = false;
11923                                                                         parentNodeScope.member.indeterminate = false;
11924                                                                 }else{
11925                                                                         updateGrpNodeCheckboxes(elem.parent().parent(),false);
11926                                                                 }
11927                                                                 angular.element(elem.parent().parent()).attr('aria-checked',false);
11928                                                         }else if(checkedCount == checkBoxesCount){
11929                                                                 angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', false);
11930                                                                 if(parentNodeScope &&  parentNodeScope.member){
11931                                                                         parentNodeScope.member.isSelected = true;
11932                                                                         parentNodeScope.member.indeterminate = false;
11933                                                                 }else{
11934                                                                         updateGrpNodeCheckboxes(elem.parent().parent(),true);
11935                                                                 }
11936                                                                 angular.element(elem.parent().parent()).attr('aria-checked',true);
11937                                                         }else{
11938                                                                 angular.element(findCheckbox(elem.parent().parent())).prop('indeterminate', true);
11939                                                                 if(parentNodeScope &&  parentNodeScope.member){
11940                                                                         parentNodeScope.member.isSelected = false;
11941                                                                         parentNodeScope.member.indeterminate = true;
11942                                                                 }else{
11943                                                                         updateGrpNodeCheckboxes(elem.parent().parent(),false);
11944                                                                 }
11945                                                                 angular.element(elem.parent().parent()).attr('aria-checked',"mixed");
11946                                                         }
11947                                                         if(parentNodeScope &&  parentNodeScope.member){
11948                                                                 parentNodeScope.$apply();
11949                                                         }        
11950                                                 }
11951                                                 
11952                                                 
11953                                                 
11954                                                 if(elem.parent().parent().attr('role') == "treeitem"){
11955                                                         upwardSelection(elem.parent().parent());
11956                                                 }
11957                                         }
11958                 }
11959
11960                 scope.showChild = function () {
11961                         if (!element.hasClass('grouped')) {
11962                             if (angular.isArray(scope.member.child) && scope.member.child.length > 0 && (scope.member.divide === undefined || scope.member.child.length < scope.member.divide)) {
11963                                 scope.groupIt = false;
11964                                 element.addClass('grouped');
11965                                 element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
11966                                 $compile(element.contents())(scope);
11967                                 if(scope.member.active && scope.member.active === true){
11968                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
11969                                 };
11970                                 if(scope.member.selected && scope.member.selected === true){
11971                                     element.attr('tabindex', 0);
11972                                     removeRootTabIndex(element);
11973                                 };
11974                                 if(scope.member.active && scope.member.active == undefined){
11975                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
11976                                 };
11977                             } else if (scope.member.child && scope.member.divide && scope.member.child.length > scope.member.divide) {
11978                                 element.addClass('grouped');
11979                                 scope.groupIt = true;
11980                                 var j = 0;
11981                                 var grpName = '';
11982                                 if(scope.member.child[0].groupName !== undefined){
11983                                     grpName = scope.member.child[0].groupName;
11984                                 }
11985                                 else{
11986                                     var toSlice = scope.member.child[0].name.search(' ');
11987                                     grpName = scope.member.child[0].name.slice(0, toSlice);
11988                                 }
11989
11990                                 for (i = 0; i < scope.member.child.length; i += scope.member.divide) {
11991                                     j = 0;
11992                                     for (j = j + i; j < (i + scope.member.divide); j++) {                                        
11993                                         if (j === scope.member.child.length) {
11994                                             scope.member.child[j - 1].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
11995                                             break;
11996                                             
11997                                             if(scope.member.child[j-1].active && scope.member.child[j-1].active===true){
11998                                                 scope.member.child[j-1].activeGrp = true;
11999                                             };
12000                                             
12001                                         }
12002                                         if (i + scope.member.divide > scope.member.child.length) {
12003                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (scope.member.child.length);
12004                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
12005                                                 scope.member.child[j].activeGrp = true;
12006                                             };
12007
12008                                         } else {
12009                                             scope.member.child[j].grpChild = grpName + ' ' + (i + 1) + ' - ' + (i + scope.member.divide);
12010                                             if(scope.member.child[j].active && scope.member.child[j].active===true){
12011                                                 scope.member.child[j].activeGrp = true;
12012                                             };
12013                                         }
12014                                     }
12015                                 }
12016                                 if(scope.member.divide){
12017                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
12018                                 } else {
12019                                     element.append("<b2b-tree-node-checkbox collection='member.child' group-it='" + scope.groupIt + "'></b2b-tree-node-checkbox>");
12020                                 }
12021                                 $compile(element.contents())(scope);
12022                                 if(scope.member.active && scope.member.active === true){
12023                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
12024                                 };
12025                                 
12026                                 if( scope.member.active && scope.member.active == undefined){
12027                                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12028                                 };
12029                             }
12030                         }
12031                         $timeout(function () {
12032                             if(!scope.member.indeterminate){
12033                                 downwardSelection(element);
12034                             }    
12035                         });  
12036
12037                 };
12038                 
12039                 if(scope.member.active && scope.member.active == true){
12040                     scope.showChild();
12041                 };
12042                 if(scope.member.active == undefined && !element.find('a').eq(0).hasClass('active') && scope.member.child !== undefined){
12043                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12044                 }
12045                 else if(scope.member.child == undefined){
12046                     angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-circle');
12047                     if(scope.$parent.$index === 0) {
12048                         element.find('a').eq(0).append('<span class="first-link"></span>');
12049                     };
12050                 };
12051                 
12052                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
12053                     scope.showChild();
12054                     var expandFunc = scope.member.onExpand;
12055                     if (element.find('a').eq(0).hasClass('active') && scope.member.onExpand !== undefined) {
12056                        var eValue = scope.member.onExpand(scope.member);
12057                     }
12058                     if (!element.find('a').eq(0).hasClass('active') && scope.member.onCollapse !== undefined) {
12059                         scope.member.onCollapse(scope.member);
12060                     }
12061                 });
12062
12063                 angular.element(element[0].querySelectorAll('.treeNodeName')).eq(0).bind('click', function (evt) {
12064
12065                 });
12066                 
12067             }
12068         }
12069 }])
12070     .directive('b2bTreeNodeLink', ['keymap', '$timeout', function (keymap, $timeout) {
12071         return {
12072             restrict: 'A',
12073             link: function (scope, element, attr, ctrl) {
12074                 var rootE, parentE, upE, downE;
12075                 var closeOthersUp = function (elem) {
12076                     
12077                     if (elem.find('a').eq(0).hasClass('active')) {
12078                         activeToggle(elem);
12079                         return;
12080                     }
12081                     if (elem.hasClass('bg')) {
12082                         elem.removeClass('bg');
12083                     }
12084                     if (elem[0].previousElementSibling !== null) {
12085                         closeOthersUp(angular.element(elem[0].previousElementSibling));
12086                     }
12087                 };
12088                 var closeOthersDown = function (elem) {
12089                     
12090                     if (elem.find('a').eq(0).hasClass('active')) {
12091                         activeToggle(elem);
12092                         return;
12093                     }
12094                     if (elem.hasClass('bg')) {
12095                         elem.removeClass('bg');
12096                     }
12097                     if (elem[0].nextElementSibling !== null) {
12098                         closeOthersDown(angular.element(elem[0].nextElementSibling));
12099                     }
12100                 };
12101
12102                 var removeBackgroundUp = function (elem) {
12103                     
12104                     if (elem.hasClass('b2b-tree-checkbox')) {
12105                         return;
12106                     } else {
12107                         elem.parent().parent().removeClass('bg');
12108                         removeBackgroundUp(elem.parent().parent());
12109                     }
12110                 };
12111
12112                 var removeBackgroundDown = function (elem) {
12113                     
12114                     angular.element(elem[0].querySelector('.bg')).removeClass('bg');
12115                 };
12116
12117
12118
12119                 var activeToggle = function (elem) {
12120                     var element = elem.find('a').eq(0);
12121                     if (element.hasClass('active')) {
12122                         elem.removeClass('bg');
12123                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
12124                             element.removeClass('active');
12125                             elem.attr('aria-expanded', 'false');
12126                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-expanded');
12127                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-collapsed');
12128                         }
12129                     } else {
12130                         elem.addClass('bg');
12131                         if (!angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')) {
12132                             element.addClass('active');
12133                             elem.attr('aria-expanded', 'true');
12134                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).removeClass('icon-primary-collapsed');
12135                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).addClass('icon-primary-expanded');
12136                         }
12137                     }
12138                 };
12139                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).bind('click', function (evt) {
12140                     
12141                         if (element[0].previousElementSibling) {
12142                             closeOthersUp(angular.element(element[0].previousElementSibling));
12143                         }
12144                         if (element[0].nextElementSibling) {
12145                             closeOthersDown(angular.element(element[0].nextElementSibling));
12146                         }
12147
12148                         activeToggle(element);
12149
12150                     removeBackgroundDown(element);
12151                     removeBackgroundUp(element);
12152                     evt.stopPropagation();                    
12153                 });
12154                 
12155                 if (element.parent().parent().hasClass('b2b-tree-checkbox') && (element.parent()[0].previousElementSibling === null)) {
12156                     element.attr('tabindex', 0);
12157                 }
12158                 
12159                 var isRoot = function (elem) {
12160                     if (elem.parent().parent().eq(0).hasClass('b2b-tree-checkbox')) {
12161                         return true;
12162                     } else {
12163                         return false;
12164                     }
12165                 };
12166                 var findRoot = function (elem) {
12167                     if (isRoot(elem)) {
12168                         rootE = elem;
12169                         return;
12170                     }
12171                     findRoot(elem.parent());
12172                 };
12173
12174                 var findPreActive = function (elem) {
12175
12176                     if (!(elem.hasClass("active"))) {
12177                         return;
12178                     } else {
12179                         var childElems = angular.element(elem[0].nextElementSibling.children);
12180                         lastE = angular.element(childElems[childElems.length - 1]);
12181                         if (lastE.find('a').eq(0).hasClass('active')) {
12182                             findPreActive(lastE.find('a').eq(0));
12183                         }
12184                         upE = lastE;
12185                     }
12186                 };
12187
12188                 var findUp = function (elem) {
12189                     if (isRoot(elem)) {
12190                         upE = elem;
12191                         return;
12192                     }
12193                     if (elem[0].previousElementSibling !== null && !angular.element(elem[0].previousElementSibling).hasClass('tree-hide')) {
12194                         upE = angular.element(elem[0].previousElementSibling);
12195                         if (upE.find('a').eq(0).hasClass('active')) {
12196                             findPreActive(upE.find('a').eq(0));
12197                         }
12198                     } else {
12199                         upE = elem.parent().parent();
12200                     }
12201                 };
12202
12203                 var downElement = function (elem) {
12204                     if (elem.next().hasClass('tree-hide')) {
12205                         downElement(elem.next());
12206                     } else {
12207                         downE = elem.next();
12208                     }
12209                 }
12210                 var isBottomElem = false;
12211                 var downParent = function(liElem){
12212                     if(liElem.eq(0).parent().parent().eq(0).hasClass('b2b-tree-checkbox')){
12213                         isBottomElem = true;
12214                         return;
12215                     }
12216                     if(liElem.next().length !== 0){
12217                         downE = liElem.next().eq(0);
12218                         return;
12219                     }
12220                     else {
12221                         downParent(liElem.parent().parent());
12222                     }
12223                 }
12224                 
12225                 var findDown = function (elem) {
12226                     if (isRoot(elem.parent()) && !elem.hasClass('active')) {
12227                         downE = elem.parent();
12228                         return;
12229                     }
12230                     if (elem.hasClass('active')) {
12231                         downE = elem.next().find('li').eq(0);
12232                         if (downE.hasClass('tree-hide')) {
12233                             downElement(downE);
12234                         }
12235
12236                     } else {
12237                         downParent(elem.parent());
12238                         if(isBottomElem === true){
12239                             downE = elem.parent();
12240                             isBottomElem = false;
12241                         }
12242                     }
12243                 };
12244                 element.bind('keydown', function (evt) {
12245                     switch (evt.keyCode) {
12246                     case keymap.KEY.HOME:
12247                         evt.preventDefault();
12248                         evt.stopPropagation();
12249                         element.attr('tabindex', -1);
12250                         findRoot(element);
12251                         rootE.eq(0).attr('tabindex', 0);
12252                         rootE[0].focus();
12253                         break;
12254                     case keymap.KEY.LEFT:
12255                         evt.preventDefault();
12256                         evt.stopPropagation();
12257                         if (!isRoot(element)) {
12258                             if(element.find('a').eq(0).hasClass('active')){
12259                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12260                                 return;
12261                             }
12262                             element.attr('tabindex', -1);
12263                             parentE = element.parent().parent();
12264                             parentE.attr('tabindex', 0);
12265                             parentE[0].focus();
12266                         } else {
12267                             if (element.find('a').eq(0).hasClass('active')) {
12268                                 angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12269                             }
12270                         };
12271                         break;
12272                     case keymap.KEY.UP:
12273                         evt.preventDefault();
12274                         evt.stopPropagation();
12275                         element.attr('tabindex', -1);
12276                         findUp(element);
12277                         upE.eq(0).attr('tabindex', 0);
12278                         upE[0].focus();
12279                         break;
12280                     case keymap.KEY.RIGHT:
12281                         evt.preventDefault();
12282                         evt.stopPropagation();
12283                         if(angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).hasClass('icon-primary-circle')){
12284                             break;
12285                         }    
12286                         if (!element.find('a').eq(0).hasClass('active')) {
12287                             angular.element(element[0].querySelectorAll('i.expandCollapseIcon')).eq(0).triggerHandler('click');
12288                         }
12289                         else {
12290                             element.attr('tabindex', -1);
12291                             findDown(element.find('a').eq(0));
12292                             downE.eq(0).attr('tabindex', 0);
12293                             downE[0].focus();                            
12294                         }                        
12295                         break;
12296                     case keymap.KEY.DOWN:
12297                         evt.preventDefault();
12298                         element.attr('tabindex', -1);
12299                         findDown(element.find('a').eq(0));
12300                         downE.eq(0).attr('tabindex', 0);
12301                         downE[0].focus();
12302                         evt.stopPropagation();
12303                         break;
12304                     case keymap.KEY.SPACE:
12305                     case keymap.KEY.ENTER:
12306                         evt.preventDefault();
12307                         evt.stopPropagation();
12308                         if(angular.isDefined(element.scope().member.isSelected)){
12309                             element.scope().member.isSelected = !element.scope().member.isSelected;
12310                             element.scope().member.indeterminate = false;
12311                             element.scope().$apply();
12312                             element.find('a').eq(0).find('input').prop('indeterminate', false);
12313                             element.find('a').eq(0).find('input').triggerHandler('change');
12314                         }
12315                         break;    
12316                     default:
12317                         break;
12318                     }
12319                 });
12320             }
12321         };
12322     }]);
12323
12324 angular.module('b2b.att.collapse', ['b2b.att.transition'])
12325
12326 // The collapsible directive indicates a block of html that will expand and collapse
12327 .directive('b2bCollapse', ['$transition', function($transition) {
12328     // CSS transitions don't work with height: auto, so we have to manually change the height to a
12329     // specific value and then once the animation completes, we can reset the height to auto.
12330     // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
12331     // "collapse") then you trigger a change to height 0 in between.
12332     // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
12333
12334     var props = {
12335         open: {
12336             marginTop: null,
12337             marginBottom: null,
12338             paddingTop: null,
12339             paddingBottom: null,
12340             display: 'block'
12341         },
12342         closed: {
12343             marginTop: 0,
12344             marginBottom: 0,
12345             paddingTop: 0,
12346             paddingBottom: 0,
12347             display: 'none'
12348         }
12349     };
12350
12351     var fixUpHeight = function(scope, element, height) {
12352         // We remove the collapse CSS class to prevent a transition when we change to height: auto
12353         element.removeClass('b2bCollapse');
12354         element.css({height: height});
12355         //adjusting for any margin or padding
12356         if (height === 0) {
12357             element.css(props.closed);
12358         } else {
12359             element.css(props.open);
12360         }
12361         // It appears that  reading offsetWidth makes the browser realise that we have changed the
12362         // height already :-/
12363         var x = element[0].offsetWidth;
12364         element.addClass('b2bCollapse');
12365     };
12366
12367     return {
12368         link: function(scope, element, attrs) {
12369             var isCollapsed;
12370             var initialAnimSkip = true;
12371             scope.$watch(function() {
12372                 return element[0].scrollHeight;
12373             }, function(value) {
12374                 //The listener is called when scrollHeight changes
12375                 //It actually does on 2 scenarios: 
12376                 // 1. Parent is set to display none
12377                 // 2. angular bindings inside are resolved
12378                 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
12379                 if (element[0].scrollHeight !== 0) {
12380                     if (!isCollapsed) {
12381                         if (initialAnimSkip) {
12382                             fixUpHeight(scope, element, element[0].scrollHeight + 'px');
12383                         } else {
12384                             fixUpHeight(scope, element, 'auto');
12385                             element.css({overflow: 'visible'});
12386                         }
12387                     }
12388                 }
12389             });
12390
12391             scope.$watch(attrs.b2bCollapse, function(value) {
12392                 if (value) {
12393                     collapse();
12394                 } else {
12395                     expand();
12396                 }
12397             });
12398
12399
12400             var currentTransition;
12401             var doTransition = function(change) {
12402                 if (currentTransition) {
12403                     currentTransition.cancel();
12404                 }
12405                 currentTransition = $transition(element, change);
12406                 currentTransition.then(
12407                         function() {
12408                             currentTransition = undefined;
12409                         },
12410                         function() {
12411                             currentTransition = undefined;
12412                         }
12413                 );
12414                 return currentTransition;
12415             };
12416
12417             var expand = function() {
12418                 scope.postTransition = true; 
12419                 if (initialAnimSkip) {
12420                     initialAnimSkip = false;
12421                     if (!isCollapsed) {
12422                         fixUpHeight(scope, element, 'auto');
12423                     }
12424                 } else {
12425                     //doTransition({ height : element[0].scrollHeight + 'px' })
12426                     doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))
12427                             .then(function() {
12428                                 // This check ensures that we don't accidentally update the height if the user has closed
12429                                 // the group while the animation was still running
12430                                 if (!isCollapsed) {
12431                                     fixUpHeight(scope, element, 'auto');
12432                                 }
12433                             });
12434                 }
12435                 isCollapsed = false;
12436             };
12437
12438             var collapse = function() {
12439                 isCollapsed = true;
12440                 if (initialAnimSkip) {
12441                     initialAnimSkip = false;
12442                     fixUpHeight(scope, element, 0);
12443                 } else {
12444                     fixUpHeight(scope, element, element[0].scrollHeight + 'px');
12445                     doTransition(angular.extend({height: 0}, props.closed)).then(function() {
12446                         scope.postTransition = false;
12447                     });
12448                     element.css({overflow: 'hidden'});
12449                 }
12450             };
12451         }
12452     };
12453 }]);
12454 angular.module('b2b.att.position', [])
12455
12456 .factory('$position', ['$document', '$window', function ($document, $window) {
12457     function getStyle(el, cssprop) {
12458         if (el.currentStyle) { //IE
12459             return el.currentStyle[cssprop];
12460         } else if ($window.getComputedStyle) {
12461             return $window.getComputedStyle(el)[cssprop];
12462         }
12463         // finally try and get inline style
12464         return el.style[cssprop];
12465     }
12466
12467     /**
12468      * Checks if a given element is statically positioned
12469      * @param element - raw DOM element
12470      */
12471     function isStaticPositioned(element) {
12472         return (getStyle(element, "position") || 'static') === 'static';
12473     }
12474
12475     /**
12476      * returns the closest, non-statically positioned parentOffset of a given element
12477      * @param element
12478      */
12479     var parentOffsetEl = function (element) {
12480         var docDomEl = $document[0];
12481         var offsetParent = element.offsetParent || docDomEl;
12482         while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
12483             offsetParent = offsetParent.offsetParent;
12484         }
12485         return offsetParent || docDomEl;
12486     };
12487
12488     return {
12489         /**
12490          * Provides read-only equivalent of jQuery's position function:
12491          * http://api.jquery.com/position/
12492          */
12493         position: function (element) {
12494             var elBCR = this.offset(element);
12495             var offsetParentBCR = {
12496                 top: 0,
12497                 left: 0
12498             };
12499             var offsetParentEl = parentOffsetEl(element[0]);
12500             if (offsetParentEl !== $document[0]) {
12501                 offsetParentBCR = this.offset(angular.element(offsetParentEl));
12502                 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
12503                 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
12504             }
12505
12506             return {
12507                 width: element.prop('offsetWidth'),
12508                 height: element.prop('offsetHeight'),
12509                 top: elBCR.top - offsetParentBCR.top,
12510                 left: elBCR.left - offsetParentBCR.left
12511             };
12512         },
12513
12514         /**
12515          * Provides read-only equivalent of jQuery's offset function:
12516          * http://api.jquery.com/offset/
12517          */
12518         offset: function (element) {
12519             var boundingClientRect = element[0].getBoundingClientRect();
12520             return {
12521                 width: element.prop('offsetWidth'),
12522                 height: element.prop('offsetHeight'),
12523                 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
12524                 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
12525             };
12526         },
12527                 
12528                  /**
12529          * Provides functionality to check whether an element is in view port.
12530          */
12531         isElementInViewport: function (element) {
12532             if (element) {
12533                 var rect = element[0].getBoundingClientRect();
12534                 return (
12535                     rect.top >= 0 &&
12536                     rect.left >= 0 &&
12537                     rect.bottom <= ($window.innerHeight || $document[0].documentElement.clientHeight) &&
12538                     rect.right <= ($window.innerWidth || $document[0].documentElement.clientWidth)
12539                 );
12540             } else {
12541                 return false;
12542             }
12543         }
12544     };
12545 }])
12546
12547 .factory('$isElement', [function () {
12548     var isElement = function (currentElem, targetElem, alternateElem) {
12549         if (currentElem[0] === targetElem[0]) {
12550             return true;
12551         } else if (currentElem[0] === alternateElem[0]) {
12552             return false;
12553         } else {
12554             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
12555         }
12556     };
12557
12558     return isElement;
12559 }])
12560
12561 .directive('attPosition', ['$position', function ($position) {
12562     return {
12563         restrict: 'A',
12564         link: function (scope, elem, attr) {
12565             scope.$watchCollection(function () {
12566                 return $position.position(elem);
12567             }, function (value) {
12568                 scope[attr.attPosition] = value;
12569             });
12570         }
12571     };
12572 }]);
12573
12574 angular.module('b2b.att.transition', [])
12575
12576 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
12577
12578   var $transition = function(element, trigger, options) {
12579     options = options || {};
12580     var deferred = $q.defer();
12581     var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
12582
12583     var transitionEndHandler = function() {
12584       $rootScope.$apply(function() {
12585         element.unbind(endEventName, transitionEndHandler);
12586         deferred.resolve(element);
12587       });
12588     };
12589
12590     if (endEventName) {
12591       element.bind(endEventName, transitionEndHandler);
12592     }
12593
12594     // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
12595     $timeout(function() {
12596       if ( angular.isString(trigger) ) {
12597         element.addClass(trigger);
12598       } else if ( angular.isFunction(trigger) ) {
12599         trigger(element);
12600       } else if ( angular.isObject(trigger) ) {
12601         element.css(trigger);
12602       }
12603       //If browser does not support transitions, instantly resolve
12604       if ( !endEventName ) {
12605         deferred.resolve(element);
12606       }
12607     }, 100);
12608
12609     // Add our custom cancel function to the promise that is returned
12610     // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
12611     // i.e. it will therefore never raise a transitionEnd event for that transition
12612     deferred.promise.cancel = function() {
12613       if ( endEventName ) {
12614         element.unbind(endEventName, transitionEndHandler);
12615       }
12616       deferred.reject('Transition cancelled');
12617     };
12618
12619     return deferred.promise;
12620   };
12621
12622   // Work out the name of the transitionEnd event
12623   var transElement = document.createElement('trans');
12624   var transitionEndEventNames = {
12625     'WebkitTransition': 'webkitTransitionEnd',
12626     'MozTransition': 'transitionend',
12627     'OTransition': 'oTransitionEnd',
12628     'transition': 'transitionend'
12629   };
12630   var animationEndEventNames = {
12631     'WebkitTransition': 'webkitAnimationEnd',
12632     'MozTransition': 'animationend',
12633     'OTransition': 'oAnimationEnd',
12634     'transition': 'animationend'
12635   };
12636   function findEndEventName(endEventNames) {
12637     for (var name in endEventNames){
12638       if (transElement.style[name] !== undefined) {
12639         return endEventNames[name];
12640       }
12641     }
12642   }
12643   $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
12644   $transition.animationEndEventName = findEndEventName(animationEndEventNames);
12645   return $transition;
12646 }])
12647
12648 .factory('$scrollTo', ['$window', function($window) {
12649     var $scrollTo = function(offsetLeft, offsetTop, duration) {
12650         TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});
12651     };
12652     return $scrollTo;
12653 }])
12654 .factory('animation', function(){
12655     return TweenMax;
12656 })
12657 .factory('$progressBar', function(){
12658
12659    //Provides a function to pass in code for closure purposes
12660    var loadingAnimationCreator = function(onUpdateCallback){
12661
12662       //Use closure to setup some resuable code
12663       var loadingAnimation = function(callback, duration){
12664           TweenMax.to({}, duration, {
12665               onUpdateParams: ["{self}"],
12666               onUpdate: onUpdateCallback,
12667               onComplete: callback
12668           });
12669       };
12670       //Returns a function that takes a callback function and a duration for the animation
12671       return (function(){
12672         return loadingAnimation;
12673       })();
12674     };
12675
12676   return loadingAnimationCreator;
12677 })
12678 .factory('$height', function(){
12679   var heightAnimation = function(element,duration,height,alpha){
12680     TweenMax.to(element,
12681       duration,
12682       {height:height, autoAlpha:alpha},
12683       0);
12684   };
12685   return heightAnimation;
12686 });
12687 angular.module('b2b.att.utilities', ['ngSanitize'])
12688 .constant('b2bUtilitiesConfig', {
12689     prev: '37',
12690     up: '38',
12691     next: '39',
12692     down: '40',
12693     type: 'list',
12694     columns: 1,
12695     enableSearch: false,
12696     searchTimer: 200,
12697     circularTraversal: false
12698 })
12699 .constant('b2bWhenScrollEndsConstants', {
12700     'threshold': 100,
12701     'width': 0,
12702     'height': 0
12703 })
12704 // All breakpoints ranges from >= min and < max
12705 .constant('b2bAwdBreakpoints', {
12706     breakpoints: {
12707         mobile: {
12708             min: 1,
12709             max: 768
12710         },
12711         tablet: {
12712             min: 768,
12713             max: 1025
12714         },
12715         desktop: {
12716             min: 1025,
12717             max: 1920
12718         }
12719     }
12720 })
12721 .filter('groupBy', function ($timeout) {
12722     //Custom GroupBy Filter for treeNav, returns key string and value.childarray as set of grouped elements
12723     return function (data, key) {
12724         if (!key) return data;
12725         var outputPropertyName = '__groupBy__' + key;
12726         if (!data[outputPropertyName]) {
12727             var result = {};
12728             for (var i = 0; i < data.length; i++) {
12729                 if (!result[data[i][key]])
12730                     result[data[i][key]] = {};
12731                 if (!result[data[i][key]].childArray) {
12732                     result[data[i][key]].childArray = [];
12733                 }
12734                 result[data[i][key]].childArray.push(data[i]);
12735                 if (data[i].activeGrp && data[i].activeGrp == true) {
12736                     result[data[i][key]].showGroup = true;
12737                 }
12738             }
12739             Object.defineProperty(result, 'length', {enumerable: false,value: Object.keys(result).length});
12740             Object.defineProperty(data, outputPropertyName, {enumerable: false,configurable: true,writable:false,value:result});
12741             $timeout(function(){delete data[outputPropertyName];},0,false);
12742         }
12743         return data[outputPropertyName];
12744     };
12745 })
12746 .filter('searchObjectPropertiesFilter', [function() {
12747     return function(items, searchText, attrs) {
12748         if(!searchText){
12749             return items;
12750         }
12751         var filtered = [];
12752         searchText = searchText.toLowerCase();
12753         angular.forEach(items, function(item) {
12754             angular.forEach(attrs, function(attr) {
12755                 if (item.hasOwnProperty(attr) && (item[attr].toLowerCase().indexOf(searchText) != -1)) {
12756                     filtered.push(item);
12757                     return;
12758                 }
12759             });
12760         });
12761         return filtered;
12762     };
12763 }])
12764 .filter('unsafe',[ '$sce', function ($sce) { 
12765     return function(val){ 
12766        return $sce.trustAsHtml(val); 
12767     }; 
12768 }])
12769 .filter('b2bHighlight', function () {
12770     function escapeRegexp(queryToEscape) {
12771         return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
12772     }
12773     return function (matchItem, query, className) {
12774         return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;
12775     }
12776 })
12777 /*License (MIT)
12778 Copyright Â© 2013 Matt Diamond
12779 https://github.com/cwilso/AudioRecorder/blob/master/js/recorderjs/recorder.js
12780 */
12781 .factory('b2bRecorder', function() {
12782
12783     var Recorder = function(source, cfg) {
12784         var WORKER_PATH = 'recorderWorker.js';
12785         var config = cfg || {};
12786         var bufferLen = config.bufferLen || 4096;
12787         this.context = source.context;
12788         if(!this.context.createScriptProcessor) {
12789             this.node = this.context.createJavacriptProcessor(bufferLen, 2, 2);
12790         } else {
12791             this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
12792         }
12793         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()}};';
12794         var blob = new Blob([workerCode]);
12795
12796         var worker = new Worker(window.URL.createObjectURL(blob)); //TODO: Use a blob instead
12797         worker.postMessage({
12798             command: 'init',
12799             config: {
12800                 sampleRate: this.context.sampleRate
12801             }
12802         });
12803         var recording = false,
12804             currCallback;
12805
12806         this.node.onaudioprocess = function(e) {
12807             if (!recording) return;
12808             worker.postMessage({
12809                 command: 'record',
12810                 buffer: [
12811                     e.inputBuffer.getChannelData(0),
12812                     e.inputBuffer.getChannelData(1)
12813                 ]
12814             });
12815         };
12816
12817         this.configure = function(cfg) {
12818             for (var prop in cfg) {//TODO: look into using angular.extend() here
12819                 if (cfg.hasOwnProperty(prop)) {
12820                     config[prop] = cfg[prop];
12821                 }
12822             }
12823         };
12824
12825         this.record = function() {
12826             recording = true;
12827         };
12828
12829         this.stop = function() {
12830             recording = false;
12831         };
12832
12833         this.clear = function() {
12834             worker.postMessage({ command: 'clear' });
12835             window.URL.revokeObjectURL(blob);
12836         };
12837
12838         this.getBuffers = function(cb) {
12839             currCallback = cb || config.callback;
12840             worker.postMessage({ command: 'getBuffers' });
12841         };
12842
12843         this.exportWAV = function(cb, type) {
12844             currCallback = cb || config.callback;
12845             type = type || config.type || 'audio/wav';
12846             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
12847             worker.postMessage({
12848                 command: 'exportWAV',
12849                 type: type
12850             });
12851         };
12852
12853         this.exportMonoWAV = function(cb, type) {
12854             currCallback = cb || config.callback;
12855             type = type || config.type || 'audio/wav';
12856             if (!currCallback) throw new Error('[b2bRecorder]: Callback not set!');
12857             worker.postMessage({
12858                 command: 'exportMonoWAV',
12859                 type: type
12860             });
12861         };
12862
12863         worker.onmessage = function(e) {
12864             var blob = e.data;
12865             currCallback(blob);
12866         };
12867
12868         source.connect(this.node);
12869         this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggerd in Chrome
12870
12871     };
12872
12873     return Recorder;
12874
12875 })
12876 .factory('b2bViewport', function() {
12877   /* Source: https://gist.github.com/bjankord/2399828 */
12878   var _viewportWidth = function() {
12879     var vpw;
12880     var webkit = (!(window.webkitConvertPointFromNodeToPage == null));
12881     
12882     // Webkit:
12883     if ( webkit ) {
12884       var vpwtest = document.createElement( "div" );
12885       // Sets test div to width 100%, !important overrides any other misc. box model styles that may be set in the CSS
12886       vpwtest.style.cssText = "width:100% !important; margin:0 !important; padding:0 !important; border:none !important;";
12887       document.documentElement.insertBefore( vpwtest, document.documentElement.firstChild );
12888       vpw = vpwtest.offsetWidth;
12889       document.documentElement.removeChild( vpwtest );
12890     }
12891     // IE 6-8:
12892     else if ( window.innerWidth === undefined ) { 
12893       vpw = document.documentElement.clientWidth; 
12894     }
12895     // Other:
12896     else{
12897       vpw =  window.innerWidth;
12898     }
12899
12900     return (vpw);
12901   }
12902   return {
12903     viewportWidth: _viewportWidth
12904   };
12905 })
12906 .directive('b2bWhenScrollEnds', function(b2bWhenScrollEndsConstants, $log) {
12907     return {
12908         restrict: 'A',
12909         link: function (scope, element, attrs) {
12910             /**
12911             * Exposed Attributes:
12912             *       threshold - integer - number of pixels before scrollbar hits end that callback is called
12913             *       width - integer - override for element's width (px)
12914             *       height - integer - override for element's height (px)
12915             *       axis - string - x/y for scroll bar axis
12916             */
12917             var threshold = parseInt(attrs.threshold, 10) || b2bWhenScrollEndsConstants.threshold;
12918
12919             if (!attrs.axis || attrs.axis === '') {
12920                 $log.warn('axis attribute must be defined for b2bWhenScrollEnds.');
12921                 return;
12922             }
12923
12924             if (attrs.axis === 'x') {
12925                 visibleWidth = parseInt(attrs.width, 10) || b2bWhenScrollEndsConstants.width;
12926                 if (element.css('width')) {
12927                     visibleWidth = element.css('width').split('px')[0];  
12928                 }
12929
12930                 element[0].addEventListener('scroll', function() {
12931                     var scrollableWidth = element.prop('scrollWidth');
12932                     if (scrollableWidth === undefined) {
12933                         scrollableWidth = 1;
12934                     }
12935                     var hiddenContentWidth = scrollableWidth - visibleWidth;
12936
12937                     if (hiddenContentWidth - element[0].scrollLeft <= threshold) {
12938                         /* Scroll almost at bottom, load more rows */
12939                         scope.$apply(attrs.b2bWhenScrollEnds);
12940                     }
12941                 });
12942             } else if (attrs.axis === 'y') {
12943                 visibleHeight = parseInt(attrs.height, 10) || b2bWhenScrollEndsConstants.height;
12944                 if (element.css('width')) {
12945                     visibleHeight = element.css('height').split('px')[0]; 
12946                 }
12947
12948                 element[0].addEventListener('scroll', function() {
12949                     var scrollableHeight = element.prop('scrollHeight');
12950                     if (scrollableHeight === undefined) {
12951                         scrollableHeight = 1;
12952                     }
12953                     var hiddenContentHeight = scrollableHeight - visibleHeight;
12954
12955                     if (hiddenContentHeight - element[0].scrollTop <= threshold) {
12956                         /* Scroll almost at bottom, load more rows */
12957                         scope.$apply(attrs.b2bWhenScrollEnds);
12958                     }
12959                 });
12960             }
12961         }
12962     };
12963 })
12964
12965 .factory('$windowBind', ['$window', '$timeout', function($window, $timeout) {
12966     var win = angular.element($window);
12967     var _scroll = function (flag, callbackFunc, scope) {
12968         scope.$watch(flag, function (val) {
12969             $timeout(function () {
12970                 if (val) {
12971                     win.bind('scroll', callbackFunc);
12972                 } else {
12973                     win.unbind('scroll', callbackFunc);
12974                 }
12975             });
12976         });
12977     };
12978
12979     var throttle = function(type, name, obj) {
12980         obj = obj || window;
12981         var running = false;
12982         var func = function() {
12983             if (running) { return; }
12984             running = true;
12985              requestAnimationFrame(function() {
12986                 obj.dispatchEvent(new CustomEvent(name));
12987                 running = false;
12988             });
12989         };
12990         obj.addEventListener(type, func);
12991     };
12992
12993     var _resize = function(callbackFunc, scope) {
12994         throttle("resize", "optimizedResize");
12995         window.addEventListener("optimizedResize", function(event) {
12996             callbackFunc();
12997             //win.bind(event, callbackFunc);
12998             if (!scope.$$phase) {
12999                 scope.$digest();
13000             }
13001         });
13002     };
13003
13004     var _click = function (flag, callbackFunc, scope) {
13005         scope.$watch(flag, function (val) {
13006             $timeout(function () {
13007                 if (val) {
13008                     win.bind('click', callbackFunc);
13009                 } else {
13010                     win.unbind('click', callbackFunc);
13011                 }
13012             });
13013         });
13014     };
13015
13016     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
13017         if (timeoutFlag) {
13018             if (!(timeoutValue)) {
13019                 timeoutValue = 0;
13020             }
13021             scope.$watch(flag, function (newVal, oldVal) {
13022                 if (newVal !== oldVal) {
13023                     $timeout(function () {
13024                         if (newVal) {
13025                             win.bind(event, callbackFunc);
13026                         } else {
13027                             win.unbind(event, callbackFunc);
13028                         }
13029                     }, timeoutValue);
13030                 }
13031             });
13032         } else {
13033             scope.$watch(flag, function (newVal, oldVal) {
13034                 if (newVal !== oldVal) {
13035                     if (newVal) {
13036                         win.bind(event, callbackFunc);
13037                     } else {
13038                         win.unbind(event, callbackFunc);
13039                     }
13040                 }
13041             });
13042         }
13043     };
13044
13045     return {
13046         click: _click,
13047         scroll: _scroll,
13048         event: _event, 
13049         resize: _resize
13050     };
13051 }])
13052
13053 .factory('keymap', function () {
13054     return {
13055         KEY: {
13056             TAB: 9,
13057             ENTER: 13,
13058             ESC: 27,
13059             SPACE: 32,
13060             LEFT: 37,
13061             UP: 38,
13062             RIGHT: 39,
13063             DOWN: 40,
13064             SHIFT: 16,
13065             CTRL: 17,
13066             ALT: 18,
13067             PAGE_UP: 33,
13068             PAGE_DOWN: 34,
13069             HOME: 36,
13070             END: 35,
13071             BACKSPACE: 8,
13072             DELETE: 46,
13073             COMMAND: 91
13074         },
13075         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 : "'"
13076         },
13077         isControl: function (e) {
13078             var k = e.keyCode;
13079             switch (k) {
13080             case this.KEY.COMMAND:
13081             case this.KEY.SHIFT:
13082             case this.KEY.CTRL:
13083             case this.KEY.ALT:
13084                 return true;
13085             default:;
13086             }
13087
13088             if (e.metaKey) {
13089                 return true;
13090             }
13091
13092             return false;
13093         },
13094         isFunctionKey: function (k) {
13095             k = k.keyCode ? k.keyCode : k;
13096             return k >= 112 && k <= 123;
13097         },
13098         isVerticalMovement: function (k) {
13099             return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);
13100         },
13101         isHorizontalMovement: function (k) {
13102             return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);
13103         },
13104         isAllowedKey: function (k) {
13105             return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);
13106         },
13107         isNumericKey: function (e) {
13108             var k = e.keyCode;
13109             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105)) {
13110                 return true;
13111             } else {
13112                 return false;
13113             }
13114         },
13115         isAlphaNumericKey: function (e) {
13116             var k = e.keyCode;
13117             if ((k >= 48 && k <= 57) || (k >= 96 && k <= 105) || (k >= 65 && k <= 90)) {
13118                 return true;
13119             } else {
13120                 return false;
13121             }
13122         }
13123     };
13124 })
13125
13126 .factory('$isElement', [function () {
13127     var isElement = function (currentElem, targetElem, alternateElem) {
13128         if (currentElem[0] === targetElem[0]) {
13129             return true;
13130         } else if (currentElem[0] === alternateElem[0]) {
13131             return false;
13132         } else {
13133             return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
13134         }
13135     };
13136
13137     return isElement;
13138 }])
13139
13140 .factory('events', function () {
13141     var _stopPropagation = function (evt) {
13142         if (evt.stopPropagation) {
13143             evt.stopPropagation();
13144         } else {
13145             evt.returnValue = false;
13146         }
13147     };
13148     var _preventDefault = function (evt) {
13149         if (evt.preventDefault) {
13150             evt.preventDefault();
13151         } else {
13152             evt.returnValue = false;
13153         }
13154     }
13155     return {
13156         stopPropagation: _stopPropagation,
13157         preventDefault: _preventDefault
13158     };
13159 })
13160
13161
13162 .factory('isHighContrast', function () {
13163     var _isHighContrast = function (idval)
13164
13165
13166      {
13167         var objDiv, objImage, strColor, strWidth, strReady;
13168         var strImageID = idval; // ID of image on the page
13169
13170         // Create a test div
13171         objDiv = document.createElement('div');
13172
13173         //Set its color style to something unusual
13174         objDiv.style.color = 'rgb(31, 41, 59)';
13175
13176         // Attach to body so we can inspect it
13177         document.body.appendChild(objDiv);
13178
13179         // Read computed color value
13180         strColor = document.defaultView ? document.defaultView.getComputedStyle(objDiv, null).color : objDiv.currentStyle.color;
13181         strColor = strColor.replace(/ /g, '');
13182
13183         // Delete the test DIV
13184         document.body.removeChild(objDiv);
13185
13186         // Check if we get the color back that we set. If not, we're in
13187         // high contrast mode.
13188         if (strColor !== 'rgb(31,41,59)') {
13189             return true;
13190         } else {
13191             return false;
13192         }
13193     };
13194
13195     return _isHighContrast;
13196 })
13197
13198 .run(['isHighContrast', '$document', function (isHighContrast, $document) {
13199     var html = $document.find('html').eq(0);
13200     if (isHighContrast()) {
13201         html.addClass('ds2-no-colors');
13202     } else {
13203         html.removeClass('ds2-no-colors');
13204     }
13205 }])
13206
13207 .factory('$documentBind', ['$document', '$timeout', function ($document, $timeout) {
13208     var _click = function (flag, callbackFunc, scope) {
13209         scope.$watch(flag, function (val) {
13210             $timeout(function () {
13211                 if (val) {
13212                     $document.bind('click', callbackFunc);
13213                 } else {
13214                     $document.unbind('click', callbackFunc);
13215                 }
13216             });
13217         });
13218     };
13219
13220     var _touch = function (flag, callbackFunc, scope) {
13221         scope.$watch(flag, function (val) {
13222             $timeout(function () {
13223                 if (val) {
13224                     $document.bind('touchstart', callbackFunc);
13225                 } else {
13226                     $document.unbind('touchstart', callbackFunc);
13227                 }
13228             });
13229         });
13230     };
13231
13232     var _scroll = function (flag, callbackFunc, scope) {
13233         scope.$watch(flag, function (val) {
13234             $timeout(function () {
13235                 if (val) {
13236                     $document.bind('scroll', callbackFunc);
13237                 } else {
13238                     $document.unbind('scroll', callbackFunc);
13239                 }
13240             });
13241         });
13242     };
13243
13244     var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
13245         if (timeoutFlag) {
13246             if (!(timeoutValue)) {
13247                 timeoutValue = 0;
13248             }
13249             scope.$watch(flag, function (newVal, oldVal) {
13250                 if (newVal !== oldVal) {
13251                     $timeout(function () {
13252                         if (newVal) {
13253                             $document.bind(event, callbackFunc);
13254                         } else {
13255                             $document.unbind(event, callbackFunc);
13256                         }
13257                     }, timeoutValue);
13258                 }
13259             });
13260         } else {
13261             scope.$watch(flag, function (newVal, oldVal) {
13262                 if (newVal !== oldVal) {
13263                     if (newVal) {
13264                         $document.bind(event, callbackFunc);
13265                     } else {
13266                         $document.unbind(event, callbackFunc);
13267                     }
13268                 }
13269             });
13270         }
13271     };
13272
13273     return {
13274         click: _click,
13275         touch: _touch,
13276         scroll: _scroll,
13277         event: _event
13278     };
13279 }])
13280
13281 .directive('b2bOnlyNums', function (keymap) {
13282     return {
13283         restrict: 'A',
13284         require: 'ngModel',
13285         link: function (scope, elm, attrs, ctrl) {
13286             var maxChars = attrs.b2bOnlyNums ? attrs.b2bOnlyNums : 4;
13287             elm.on('keydown', function (event) {
13288                 if ((event.which >= 48 && event.which <= 57) || (event.which >= 96 && event.which <= 105)) {
13289                     // check for maximum characters allowed
13290                     if (elm.val().length < maxChars){
13291                         return true;
13292                     } else {
13293                         event.preventDefault();
13294                         return false;
13295                     }
13296                 } else if ([8, 9, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {
13297                     // to allow backspace, tab, enter, escape, arrows
13298                     return true;
13299                 } else if (event.altKey || event.ctrlKey) {
13300                     // to allow alter, control, and shift keys
13301                     return true;
13302                 } else {
13303                     // to stop others
13304                     event.preventDefault();
13305                     return false;
13306                 }
13307             });
13308
13309             var validateString = function (value) {
13310                 if (angular.isUndefined(value) || value === null || value === '') {
13311                     return ctrl.$modelValue;
13312                 }
13313                 return value;
13314             };
13315             ctrl.$parsers.unshift(validateString);
13316         }
13317     }
13318 })
13319
13320 .directive('b2bKeyupClick', [ function () {
13321     return {
13322         restrict: 'A',
13323         link: function (scope, elem, attr) {
13324             var keyCode = [];
13325             attr.$observe('b2bKeyupClick', function (value) {
13326                 if (value) {
13327                     keyCode = value.split(',');
13328                 }
13329             });
13330             elem.bind('keydown keyup', function (ev) {
13331                 var keyCodeCondition = function () {
13332                     var flag = false;
13333                     if (!(ev.keyCode)) {
13334                         if (ev.which) {
13335                             ev.keyCode = ev.which;
13336                         } else if (ev.charCode) {
13337                             ev.keyCode = ev.charCode;
13338                         }
13339                     }
13340                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
13341                         flag = true;
13342                     }
13343                     return flag;
13344                 };
13345                 if (ev.type === 'keydown' && keyCodeCondition()) {
13346                     ev.preventDefault();
13347                 }
13348                 else if (ev.type === 'keyup' && keyCodeCondition()) {
13349                     elem[0].click();
13350                 }
13351             });
13352         }
13353     };
13354 }])
13355
13356 .factory('b2bDOMHelper', function() {
13357
13358     var _isTabable = function(node) {
13359         var element = angular.element(node);
13360         var tagName = element[0].tagName.toUpperCase();
13361
13362         if (isHidden(element)) {
13363             return false;
13364         }
13365         if (element.attr('tabindex') !== undefined) {
13366             return (parseInt(element.attr('tabindex'), 10) >= 0);
13367         }
13368         if (tagName === 'A' || tagName === 'AREA' || tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
13369             if (tagName === 'A' || tagName === 'AREA') {
13370                 // anchors/areas without href are not focusable
13371                 return (element[0].href !== '');
13372             }
13373             return !(element[0].disabled);
13374         }
13375         return false;
13376     };
13377
13378     function isValidChild(child) {
13379         return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';
13380     }
13381     
13382     function isHidden(obj) {
13383         var elem = angular.element(obj);
13384         var elemStyle = undefined;
13385         if(obj instanceof HTMLElement){
13386             elemStyle = window.getComputedStyle(obj);
13387         }
13388         else {
13389             elemStyle = window.getComputedStyle(obj[0]);
13390         }
13391         return elem.hasClass('ng-hide') || elem.css('display') === 'none' || elemStyle.display === 'none' || elemStyle.visibility === 'hidden' || elem.css('visibility') === 'hidden';
13392     }
13393
13394     function hasValidParent(obj) {
13395         return (isValidChild(obj) && obj.parentElement.nodeName !== 'BODY');
13396     }
13397
13398     function traverse(obj, fromTop) {
13399         var obj = obj || document.getElementsByTagName('body')[0];
13400         if (isValidChild(obj) && _isTabable(obj)) {
13401             return obj;
13402         }
13403         // If object is hidden, skip it's children
13404         if (isValidChild(obj) && isHidden(obj)) {
13405             return undefined;
13406         } 
13407         // If object is hidden, skip it's children
13408         if (angular.element(obj).hasClass('ng-hide')) {
13409             return undefined;
13410         }  
13411         if (obj.hasChildNodes()) {
13412             var child;
13413             if (fromTop) {
13414                 child = obj.firstChild;
13415             } else {
13416                 child = obj.lastChild;
13417             }
13418             while(child) {
13419                 var res =  traverse(child, fromTop);
13420                 if(res){
13421                     return res;
13422                 }
13423                 else{
13424                     if (fromTop) {
13425                         child = child.nextSibling;
13426                     } else {
13427                         child = child.previousSibling;
13428                     }
13429                 }
13430             }
13431         }
13432         else{
13433             return undefined;
13434         }
13435     }
13436
13437     var _previousElement = function(el, isFocusable){
13438
13439         var elem = el;
13440         if (el.hasOwnProperty('length')) {
13441             elem = el[0];
13442         }
13443
13444         var parent = elem.parentElement;
13445         var previousElem = undefined;
13446
13447         if(isFocusable) {
13448             if (hasValidParent(elem)) {
13449                 var siblings = angular.element(parent).children();
13450                 if (siblings.length > 0) {
13451                     // Good practice to splice out the elem from siblings if there, saving some time.
13452                     // We allow for a quick check for jumping to parent first before removing. 
13453                     if (siblings[0] === elem) {
13454                         // If we are looking at immidiate parent and elem is first child, we need to go higher
13455                         var e = _previousElement(angular.element(elem).parent(), isFocusable);
13456                         if (_isTabable(e)) {
13457                             return e;
13458                         }
13459                     } else {
13460                         // I need to filter myself and any nodes next to me from the siblings
13461                         var indexOfElem = Array.prototype.indexOf.call(siblings, elem);
13462                         siblings = Array.prototype.filter.call(siblings, function(item, itemIndex) {
13463                             if (!angular.equals(elem, item) && itemIndex < indexOfElem) {
13464                                 return true;
13465                             }
13466                         });
13467                     }
13468                     // We need to search backwards
13469                     for (var i = 0; i <= siblings.length-1; i++) {//for (var i = siblings.length-1; i >= 0; i--) {
13470                         var ret = traverse(siblings[i], false);
13471                         if (ret !== undefined) {
13472                             return ret;
13473                         }
13474                     }
13475
13476                     var e = _previousElement(angular.element(elem).parent(), isFocusable);
13477                     if (_isTabable(e)) {
13478                         return e;
13479                     }
13480                 }
13481             }
13482         } else {
13483             var siblings = angular.element(parent).children();
13484             if (siblings.length > 1) {
13485                 // Since indexOf is on Array.prototype and parent.children is a NodeList, we have to use call()
13486                 var index = Array.prototype.indexOf.call(siblings, elem);
13487                 previousElem = siblings[index-1];
13488             }
13489         }
13490         return previousElem;
13491     };
13492
13493     var _lastTabableElement = function(el) {
13494         /* This will return the first tabable element from the parent el */
13495         var elem = el;
13496         if (el.hasOwnProperty('length')) {
13497             elem = el[0];
13498         }
13499
13500         return traverse(elem, false);
13501     };
13502
13503     var _firstTabableElement = function(el) {
13504         /* This will return the first tabable element from the parent el */
13505         var elem = el;
13506         if (el.hasOwnProperty('length')) {
13507             elem = el[0];
13508         }
13509
13510         return traverse(elem, true);
13511     };
13512
13513     var _isInDOM = function(obj) {
13514       return document.documentElement.contains(obj);
13515     }
13516
13517     return {
13518         firstTabableElement: _firstTabableElement,
13519         lastTabableElement: _lastTabableElement,
13520         previousElement: _previousElement,
13521         isInDOM: _isInDOM,
13522         isTabable: _isTabable,
13523         isHidden: isHidden
13524     };
13525 })
13526
13527 .factory('windowOrientation', ['$window', function ($window) {
13528     var _isPotrait = function () {
13529         if ($window.innerHeight > $window.innerWidth) {
13530             return true;
13531         } else {
13532             return false;
13533         }
13534     };
13535     var _isLandscape = function () {
13536         if ($window.innerHeight < $window.innerWidth) {
13537             return true;
13538         } else {
13539             return false;
13540         }
13541     };
13542
13543     return {
13544         isPotrait: _isPotrait,
13545         isLandscape: _isLandscape
13546     };
13547 }])
13548 .directive('b2bNextElement', function() {
13549   return {
13550     restrict: 'A',
13551     transclude: false,
13552     link: function (scope, elem, attr, ctrls) {
13553
13554         var keys = attr.b2bNextElement.split(',');
13555
13556         elem.bind('keydown', function (e) {
13557             var nextElement = elem.next();
13558             if(e.keyCode == 39 || e.keyCode == 40){ // if e.keyCode in keys
13559                 if(nextElement.length) {
13560                     e.preventDefault();
13561                     nextElement[0].focus();
13562                 }
13563             }
13564         });
13565     }
13566   }
13567 })
13568
13569 .directive('b2bAccessibilityClick', [function () {
13570     return {
13571         restrict: 'A',
13572         link: function (scope, elem, attr, ctrl) {
13573             var keyCode = [];
13574             attr.$observe('b2bAccessibilityClick', function (value) {
13575                 if (value) {
13576                     keyCode = value.split(',');
13577                 }
13578             });
13579             elem.bind('keydown keypress', function (ev) {
13580                 var keyCodeCondition = function () {
13581                     var flag = false;
13582                     if (!(ev.keyCode)) {
13583                         if (ev.which) {
13584                             ev.keyCode = ev.which; 
13585                         } else if (ev.charCode) {
13586                             ev.keyCode = ev.charCode;
13587                         }
13588                     }
13589                     if ((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)) {
13590                         flag = true;
13591                     }
13592                     return flag;
13593                 };
13594                 if (keyCode.length > 0 && keyCodeCondition()) {
13595                     elem[0].click();
13596                     ev.preventDefault();
13597                 }
13598             });
13599         }
13600     };
13601 }])
13602
13603 .directive('b2bReset', ['$compile', function ($compile) {
13604         return {
13605             restrict: 'A',
13606             require: ['?ngModel', 'b2bReset'],
13607             controller: ['$scope', function ($scope) {
13608                 var resetButton = angular.element('<button type="button" class="reset-field" tabindex="-1" aria-label="Click to reset" aria-hidden="true" role="button"></button>');
13609
13610                 this.getResetButton = function () {
13611                     return resetButton;
13612                 };
13613             }],
13614             link: function (scope, element, attrs, ctrls) {
13615
13616                 var ngModelCtrl = ctrls[0];
13617                 var ctrl = ctrls[1];
13618
13619                 var resetButton = ctrl.getResetButton();
13620
13621
13622                 resetButton.on('click', function () {
13623                     element[0].value = '';
13624
13625                     if (ngModelCtrl) {
13626                         if (attrs.b2bReset) {
13627                             ngModelCtrl.$setViewValue(attrs.b2bReset);
13628                         } else {
13629                             ngModelCtrl.$setViewValue('');
13630                         }
13631                         element[0].value = ngModelCtrl.$viewValue;
13632                         ngModelCtrl.$render();
13633                         scope.$digest();
13634                     }
13635                     element[0].focus();
13636                     element[0].select();
13637                 });
13638
13639                 var addResetButton = function () {
13640                     element.after(resetButton);
13641                     element.unbind('focus input', addResetButton);
13642                 };
13643
13644                 element.bind('focus input', addResetButton);
13645             }
13646         };
13647     }])
13648
13649 .directive('b2bPrevElement', ['b2bDOMHelper', 'keymap', function (b2bDOMHelper, keymap) {
13650   return {
13651     restrict: 'A',
13652     transclude: false,
13653     link: function (scope, elem, attr) {
13654
13655         elem.bind('keydown', function (e) {
13656             if(e.keyCode == 37 || e.keyCode == 38){
13657                 var prev = b2bDOMHelper.previousElement(elem, false);
13658                 if(prev !== undefined) {
13659                     e.preventDefault();
13660                     prev.focus();
13661                 }
13662             }
13663         });
13664     }
13665   }
13666 }])
13667 /**
13668  * @param {integer} delay - Timeout before first and last focusable elements are found
13669  * @param {boolean} trigger - A variable on scope that will trigger refinding first/last focusable elements 
13670  */
13671 .directive('b2bTrapFocusInsideElement', ['$timeout', 'b2bDOMHelper', 'keymap', 'events', function ($timeout, b2bDOMHelper, keymap, events) {
13672     return {
13673         restrict: 'A',
13674         transclude: false,
13675         link: function (scope, elem, attr) {
13676
13677             var delay = parseInt(attr.delay, 10) || 10;
13678
13679             /* Before opening modal, find the focused element */
13680             var firstTabableElement = undefined,
13681                 lastTabableElement = undefined;
13682                 
13683             function init() {
13684                 $timeout(function () {
13685                     firstTabableElement = b2bDOMHelper.firstTabableElement(elem);
13686                     lastTabableElement = b2bDOMHelper.lastTabableElement(elem);
13687                     angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
13688                     angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
13689                 }, delay, false);
13690             }
13691
13692             if (attr.trigger !== undefined) {
13693                 scope.$watch('trigger', function() {
13694                     if (scope.trigger) {
13695                         init();
13696                     }
13697                 });
13698             }
13699
13700             var firstTabableElementKeyhandler = function(e) {
13701                 if (!e.keyCode) {
13702                     e.keyCode = e.which;
13703                 }
13704                 if (e.keyCode === keymap.KEY.TAB && e.shiftKey) {
13705                     if (attr.trapFocusInsideElement === 'true') {
13706                         var temp = b2bDOMHelper.lastTabableElement(elem);
13707                         if (lastTabableElement !== temp) {
13708                             // Unbind keydown handler on lastTabableElement
13709                             angular.element(lastTabableElement).unbind('keydown', lastTabableElementKeyhandler);
13710                             lastTabableElement = temp;
13711                             angular.element(lastTabableElement).bind('keydown', lastTabableElementKeyhandler);
13712                         }
13713                     }
13714                     lastTabableElement.focus();
13715                     events.preventDefault(e);
13716                     events.stopPropagation(e);
13717                 }
13718             };
13719
13720             var lastTabableElementKeyhandler = function(e) {
13721                 if (!e.keyCode) {
13722                     e.keyCode = e.which;
13723                 }
13724                 if (e.keyCode === keymap.KEY.TAB && !e.shiftKey) {
13725                     if (attr.trapFocusInsideElement === 'true') {
13726                         var temp = b2bDOMHelper.firstTabableElement(elem);
13727                         if (firstTabableElement !== temp) {
13728                             // Unbind keydown handler on firstTabableElement
13729                             angular.element(firstTabableElement).unbind('keydown', firstTabableElementKeyhandler);
13730                             firstTabableElement = temp;
13731                             angular.element(firstTabableElement).bind('keydown', firstTabableElementKeyhandler);
13732                         }
13733                     }
13734                     firstTabableElement.focus();
13735                     events.preventDefault(e);
13736                     events.stopPropagation(e);
13737                 }
13738             };
13739
13740             init();
13741         }
13742     };
13743 }])
13744
13745 .factory('trapFocusInElement', ['$document', '$isElement', 'b2bDOMHelper', 'keymap', '$interval', function ($document, $isElement, b2bDOMHelper, keymap, $interval) {
13746     var elementStack = [];
13747     var stackHead = undefined;
13748     var stopInterval = undefined;
13749     var intervalRequired = false;
13750     var interval = 1000;
13751     var firstTabableElement, lastTabableElement;
13752
13753     var trapKeyboardFocusInFirstElement = function (e) {
13754         if (!e.keyCode) {
13755             e.keyCode = e.which;
13756         }
13757
13758         if (e.shiftKey === true && e.keyCode === keymap.KEY.TAB) {
13759             lastTabableElement[0].focus();
13760             e.preventDefault(e);
13761             e.stopPropagation(e);
13762         }
13763
13764     };
13765
13766     var trapKeyboardFocusInLastElement = function (e) {
13767         if (!e.keyCode) {
13768             e.keyCode = e.which;
13769         }
13770
13771         if (e.shiftKey === false && e.keyCode === keymap.KEY.TAB) {
13772             firstTabableElement[0].focus();
13773             e.preventDefault(e);
13774             e.stopPropagation(e);
13775         }
13776     };
13777
13778     var trapFocusInElement = function (flag, firstTabableElementParam, lastTabableElementParam) {
13779         var bodyElements = $document.find('body').children();
13780
13781         firstTabableElement = firstTabableElementParam ? firstTabableElementParam : angular.element(b2bDOMHelper.firstTabableElement(stackHead));
13782         lastTabableElement = lastTabableElementParam ? lastTabableElementParam : angular.element(b2bDOMHelper.lastTabableElement(stackHead));
13783
13784         if (flag) {
13785             for (var i = 0; i < bodyElements.length; i++) {
13786                 if (bodyElements[i] !== stackHead[0]) {
13787                     bodyElements.eq(i).attr('aria-hidden', true);
13788                 }
13789             }
13790             firstTabableElement.bind('keydown', trapKeyboardFocusInFirstElement);
13791             lastTabableElement.bind('keydown', trapKeyboardFocusInLastElement);
13792         } else {
13793             for (var j = 0; j < bodyElements.length; j++) {
13794                 if (bodyElements[j] !== stackHead[0]) {
13795                     bodyElements.eq(j).removeAttr('aria-hidden');
13796                 }
13797             }
13798             firstTabableElement.unbind('keydown', trapKeyboardFocusInFirstElement);
13799             lastTabableElement.unbind('keydown', trapKeyboardFocusInLastElement);
13800         }
13801
13802         if (intervalRequired && flag) {
13803             stopInterval = $interval(function () {
13804                 var firstTabableElementTemp = angular.element(b2bDOMHelper.firstTabableElement(stackHead));
13805                 var lastTabableElementTemp = angular.element(b2bDOMHelper.lastTabableElement(stackHead));
13806                 if (firstTabableElementTemp[0] !== firstTabableElement[0] || lastTabableElementTemp[0] !== lastTabableElement[0]) {
13807                     $interval.cancel(stopInterval);
13808                     stopInterval = undefined;
13809                     trapFocusInElement(false, firstTabableElement, lastTabableElement);
13810                     trapFocusInElement(true, firstTabableElementTemp, lastTabableElementTemp);
13811                 }
13812             }, interval);
13813         } else {
13814             if (stopInterval) {
13815                 $interval.cancel(stopInterval);
13816                 stopInterval = undefined;
13817             }
13818         }
13819     };
13820     var toggleTrapFocusInElement = function (flag, element, intervalRequiredParam, intervalParam) {
13821         intervalRequired = intervalRequiredParam ? intervalRequiredParam : intervalRequired;
13822         interval = intervalParam ? intervalParam : interval;
13823         if (angular.isDefined(flag) && angular.isDefined(element)) {
13824             if (flag && angular.isUndefined(stackHead)) {
13825                 stackHead = element;
13826                 trapFocusInElement(flag);
13827             } else {
13828                 if (flag) {
13829                     trapFocusInElement(false);
13830                     elementStack.push(stackHead);
13831                     stackHead = element;
13832                     trapFocusInElement(true);
13833                 } else {
13834                     if (angular.isDefined(stackHead) && (stackHead[0] === element[0])) {
13835                         trapFocusInElement(false);
13836                         stackHead = elementStack.pop();
13837                         if (angular.isDefined(stackHead)) {
13838                             trapFocusInElement(true);
13839                         }
13840                     }
13841                 }
13842             }
13843         } else {
13844             if (angular.isDefined(stackHead)) {
13845                 trapFocusInElement(false, firstTabableElement, lastTabableElement);
13846                 trapFocusInElement(true);
13847             }
13848         }
13849     };
13850
13851     return toggleTrapFocusInElement;
13852 }])
13853 .factory('draggedElement', function(){
13854     var draggedElement;
13855     return {
13856         setElement: function(data){
13857             draggedElement = data;
13858         },
13859         getElement: function(){
13860             return draggedElement;
13861         }
13862     }
13863 })
13864
13865 .directive('draggable', ['draggedElement',function (draggedElement) { 
13866     return function(scope, element) { 
13867  
13868       element[0].draggable = true; 
13869  
13870       element.bind('dragstart', function(e) {
13871         draggedElement.setElement(this.parentElement.parentElement); 
13872         e.dataTransfer.effectAllowed = 'move'; 
13873         e.dataTransfer.setDragImage(this.parentElement.parentElement, 0, 0); 
13874         this.parentElement.parentElement.classList.add('b2-drag-element');
13875         return false; 
13876       }); 
13877  
13878       element.bind('dragend', function(e) { 
13879         draggedElement.setElement(e); 
13880         this.parentElement.parentElement.classList.remove('b2-drag-element'); 
13881         return false; 
13882       });
13883     }; 
13884 }]) 
13885  
13886 .directive('droppable', ['draggedElement',function (draggedElement) { 
13887     return { 
13888         restrict: 'EA', 
13889         replace: true, 
13890         scope: { 
13891           rowData: '=' 
13892         }, 
13893         link: function(scope, element, attr) {
13894             if(attr.droppable === 'true') {
13895               element.bind('dragover', function(e) { 
13896                 e.dataTransfer.dropEffect = 'move'; 
13897                 this.classList.add('b2b-drag-over') 
13898                 if (e.preventDefault) e.preventDefault(); // allows us to drop 
13899                 return false; 
13900               }); 
13901
13902               element.bind('dragstart', function(e) {
13903                 if(!e.target.parentElement.classList.contains('b2b-draggable')) {
13904                     e.preventDefault();
13905                     return false;
13906                 }
13907               }); 
13908
13909               element.bind('dragenter', function(e) { 
13910                 if(e.target.getAttribute('droppable') ==='true') {
13911                     this.click();
13912                 }
13913               });
13914
13915               element.bind('dragleave', function(e) { 
13916                 this.classList.remove('b2b-drag-over'); 
13917                 return false; 
13918               });
13919
13920               element.bind('drop', function(e) { 
13921                 var ele = draggedElement.getElement();
13922                 if (e.stopPropagation) e.stopPropagation(); 
13923                 if (e.preventDefault) e.preventDefault(); 
13924                 this.classList.remove('b2b-drag-over'); 
13925
13926                 if(ele && ele.hasAttribute('data-index')){
13927                     var element = scope.rowData[parseInt(ele.getAttribute('data-index'))]; 
13928                     if(element !== undefined) { 
13929                         scope.rowData.splice(parseInt(ele.getAttribute('data-index')), 1); 
13930                         scope.rowData.splice(parseInt(e.currentTarget.getAttribute('data-index')), 0 , element); 
13931                     }
13932                 }
13933                 scope.$apply(); 
13934      
13935                 return false; 
13936               }); 
13937           }
13938         } 
13939     } 
13940 }])
13941 .directive('b2bSetNextFocusOn', ['b2bDOMHelper', '$timeout', function(b2bDOMHelper, $timeout) {
13942     return {
13943         restrict: 'A',
13944         scope: true,
13945         link: function (scope, elem, attr) {
13946             elem.bind('click', function(){
13947                 var firstFocusableElement = undefined; 
13948                 var containerElem = undefined; 
13949                 var containerArray = [];
13950                 var timeout = parseInt(attr.setNextFocusTimeout, 0) | 100;
13951                 var index = parseInt(attr.b2bSetNextFocusIndex, 0) | 0;
13952
13953                                  /*
13954                                   *Fix for IE7 and lower 
13955                                   *polyfill src: https://github.com/HubSpot/pace/issues/102
13956                                   */
13957                                 if (!document.querySelectorAll) {
13958                                         document.querySelectorAll = function (selectors) {
13959                                                 var style = document.createElement('style'), elements = [], element;
13960                                                 document.documentElement.firstChild.appendChild(style);
13961                                                 document._qsa = [];
13962
13963                                                 style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
13964                                                 window.scrollBy(0, 0);
13965                                                 style.parentNode.removeChild(style);
13966
13967                                                 while (document._qsa.length) {
13968                                                         element = document._qsa.shift();
13969                                                         element.style.removeAttribute('x-qsa');
13970                                                         elements.push(element);
13971                                                 }
13972                                                 document._qsa = null;
13973                                                 return elements;
13974                                         };
13975                                 }
13976
13977                 if (attr.b2bSetNextFocusOn === '') {
13978                     return;
13979                 } else {
13980                     containerArray = attr.b2bSetNextFocusOn.split(' ');
13981                 }
13982                 $timeout(function(){
13983                     var i = 0;
13984                     do { // cycles thru containerArray until finds a match in DOM to set focus to
13985                         containerElem = document.querySelectorAll(containerArray[i])[index]; 
13986                         i++;
13987                     } while ( (!containerElem) && (i < containerArray.length) );
13988                     if(containerElem){
13989                         if (!angular.isDefined(firstFocusableElement)) { 
13990                             firstFocusableElement = b2bDOMHelper.firstTabableElement(containerElem); 
13991                         }
13992                         firstFocusableElement.focus(); 
13993                     }
13994                 }, timeout, false)
13995             });
13996         }
13997
13998     };
13999 }])
14000
14001 .directive('b2bInputAllow', [function() {
14002     return {
14003         restrict: 'A',
14004         require: 'ngModel',
14005         link: function (scope, elem, attr, ctrl) {
14006             var regexExpression = null;
14007             attr.$observe('b2bInputAllow', function (value) {
14008                 if (value) {
14009                     regexExpression = new RegExp(value);
14010                 }
14011             });
14012             var isValid = function(str) {
14013                 if (regexExpression !== null) {
14014                     return regexExpression.test(str);
14015                 }
14016                 return false;
14017             };
14018             elem.bind('keypress', function($event) {
14019                 var charcode = String.fromCharCode($event.which || $event.keyCode);
14020                 if (!isValid(charcode)) {
14021                     $event.preventDefault();
14022                     $event.stopPropagation();
14023                 }
14024             });
14025             elem.bind('input', function (evt) {
14026                 var inputString = ctrl.$viewValue;
14027                 if (isValid(inputString)) {
14028                     ctrl.$setViewValue(inputString);
14029                     ctrl.$render();
14030                     scope.$apply();
14031                 }
14032             });
14033         }
14034     };
14035 }])
14036
14037 .directive('b2bInputDeny', [function() {
14038     return {
14039         restrict: 'A',
14040         require: 'ngModel',
14041         link: function (scope, elem, attr, ctrl) {
14042             var regexExpression = null;
14043             attr.$observe('b2bInputDeny', function (value) {
14044                 if (value) {
14045                     regexExpression = new RegExp(value, 'g');
14046                 }
14047             });
14048             elem.bind('input', function () {
14049                 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');
14050                 if (inputString !== ctrl.$viewValue) {
14051                     ctrl.$setViewValue(inputString);
14052                     ctrl.$render();
14053                     scope.$apply();
14054                 }
14055             });
14056         }
14057     };
14058 }])
14059
14060 .directive('b2bDragonInput', [function() {
14061     return {
14062         restrict: 'A',
14063         require: 'ngModel',
14064         link: function (scope, elem, attr, ctrl) {
14065             elem.on('focus keyup', function(){
14066                 elem.triggerHandler('change');
14067             });
14068         }
14069     };
14070 }])
14071
14072 .directive('b2bKey', ['b2bUtilitiesConfig', '$timeout', 'keymap', function (b2bUtilitiesConfig, $timeout, keymap) {
14073     return {
14074         restrict: 'EA',
14075         controller: ['$scope', '$element', '$attrs', function ($scope, $element,attr) {
14076             this.childElements = [];
14077             this.disableNodes = {};
14078             this.enableSearch = attr.enableSearch !== undefined ? true : b2bUtilitiesConfig.enableSearch;
14079             this.circularTraversal = attr.circularTraversal !== undefined ? true : b2bUtilitiesConfig.circularTraversal;
14080             this.counter = -1;
14081             if (this.enableSearch) {
14082                 this.searchKeys = [];
14083             }
14084             var searchString = '';
14085
14086             var selfCtrl = this;
14087
14088             this.childElementsList = [];
14089
14090             this.b2bKeyID = "";
14091
14092             if (angular.isDefined(attr.b2bKey)) {
14093                 this.b2bKeyID = attr.b2bKey;
14094             }
14095
14096             this.calculateChildElementsList = function () {
14097                 return $element[0].querySelectorAll("[b2b-key-item='" + this.b2bKeyID + "']:not([disabled])");
14098             };
14099
14100             this.resetChildElementsList = function () {
14101                 return $timeout(function () {
14102                     selfCtrl.childElementsList = selfCtrl.calculateChildElementsList();
14103                 });
14104             };
14105
14106             this.resetChildElementsList();
14107
14108             $scope.$on('b2b-key-reset-child-elements-list', function () {
14109                 selfCtrl.resetChildElementsList();
14110             });
14111
14112
14113             this.registerElement = function (childElement, searchKey) {
14114                 this.childElements.push(childElement);
14115                 if (this.enableSearch) {
14116                     this.searchKeys.push(searchKey);
14117                 }
14118                 var count = this.childElements.length - 1;
14119                 this.maxLength = count + 1;
14120                 return count;
14121             };
14122             this.toggleDisable = function (count, state) {
14123                 this.disableNodes[count] = state;
14124             };
14125             this.searchElement = function (searchExp) {
14126                 var regex = new RegExp("\\b" + searchExp, "gi");
14127                 var position = this.searchKeys.regexIndexOf(regex, this.counter + 1, true);
14128                 if (position > -1) {
14129                     this.counter = position;
14130                     this.moveFocus(this.counter);
14131                 }
14132             };
14133             this.startTimer = function (time) {
14134                 if (searchString === '') {
14135                     $timeout(function () {
14136                         searchString = '';
14137                     }, time);
14138                 }
14139             };
14140             this.resetCounter = function (count) {
14141                 this.counter = count;
14142             };
14143             this.moveNext = function (count) {
14144                 this.counter = (this.counter + count) < this.maxLength ? this.counter + count : (this.circularTraversal ? 0 : this.counter);
14145                 if (this.disableNodes[this.counter]) {
14146                     if ((this.counter + count) < this.maxLength) {
14147                         this.moveNext(count);
14148                     }
14149                 } else {
14150                     this.moveFocus(this.counter);
14151                 }
14152             };
14153             this.movePrev = function (count) {
14154                 this.counter = (this.counter - count) > -1 ? this.counter - count : (this.circularTraversal ? this.maxLength-1 : this.counter);
14155                 if (this.disableNodes[this.counter]) {
14156                     if ((this.counter - count) > -1) {
14157                         this.movePrev(count);
14158                     }
14159                 } else {
14160                     this.moveFocus(this.counter);
14161                 }
14162             };
14163             this.moveFocus = function (index) {
14164                 this.childElements[index][0].focus();
14165             };
14166
14167             this.keyDownHandler = function (ev, count) {
14168                 if (angular.isDefined(count) && !isNaN(count) && count !== this.counter) {
14169                     this.resetCounter(count);
14170                 }
14171                 if (!ev.keyCode) {
14172                     if (ev.which) {
14173                         ev.keyCode = ev.which;
14174                     } else if (ev.charCode) {
14175                         ev.keyCode = ev.charCode;
14176                     }
14177                 }
14178                 if (ev.keyCode) {
14179                     if (this.prev && this.prev.indexOf(ev.keyCode.toString()) > -1) {
14180                         this.movePrev(1);
14181                         ev.preventDefault();
14182                         ev.stopPropagation();
14183                     } else if (this.next && this.next.indexOf(ev.keyCode.toString()) > -1) {
14184                         this.moveNext(1);
14185                         ev.preventDefault();
14186                         ev.stopPropagation();
14187                     } else if (this.up && this.up.indexOf(ev.keyCode.toString()) > -1) {
14188                         if (this.type === 'table') {
14189                             this.movePrev(this.columns);
14190                             ev.preventDefault();
14191                             ev.stopPropagation();
14192                         }
14193                     } else if (this.down && this.down.indexOf(ev.keyCode.toString()) > -1) {
14194                         if (this.type === 'table') {
14195                             this.moveNext(this.columns);
14196                             ev.preventDefault();
14197                             ev.stopPropagation();
14198                         }
14199                     } else if (ev.keyCode === keymap.KEY.HOME) {
14200                         var firstIndex = 0;
14201                         while (this.disableNodes[firstIndex] !== false) {
14202                             firstIndex++;
14203                         };
14204                         var count = this.counter - firstIndex;
14205                         this.movePrev(count);
14206                         ev.preventDefault();
14207                         ev.stopPropagation();
14208                     } else if (ev.keyCode === keymap.KEY.END) {
14209                         var lastIndex = this.childElements.length - 1;
14210                         while (this.disableNodes[lastIndex] !== false) {
14211                             lastIndex--;
14212                         };
14213                         var count = lastIndex - this.counter;
14214                         this.moveNext(count);
14215                         ev.preventDefault();
14216                         ev.stopPropagation();
14217                     } else if (ev.keyCode >= 48 && ev.keyCode <= 105) {
14218                         if (this.enableSearch) {
14219                             this.startTimer(b2bUtilitiesConfig.searchTimer);
14220                             searchString = searchString + (keymap.MAP[ev.keyCode] || '');
14221                             this.searchElement(searchString);
14222                             ev.preventDefault();
14223                             ev.stopPropagation();
14224                         }
14225                     }
14226                 }
14227             };
14228         }],
14229         link: function (scope, elem, attr, ctrl) {
14230             ctrl.prev = attr.prev ? attr.prev.split(',') : b2bUtilitiesConfig.prev.split(',');
14231             ctrl.next = attr.next ? attr.next.split(',') : b2bUtilitiesConfig.next.split(',');
14232             ctrl.type = attr.type ? attr.type : b2bUtilitiesConfig.type;
14233             if (ctrl.type === 'table') {
14234                 ctrl.up = attr.up ? attr.up.split(',') : b2bUtilitiesConfig.up.split(',');
14235                 ctrl.down = attr.down ? attr.down.split(',') : b2bUtilitiesConfig.down.split(',');
14236                 ctrl.columns = attr.columns ? parseInt(attr.columns, 10) : b2bUtilitiesConfig.columns;
14237             }
14238
14239             elem.bind('keydown', function (ev) {
14240                 ctrl.keyDownHandler(ev);
14241             });
14242         }
14243     };
14244 }])
14245
14246 .directive('b2bKeyItem', [function () {
14247     return {
14248         restrict: 'EA',
14249         link: function (scope, elem, attr, ctrl) {
14250             var parentCtrl = (elem.parent() && elem.parent().controller('b2bKey')) || undefined;
14251             if (angular.isDefined(parentCtrl)) {
14252                 var count = parentCtrl.registerElement(elem, attr.searchKey);
14253                 elem.bind('keydown', function (ev) {
14254                     parentCtrl.keyDownHandler(ev, count);
14255                 });
14256                 scope.$watch(attr.b2bKeyItem, function (value) {
14257                     value = value === undefined ? true : value;
14258                     parentCtrl.toggleDisable(count, !value); 
14259                 });
14260                 scope.$on('$destroy', function () {
14261                     parentCtrl.toggleDisable(count, true);
14262                 });
14263             }
14264         }
14265     };
14266 }])
14267
14268 .directive('b2bElementFocus', [function () {
14269     return {
14270         restrict: 'A',
14271         link: function (scope, elem, attr, ctrl) {
14272             scope.$watch(attr.b2bElementFocus, function (value) {
14273                 if (value === true) {
14274                     elem[0].focus();
14275                 }
14276             });
14277         }
14278     };
14279 }])
14280
14281
14282 .directive('b2bAppendElement', ['$compile', function ($compile) {
14283     return {
14284         restrict: 'A',
14285         link: function (scope, elem, attr, ctrl) {
14286             var parameters = attr.b2bAppendElement.split(':');
14287             if (parameters.length === 1) {
14288                 elem.append(scope.$eval(parameters[0]));
14289             } else if (parameters.length === 2) {
14290                 if (parameters[1] === 'compile') {
14291                     var element = angular.element('<span>' + scope.$eval(parameters[0]) + '</span>');
14292                     elem.append($compile(element)(scope));
14293                 }
14294             }
14295
14296         }
14297     };
14298 }])
14299
14300 .directive('b2bKeyItemRefreshInNgRepeat', [function () {
14301     return {
14302         restrict: 'EA',
14303         require: '^^b2bKey',
14304         link: function (scope, elem, attr, parentCtrl) {
14305             if (angular.isDefined(parentCtrl)) {
14306
14307                 var attrToObserve = 'attrToObserve';
14308
14309                 if (attr.b2bKeyItemRefreshInNgRepeat) {
14310                     attrToObserve = 'b2bKeyItemRefreshInNgRepeat';
14311                 }
14312
14313                 attr.$observe(attrToObserve, function (newVal, oldVal) {
14314                     if (newVal && newVal !== oldVal) {
14315                         parentCtrl.resetChildElementsList();
14316                     }
14317                 });
14318             }
14319         }
14320     };
14321 }])
14322
14323 .constant('b2bMaskConfig', {
14324     maskDefinitions: {
14325         '9': /\d/,
14326         'A': /[a-zA-Z]/,
14327         '*': /[a-zA-Z0-9]/
14328     },
14329     clearOnBlur: false,
14330     clearOnBlurPlaceholder: false,
14331     escChar: '\\',
14332     eventsToHandle: ['input', 'keyup', 'click', 'focus'],
14333     addDefaultPlaceholder: true,
14334     allowInvalidValue: true
14335 })
14336 /**
14337  * @param {boolean} modelViewValue - If this is set to true, then the model value bound with ng-model will be the same as the $viewValue meaning it will contain any static mask characters present in the mask definition. This will not set the model value to a $viewValue that is considered invalid.
14338  * @param {String} maskPlaceholder - Allows customizing the mask placeholder when a user has focused the input element and while typing in their value
14339  * @param {String} maskPlaceholderChar - Allows customizing the mask placeholder character. The default mask placeholder is _.
14340  * @param {boolean} addDefaultPlaceholder - The default placeholder is constructed from the ui-mask definition so a mask of 999-9999 would have a default placeholder of ___-____; unless you have overridden the default placeholder character.
14341  */
14342 .directive('b2bMask', ['b2bMaskConfig', function(b2bMaskConfig) {
14343     return {
14344         require: 'ngModel',
14345         restrict: 'A',
14346         link: function(scope, element, attrs, ctrl) {
14347             var maskProcessed = false, eventsBound = false,
14348                 maskCaretMap, maskPatterns, maskPlaceholder, maskComponents,
14349                 // Minimum required length of the value to be considered valid
14350                 minRequiredLength,
14351                 value, valueMasked, isValid,
14352                 // Vars for initializing/uninitializing
14353                 originalPlaceholder = attrs.placeholder,
14354                 originalMaxlength = attrs.maxlength,
14355                 // Vars used exclusively in eventHandler()
14356                 oldValue, oldValueUnmasked, oldCaretPosition, oldSelectionLength,
14357                 // Used for communicating if a backspace operation should be allowed between
14358                 // keydownHandler and eventHandler
14359                 preventBackspace;
14360
14361             var options = b2bMaskConfig;
14362
14363             function isFocused (elem) {
14364               return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
14365             }
14366
14367             var originalIsEmpty = ctrl.$isEmpty;
14368             ctrl.$isEmpty = function(value) {
14369                 if (maskProcessed) {
14370                     return originalIsEmpty(unmaskValue(value || ''));
14371                 } else {
14372                     return originalIsEmpty(value);
14373                 }
14374             };
14375
14376             function initialize(maskAttr) {
14377                 if (!angular.isDefined(maskAttr)) {
14378                     return uninitialize();
14379                 }
14380                 processRawMask(maskAttr);
14381                 if (!maskProcessed) {
14382                     return uninitialize();
14383                 }
14384                 initializeElement();
14385                 bindEventListeners();
14386                 return true;
14387             }
14388
14389             function initPlaceholder(placeholderAttr) {
14390                 if ( ! placeholderAttr) {
14391                     return;
14392                 }
14393                 maskPlaceholder = placeholderAttr;
14394                 /* If the mask is processed, then we need to update the value
14395                    but don't set the value if there is nothing entered into the element
14396                    and there is a placeholder attribute on the element because that
14397                    will only set the value as the blank maskPlaceholder
14398                    and override the placeholder on the element */
14399                 if (maskProcessed && !(element.val().length === 0 && angular.isDefined(attrs.placeholder))) {
14400                     element.val(maskValue(unmaskValue(element.val())));
14401                 }
14402             }
14403
14404             function initPlaceholderChar() {
14405                 return initialize(attrs.uiMask);
14406             }
14407
14408             var modelViewValue = false;
14409
14410             attrs.$observe('modelViewValue', function(val) {
14411                 if (val === 'true') {
14412                     modelViewValue = true;
14413                 }
14414             });
14415
14416             attrs.$observe('allowInvalidValue', function(val) {
14417                 linkOptions.allowInvalidValue = val === ''? true : !!val;
14418                 formatter(ctrl.$modelValue);
14419             });
14420
14421             function formatter(fromModelValue) {
14422                 if (!maskProcessed) {
14423                     return fromModelValue;
14424                 }
14425                 value = unmaskValue(fromModelValue || '');
14426                 isValid = validateValue(value);
14427                 ctrl.$setValidity('mask', isValid);
14428
14429                 if (!value.length) return undefined;
14430                 if (isValid || linkOptions.allowInvalidValue) {
14431                     return maskValue(value);
14432                 } else {
14433                     return undefined;
14434                 }
14435             }
14436
14437             function parser(fromViewValue) {
14438                 if (!maskProcessed) {
14439                     return fromViewValue;
14440                 }
14441                 value = unmaskValue(fromViewValue || '');
14442                 isValid = validateValue(value);
14443                 /* We have to set viewValue manually as the reformatting of the input
14444                    value performed by eventHandler() doesn't happen until after
14445                    this parser is called, which causes what the user sees in the input
14446                    to be out-of-sync with what the ctrl's $viewValue is set to. */
14447                 ctrl.$viewValue = value.length ? maskValue(value) : '';
14448                 ctrl.$setValidity('mask', isValid);
14449
14450                 if (isValid || linkOptions.allowInvalidValue) {
14451                     return modelViewValue ? ctrl.$viewValue : value;
14452                 }
14453             }
14454
14455             var linkOptions = {};
14456
14457             // to do 
14458             if (attrs.b2bMaskOptions) {
14459                 linkOptions = scope.$eval('[' + attrs.b2bMaskOptions + ']');
14460                 if (angular.isObject(linkOptions[0])) {
14461                     // we can't use angular.copy nor angular.extend, they lack the power to do a deep merge
14462                     linkOptions = (function(original, current) {
14463                         for (var i in original) {
14464                             if (Object.prototype.hasOwnProperty.call(original, i)) {
14465                                 if (current[i] === undefined) {
14466                                     current[i] = angular.copy(original[i]);
14467                                 } else {
14468                                     if (angular.isObject(current[i]) && !angular.isArray(current[i])) {
14469                                         current[i] = angular.extend({}, original[i], current[i]);
14470                                     }
14471                                 }
14472                             }
14473                         }
14474                         return current;
14475                     })(options, linkOptions[0]);
14476                 } else {
14477                     linkOptions = options;  //gotta be a better way to do this..
14478                 }
14479             } else {
14480                 linkOptions = options;
14481             }
14482
14483             attrs.$observe('b2bMask', initialize);
14484             if (angular.isDefined(attrs.maskPlaceholder)) {
14485                 attrs.$observe('maskPlaceholder', initPlaceholder);
14486             }
14487             else {
14488                 attrs.$observe('placeholder', initPlaceholder);
14489             }
14490             if (angular.isDefined(attrs.maskPlaceholderChar)) {
14491                 attrs.$observe('maskPlaceholderChar', initPlaceholderChar);
14492             }
14493
14494             ctrl.$formatters.unshift(formatter);
14495             ctrl.$parsers.unshift(parser);
14496
14497             function uninitialize() {
14498                 maskProcessed = false;
14499                 unbindEventListeners();
14500
14501                 if (angular.isDefined(originalPlaceholder)) {
14502                     element.attr('placeholder', originalPlaceholder);
14503                 } else {
14504                     element.removeAttr('placeholder');
14505                 }
14506
14507                 if (angular.isDefined(originalMaxlength)) {
14508                     element.attr('maxlength', originalMaxlength);
14509                 } else {
14510                     element.removeAttr('maxlength');
14511                 }
14512
14513                 element.val(ctrl.$modelValue);
14514                 ctrl.$viewValue = ctrl.$modelValue;
14515                 return false;
14516             }
14517
14518             function initializeElement() {
14519                 value = oldValueUnmasked = unmaskValue(ctrl.$modelValue || '');
14520                 valueMasked = oldValue = maskValue(value);
14521                 isValid = validateValue(value);
14522                 if (attrs.maxlength) { // Double maxlength to allow pasting new val at end of mask
14523                     element.attr('maxlength', maskCaretMap[maskCaretMap.length - 1] * 2);
14524                 }
14525                 if ( ! originalPlaceholder && linkOptions.addDefaultPlaceholder) {
14526                     element.attr('placeholder', maskPlaceholder);
14527                 }
14528                 var viewValue = ctrl.$modelValue;
14529                 var idx = ctrl.$formatters.length;
14530                 while(idx--) {
14531                     viewValue = ctrl.$formatters[idx](viewValue);
14532                 }
14533                 ctrl.$viewValue = viewValue || '';
14534                 ctrl.$render();
14535             }
14536
14537             function bindEventListeners() {
14538                 if (eventsBound) {
14539                     return;
14540                 }
14541                 element.bind('blur', blurHandler);
14542                 element.bind('mousedown mouseup', mouseDownUpHandler);
14543                 element.bind('keydown', keydownHandler);
14544                 element.bind(linkOptions.eventsToHandle.join(' '), eventHandler);
14545                 eventsBound = true;
14546             }
14547
14548             function unbindEventListeners() {
14549                 if (!eventsBound) {
14550                     return;
14551                 }
14552                 element.unbind('blur', blurHandler);
14553                 element.unbind('mousedown', mouseDownUpHandler);
14554                 element.unbind('mouseup', mouseDownUpHandler);
14555                 element.unbind('keydown', keydownHandler);
14556                 element.unbind('input', eventHandler);
14557                 element.unbind('keyup', eventHandler);
14558                 element.unbind('click', eventHandler);
14559                 element.unbind('focus', eventHandler);
14560                 eventsBound = false;
14561             }
14562
14563             function validateValue(value) {
14564                 // Zero-length value validity is ngRequired's determination
14565                 return value.length ? value.length >= minRequiredLength : true;
14566             }
14567
14568              function unmaskValue(value) {
14569                 var valueUnmasked = '',
14570                     input = element[0],
14571                     maskPatternsCopy = maskPatterns.slice(),
14572                     selectionStart = oldCaretPosition,
14573                     selectionEnd = selectionStart + getSelectionLength(input),
14574                     valueOffset, valueDelta, tempValue = '';
14575                 // Preprocess by stripping mask components from value
14576                 value = value.toString();
14577                 valueOffset = 0;
14578                 valueDelta = value.length - maskPlaceholder.length;
14579                 angular.forEach(maskComponents, function(component) {
14580                     var position = component.position;
14581                     //Only try and replace the component if the component position is not within the selected range
14582                     //If component was in selected range then it was removed with the user input so no need to try and remove that component
14583                     if (!(position >= selectionStart && position < selectionEnd)) {
14584                         if (position >= selectionStart) {
14585                             position += valueDelta;
14586                         }
14587                         if (value.substring(position, position + component.value.length) === component.value) {
14588                             tempValue += value.slice(valueOffset, position);// + value.slice(position + component.value.length);
14589                             valueOffset = position + component.value.length;
14590                         }
14591                     }
14592                 });
14593                 value = tempValue + value.slice(valueOffset);
14594                 angular.forEach(value.split(''), function(chr) {
14595                     if (maskPatternsCopy.length && maskPatternsCopy[0].test(chr)) {
14596                         valueUnmasked += chr;
14597                         maskPatternsCopy.shift();
14598                     }
14599                 });
14600
14601                 return valueUnmasked;
14602             }
14603
14604             function maskValue(unmaskedValue) {
14605                 var valueMasked = '',
14606                         maskCaretMapCopy = maskCaretMap.slice();
14607
14608                 angular.forEach(maskPlaceholder.split(''), function(chr, i) {
14609                     if (unmaskedValue.length && i === maskCaretMapCopy[0]) {
14610                         valueMasked += unmaskedValue.charAt(0) || '_';
14611                         unmaskedValue = unmaskedValue.substr(1);
14612                         maskCaretMapCopy.shift();
14613                     }
14614                     else {
14615                         valueMasked += chr;
14616                     }
14617                 });
14618                 return valueMasked;
14619             }
14620
14621             function getPlaceholderChar(i) {
14622                 var placeholder = angular.isDefined(attrs.uiMaskPlaceholder) ? attrs.uiMaskPlaceholder : attrs.placeholder,
14623                     defaultPlaceholderChar;
14624
14625                 if (angular.isDefined(placeholder) && placeholder[i]) {
14626                     return placeholder[i];
14627                 } else {
14628                     defaultPlaceholderChar = angular.isDefined(attrs.uiMaskPlaceholderChar) && attrs.uiMaskPlaceholderChar ? attrs.uiMaskPlaceholderChar : '_';
14629                     return (defaultPlaceholderChar.toLowerCase() === 'space') ? ' ' : defaultPlaceholderChar[0];
14630                 }
14631             }
14632
14633             /* Generate array of mask components that will be stripped from a masked value
14634                before processing to prevent mask components from being added to the unmasked value.
14635                E.g., a mask pattern of '+7 9999' won't have the 7 bleed into the unmasked value. */
14636             function getMaskComponents() {
14637                 var maskPlaceholderChars = maskPlaceholder.split(''),
14638                         maskPlaceholderCopy, components;
14639
14640                 /* maskCaretMap can have bad values if the input has the ui-mask attribute implemented as an obversable property, e.g. the demo page */
14641                 if (maskCaretMap && !isNaN(maskCaretMap[0])) {
14642                     /* Instead of trying to manipulate the RegEx based on the placeholder characters
14643                        we can simply replace the placeholder characters based on the already built
14644                        maskCaretMap to underscores and leave the original working RegEx to get the proper
14645                        mask components */
14646                     angular.forEach(maskCaretMap, function(value) {
14647                         maskPlaceholderChars[value] = '_';
14648                     });
14649                 }
14650                 maskPlaceholderCopy = maskPlaceholderChars.join('');
14651                 components = maskPlaceholderCopy.replace(/[_]+/g, '_').split('_');
14652                 components = components.filter(function(s) {
14653                     return s !== '';
14654                 });
14655
14656                 /* need a string search offset in cases where the mask contains multiple identical components
14657                    E.g., a mask of 99.99.99-999.99 */
14658                 var offset = 0;
14659                 return components.map(function(c) {
14660                     var componentPosition = maskPlaceholderCopy.indexOf(c, offset);
14661                     offset = componentPosition + 1;
14662                     return {
14663                         value: c,
14664                         position: componentPosition
14665                     };
14666                 });
14667             }
14668
14669             function processRawMask(mask) {
14670                 var characterCount = 0;
14671
14672                 maskCaretMap = [];
14673                 maskPatterns = [];
14674                 maskPlaceholder = '';
14675
14676                 if (angular.isString(mask)) {
14677                     minRequiredLength = 0;
14678
14679                     var isOptional = false,
14680                             numberOfOptionalCharacters = 0,
14681                             splitMask = mask.split('');
14682
14683                     var inEscape = false;
14684                     angular.forEach(splitMask, function(chr, i) {
14685                         if (inEscape) {
14686                             inEscape = false;
14687                             maskPlaceholder += chr;
14688                             characterCount++;
14689                         }
14690                         else if (linkOptions.escChar === chr) {
14691                             inEscape = true;
14692                         }
14693                         else if (linkOptions.maskDefinitions[chr]) {
14694                             maskCaretMap.push(characterCount);
14695
14696                             maskPlaceholder += getPlaceholderChar(i - numberOfOptionalCharacters);
14697                             maskPatterns.push(linkOptions.maskDefinitions[chr]);
14698
14699                             characterCount++;
14700                             if (!isOptional) {
14701                                 minRequiredLength++;
14702                             }
14703
14704                             isOptional = false;
14705                         }
14706                         else if (chr === '?') {
14707                             isOptional = true;
14708                             numberOfOptionalCharacters++;
14709                         }
14710                         else {
14711                             maskPlaceholder += chr;
14712                             characterCount++;
14713                         }
14714                     });
14715                 }
14716                 // Caret position immediately following last position is valid.
14717                 maskCaretMap.push(maskCaretMap.slice().pop() + 1);
14718
14719                 maskComponents = getMaskComponents();
14720                 maskProcessed = maskCaretMap.length > 1 ? true : false;
14721             }
14722
14723             var prevValue = element.val();
14724             function blurHandler() {
14725                 if (linkOptions.clearOnBlur || ((linkOptions.clearOnBlurPlaceholder) && (value.length === 0) && attrs.placeholder)) {
14726                     oldCaretPosition = 0;
14727                     oldSelectionLength = 0;
14728                     if (!isValid || value.length === 0) {
14729                         valueMasked = '';
14730                         element.val('');
14731                         scope.$apply(function() {
14732                             //only $setViewValue when not $pristine to avoid changing $pristine state.
14733                             if (!ctrl.$pristine) {
14734                                 ctrl.$setViewValue('');
14735                             }
14736                         });
14737                     }
14738                 }
14739                 //Check for different value and trigger change.
14740                 if (value !== prevValue) {
14741                     var currentVal = element.val();
14742                     var isTemporarilyEmpty = value === '' && currentVal && angular.isDefined(attrs.uiMaskPlaceholderChar) && attrs.uiMaskPlaceholderChar === 'space';
14743                     if(isTemporarilyEmpty) {
14744                         element.val('');
14745                     }
14746                     triggerChangeEvent(element[0]);
14747                     if(isTemporarilyEmpty) {
14748                         element.val(currentVal);
14749                     }
14750                 }
14751                 prevValue = value;
14752             }
14753
14754             function triggerChangeEvent(element) {
14755                 var change;
14756                 if (angular.isFunction(window.Event) && !element.fireEvent) {
14757                     // modern browsers and Edge
14758                     try {
14759                         change = new Event('change', {
14760                             view: window,
14761                             bubbles: true,
14762                             cancelable: false
14763                         });
14764                     } catch (ex) {
14765                         //this is for certain mobile browsers that have the Event object
14766                         //but don't support the Event constructor 
14767                         change = document.createEvent('HTMLEvents');
14768                         change.initEvent('change', false, true);
14769                     } finally {
14770                         element.dispatchEvent(change);
14771                     }
14772                 } else if ('createEvent' in document) {
14773                     // older browsers
14774                     change = document.createEvent('HTMLEvents');
14775                     change.initEvent('change', false, true);
14776                     element.dispatchEvent(change);
14777                 }
14778                 else if (element.fireEvent) {
14779                     // IE <= 11
14780                     element.fireEvent('onchange');
14781                 }
14782             }
14783
14784             function mouseDownUpHandler(e) {
14785                 if (e.type === 'mousedown') {
14786                     element.bind('mouseout', mouseoutHandler);
14787                 } else {
14788                     element.unbind('mouseout', mouseoutHandler);
14789                 }
14790             }
14791
14792             element.bind('mousedown mouseup', mouseDownUpHandler);
14793
14794             function mouseoutHandler() {
14795                 oldSelectionLength = getSelectionLength(this);
14796                 element.unbind('mouseout', mouseoutHandler);
14797             }
14798
14799             function keydownHandler(e) {
14800                 var isKeyBackspace = e.which === 8,
14801                 caretPos = getCaretPosition(this) - 1 || 0, //value in keydown is pre change so bump caret position back to simulate post change
14802                 isCtrlZ = e.which === 90 && e.ctrlKey; //ctrl+z pressed
14803
14804                 if (isKeyBackspace) {
14805                     while(caretPos >= 0) {
14806                         if (isValidCaretPosition(caretPos)) {
14807                             //re-adjust the caret position.
14808                             //Increment to account for the initial decrement to simulate post change caret position
14809                             setCaretPosition(this, caretPos + 1);
14810                             break;
14811                         }
14812                         caretPos--;
14813                     }
14814                     preventBackspace = caretPos === -1;
14815                 }
14816
14817                 if (isCtrlZ) {
14818                     // prevent IE bug - value should be returned to initial state
14819                     element.val('');
14820                     e.preventDefault();
14821                 }
14822             }
14823
14824             function eventHandler(e) {
14825                 e = e || {};
14826                 // Allows more efficient minification
14827                 var eventWhich = e.which,
14828                         eventType = e.type;
14829
14830                 // Prevent shift and ctrl from mucking with old values
14831                 if (eventWhich === 16 || eventWhich === 91) {
14832                     return; 
14833                 }
14834
14835                 var val = element.val(),
14836                         valOld = oldValue,
14837                         valMasked,
14838                         valAltered = false,
14839                         valUnmasked = unmaskValue(val),
14840                         valUnmaskedOld = oldValueUnmasked,
14841                         caretPos = getCaretPosition(this) || 0,
14842                         caretPosOld = oldCaretPosition || 0,
14843                         caretPosDelta = caretPos - caretPosOld,
14844                         caretPosMin = maskCaretMap[0],
14845                         caretPosMax = maskCaretMap[valUnmasked.length] || maskCaretMap.slice().shift(),
14846                         selectionLenOld = oldSelectionLength || 0,
14847                         isSelected = getSelectionLength(this) > 0,
14848                         wasSelected = selectionLenOld > 0,
14849                         // Case: Typing a character to overwrite a selection
14850                         isAddition = (val.length > valOld.length) || (selectionLenOld && val.length > valOld.length - selectionLenOld),
14851                         // Case: Delete and backspace behave identically on a selection
14852                         isDeletion = (val.length < valOld.length) || (selectionLenOld && val.length === valOld.length - selectionLenOld),
14853                         isSelection = (eventWhich >= 37 && eventWhich <= 40) && e.shiftKey, // Arrow key codes
14854
14855                         isKeyLeftArrow = eventWhich === 37,
14856                         // Necessary due to "input" event not providing a key code
14857                         isKeyBackspace = eventWhich === 8 || (eventType !== 'keyup' && isDeletion && (caretPosDelta === -1)),
14858                         isKeyDelete = eventWhich === 46 || (eventType !== 'keyup' && isDeletion && (caretPosDelta === 0) && !wasSelected),
14859                         // Handles cases where caret is moved and placed in front of invalid maskCaretMap position. Logic below
14860                         // ensures that, on click or leftward caret placement, caret is moved leftward until directly right of
14861                         // non-mask character. Also applied to click since users are (arguably) more likely to backspace
14862                         // a character when clicking within a filled input.
14863                         caretBumpBack = (isKeyLeftArrow || isKeyBackspace || eventType === 'click') && caretPos > caretPosMin;
14864
14865                 oldSelectionLength = getSelectionLength(this);
14866
14867                 // These events don't require any action
14868                 if (isSelection || (isSelected && (eventType === 'click' || eventType === 'keyup' || eventType === 'focus'))) {
14869                     return;
14870                 }
14871
14872                 if (isKeyBackspace && preventBackspace) {
14873                     element.val(maskPlaceholder);
14874                     // This shouldn't be needed but for some reason after aggressive backspacing the ctrl $viewValue is incorrect.
14875                     // This keeps the $viewValue updated and correct.
14876                     scope.$apply(function () {
14877                         ctrl.$setViewValue(''); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
14878                     });
14879                     setCaretPosition(this, caretPosOld);
14880                     return;
14881                 }
14882
14883                 // User attempted to delete but raw value was unaffected--correct this grievous offense
14884                 if ((eventType === 'input') && isDeletion && !wasSelected && valUnmasked === valUnmaskedOld) {
14885                     while (isKeyBackspace && caretPos > caretPosMin && !isValidCaretPosition(caretPos)) {
14886                         caretPos--;
14887                     }
14888                     while (isKeyDelete && caretPos < caretPosMax && maskCaretMap.indexOf(caretPos) === -1) {
14889                         caretPos++;
14890                     }
14891                     var charIndex = maskCaretMap.indexOf(caretPos);
14892                     // Strip out non-mask character that user would have deleted if mask hadn't been in the way.
14893                     valUnmasked = valUnmasked.substring(0, charIndex) + valUnmasked.substring(charIndex + 1);
14894
14895                     // If value has not changed, don't want to call $setViewValue, may be caused by IE raising input event due to placeholder
14896                     if (valUnmasked !== valUnmaskedOld)
14897                         valAltered = true;
14898                 }
14899
14900                 // Update values
14901                 valMasked = maskValue(valUnmasked);
14902
14903                 oldValue = valMasked;
14904                 oldValueUnmasked = valUnmasked;
14905
14906                 //additional check to fix the problem where the viewValue is out of sync with the value of the element.
14907                 //better fix for commit 2a83b5fb8312e71d220a497545f999fc82503bd9 (I think)
14908                 if (!valAltered && val.length > valMasked.length)
14909                     valAltered = true;
14910
14911                 element.val(valMasked);
14912
14913                 //we need this check.  What could happen if you don't have it is that you'll set the model value without the user
14914                 //actually doing anything.  Meaning, things like pristine and touched will be set.
14915                 if (valAltered) {
14916                     scope.$apply(function () {
14917                         ctrl.$setViewValue(valMasked); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
14918                     });
14919                 }
14920
14921                 // Caret Repositioning
14922                 // Ensure that typing always places caret ahead of typed character in cases where the first char of
14923                 // the input is a mask char and the caret is placed at the 0 position.
14924                 if (isAddition && (caretPos <= caretPosMin)) {
14925                     caretPos = caretPosMin + 1;
14926                 }
14927
14928                 if (caretBumpBack) {
14929                     caretPos--;
14930                 }
14931
14932                 // Make sure caret is within min and max position limits
14933                 caretPos = caretPos > caretPosMax ? caretPosMax : caretPos < caretPosMin ? caretPosMin : caretPos;
14934
14935                 // Scoot the caret back or forth until it's in a non-mask position and within min/max position limits
14936                 while (!isValidCaretPosition(caretPos) && caretPos > caretPosMin && caretPos < caretPosMax) {
14937                     caretPos += caretBumpBack ? -1 : 1;
14938                 }
14939
14940                 if ((caretBumpBack && caretPos < caretPosMax) || (isAddition && !isValidCaretPosition(caretPosOld))) {
14941                     caretPos++;
14942                 }
14943                 oldCaretPosition = caretPos;
14944                 setCaretPosition(this, caretPos);
14945             }
14946
14947             function isValidCaretPosition(pos) {
14948                 return maskCaretMap.indexOf(pos) > -1;
14949             }
14950
14951             function getCaretPosition(input) {
14952                 if (!input)
14953                     return 0;
14954                 if (input.selectionStart !== undefined) {
14955                     return input.selectionStart;
14956                 } else if (document.selection) {
14957                     if (isFocused(element[0])) {
14958                         // For IE
14959                         input.focus();
14960                         var selection = document.selection.createRange();
14961                         selection.moveStart('character', input.value ? -input.value.length : 0);
14962                         return selection.text.length;
14963                     }
14964                 }
14965                 return 0;
14966             }
14967
14968             function setCaretPosition(input, pos) {
14969                 if (!input)
14970                     return 0;
14971                 if (input.offsetWidth === 0 || input.offsetHeight === 0) {
14972                     return; // Input's hidden
14973                 }
14974                 if (input.setSelectionRange) {
14975                     if (isFocused(element[0])) {
14976                         input.focus();
14977                         input.setSelectionRange(pos, pos);
14978                     }
14979                 }
14980                 else if (input.createTextRange) {
14981                     // For IE
14982                     var range = input.createTextRange();
14983                     range.collapse(true);
14984                     range.moveEnd('character', pos);
14985                     range.moveStart('character', pos);
14986                     range.select();
14987                 }
14988             }
14989
14990             function getSelectionLength(input) {
14991                 if (!input)
14992                     return 0;
14993                 if (input.selectionStart !== undefined) {
14994                     return (input.selectionEnd - input.selectionStart);
14995                 }
14996                 if (window.getSelection) {
14997                     return (window.getSelection().toString().length);
14998                 }
14999                 if (document.selection) {
15000                     return (document.selection.createRange().text.length);
15001                 }
15002                 return 0;
15003             }
15004         }
15005     };
15006 }])
15007 .filter('b2bMultiSepartorHighlight', function($sce) {
15008         return function(text, searchText, searchSeperator) {
15009             var splitText = function(string) {
15010                 if(angular.isDefined(searchSeperator)){
15011                     if (string.indexOf(searchSeperator) > -1) {
15012                         return string.split(searchSeperator);
15013                     } else {
15014                         return string
15015                     }
15016                 }else{
15017                     return string;
15018                 }
15019             }
15020             if (text) {
15021                 var newText = splitText(text);
15022                 var newPhrase = splitText(searchText);
15023                 if (angular.isArray(newPhrase)) {
15024                     for (var i = 0; i < newText.length; i++) {
15025                         if (i <= 0) {
15026                             text = newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
15027                                 '<span class="b2b-search-hightlight">$1</span>');
15028                         } else {
15029                             text = text + searchSeperator + ' ' + (newPhrase[i] ? newText[i].replace(new RegExp('(' + newPhrase[i] + ')', 'gi'),
15030                                 '<span class="b2b-search-hightlight">$1</span>') : newText[i]);
15031                         }
15032                     }
15033                 } else {
15034                     text = text.replace(new RegExp('(' + searchText + ')', 'gi'),
15035                         '<span class="b2b-search-hightlight">$1</span>');
15036                 }
15037             }
15038             return $sce.trustAsHtml(text)
15039         }
15040     })
15041     
15042     .factory('b2bUserAgent', [function() {
15043         var _isMobile = function() {
15044             if(/Android/i.test(navigator.userAgent)){
15045                 return /Mobile/i.test(navigator.userAgent);
15046             }else{
15047                 return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
15048             }
15049             
15050         };
15051         var _notMobile = function() {
15052             if(/Android/i.test(navigator.userAgent)){
15053                 return !/Mobile/i.test(navigator.userAgent);
15054             }else{
15055                 return !/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
15056             }
15057             
15058         };
15059         var _isIE = function() {
15060             return /msie|trident/i.test(navigator.userAgent);
15061         };
15062         var _isFF = function() {
15063             return /Firefox/.test(navigator.userAgent);
15064         };
15065         var _isChrome = function() {
15066             return /Chrome/.test(navigator.userAgent);
15067         };
15068         var _isSafari = function() {
15069             return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
15070         };
15071
15072         return {
15073             isMobile: _isMobile,
15074             notMobile: _notMobile,
15075             isIE: _isIE,
15076             isFF: _isFF,
15077             isChrome: _isChrome,
15078             isSafari: _isSafari
15079         };
15080     }])
15081     .run(['$document', 'b2bUserAgent', function($document, b2bUserAgent) {
15082         var html = $document.find('html').eq(0);
15083         if (b2bUserAgent.isIE()) {
15084             html.addClass('isIE');
15085         } else {
15086             html.removeClass('isIE');
15087         }
15088     }]);
15089     
15090
15091 (function () {
15092     String.prototype.toSnakeCase = function () {
15093         return this.replace(/([A-Z])/g, function ($1) {
15094             return "-" + $1.toLowerCase();
15095         });
15096     };
15097     var concat = function (character, times) {
15098         character = character || '';
15099         times = (!isNaN(times) && times) || 0;
15100         var finalChar = '';
15101         for (var i = 0; i < times; i++) {
15102             finalChar += character;
15103         }
15104         return finalChar;
15105     };
15106
15107     // direction: true for left and false for right
15108     var pad = function (actualString, width, character, direction) {
15109         actualString = actualString || '';
15110         width = (!isNaN(width) && width) || 0;
15111         character = character || '';
15112         if (width > actualString.length) {
15113             if (direction) {
15114                 return concat(character, (width - actualString.length)) + actualString;
15115             } else {
15116                 return actualString + concat(character, (width - actualString.length));
15117             }
15118         }
15119         return actualString;
15120     };
15121
15122     String.prototype.lPad = function (width, character) {
15123         return pad(this, width, character, true);
15124     };
15125
15126     String.prototype.rPad = function (width, character) {
15127         return pad(this, width, character, false);
15128     };
15129
15130     if (!Array.prototype.indexOf) {
15131         Array.prototype.indexOf = function (val) {
15132             for (var index = 0; index < this.length; index++) {
15133                 if (this[index] === val) {
15134                     return index;
15135                 }
15136             }
15137             return -1;
15138         };
15139     }
15140
15141     if (!Array.prototype.regexIndexOf) {
15142         Object.defineProperty(Array.prototype, 'regexIndexOf', {
15143             enumerable: false,
15144             value: function (regex, startIndex, loop) {
15145                 startIndex = startIndex && startIndex > -1 ? startIndex : 0;
15146                 for (var index = startIndex; index < this.length; index++) {
15147                     if (this[index].toString().match(regex)) {
15148                         return index;
15149                     }
15150                 }
15151                 if (loop) {
15152                     for (var index = 0; index < startIndex; index++) {
15153                         if (this[index].toString().match(regex)) {
15154                             return index;
15155                         }
15156                     }
15157                 }
15158                 return -1;
15159             }
15160         })
15161     }
15162 })();
15163 angular.module("b2bTemplate/audioPlayer/audioPlayer.html", []).run(["$templateCache", function($templateCache) {
15164   $templateCache.put("b2bTemplate/audioPlayer/audioPlayer.html",
15165     "<div class=\"b2b-audio\">\n" +
15166     "   <audio preload=\"auto\">\n" +
15167     "           <source ng-src=\"{{audio.mp3 | trustedAudioUrl}}\" type=\"audio/mp3\"></source>\n" +
15168     "           <i>Your browser does not support the audio element.</i>\n" +
15169     "    </audio>\n" +
15170     "\n" +
15171     "    <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" +
15172     "           <i class=\"icoControls-pointer\" ng-show='!isPlayInProgress'></i>\n" +
15173     "           <i class=\"icoControls-pause\" ng-show='isPlayInProgress'></i>\n" +
15174     "    </div>\n" +
15175     "\n" +
15176     "    <div class=\"seek-bar-container-wrapper\">\n" +
15177     "           <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" +
15178     "           <div class=\"timing-container\">\n" +
15179     "                   <span class=\"timing-container-left\">{{timeFormatter(audio.currentTime)}}</span>\n" +
15180     "                   <span class=\"timing-container-right\">{{timeFormatter(audio.duration)}}</span>\n" +
15181     "                   <div class=\"timing-container-spacer\"></div>\n" +
15182     "           </div>\n" +
15183     "    </div>\n" +
15184     "           \n" +
15185     "    <b2b-flyout>\n" +
15186     "           <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" +
15187     "                   <i class=\"icoControls-mutespeakers\" ng-show=\"audio.currentVolume === 0\"></i>\n" +
15188     "                   <i class=\"icoControls-volumedown\" ng-show=\"audio.currentVolume > 0 && audio.currentVolume <= 50\"></i>\n" +
15189     "                   <i class=\"icoControls-volumeup\" ng-show=\"audio.currentVolume > 50\"></i>\n" +
15190     "           </div> \n" +
15191     "           \n" +
15192     "           <b2b-flyout-content horizontal-placement=\"center\" flyout-style=\"width:70px; height:190px;\" vertical-placement=\"above\">\n" +
15193     "                   <div class=\"b2b-audio-popover text-center\">\n" +
15194     "                           <span>Max</span>\n" +
15195     "                           <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" +
15196     "                           <div class=\"min-label\">Min</div>\n" +
15197     "                   </div>\n" +
15198     "           </b2b-flyout-content>\n" +
15199     "   </b2b-flyout>\n" +
15200     "</div>");
15201 }]);
15202
15203 angular.module("b2bTemplate/audioRecorder/audioRecorder.html", []).run(["$templateCache", function($templateCache) {
15204   $templateCache.put("b2bTemplate/audioRecorder/audioRecorder.html",
15205     "<div class=\"b2b-audio-recorder row\">\n" +
15206     "   <div class=\"b2b-elapsed-time span11\">\n" +
15207     "           <div ng-if=\"isRecording\">\n" +
15208     "                   <span style=\"padding-right: 25px;\">{{config.whileRecordingMessage}}</span>\n" +
15209     "                   <span>{{timeFormatter(elapsedTime)}}</span>\n" +
15210     "           </div>\n" +
15211     "           <span ng-if=\"!isRecording\">{{config.startRecordingMessage}}</span>\n" +
15212     "   </div>      \n" +
15213     "   <div class=\"b2b-controls\" title=\"{{isRecording ? 'Stop' : 'REC'}}\" b2b-accessibility-click=\"13,32\" ng-click=\"toggleRecording()\" role=\"button\">\n" +
15214     "           <i ng-if=\"isRecording\" class=\"icoControls-stop\" ></i>\n" +
15215     "           <i ng-if=\"!isRecording\" class=\"icoControls-record\"></i>\n" +
15216     "    </div>\n" +
15217     "</div>");
15218 }]);
15219
15220 angular.module("b2bTemplate/backToTop/backToTop.html", []).run(["$templateCache", function($templateCache) {
15221   $templateCache.put("b2bTemplate/backToTop/backToTop.html",
15222     "<button class=\"btn-arrow b2b-backtotop-button\" type=\"button\" aria-label=\"Back to top\">\n" +
15223     "    <div class=\"btn-secondary b2b-top-btn\">\n" +
15224     "        <i class=\"icoControls-upPRIMARY\" role=\"img\"></i>\n" +
15225     "    </div>\n" +
15226     "</button>\n" +
15227     "");
15228 }]);
15229
15230 angular.module("b2bTemplate/boardstrip/b2bAddBoard.html", []).run(["$templateCache", function($templateCache) {
15231   $templateCache.put("b2bTemplate/boardstrip/b2bAddBoard.html",
15232     "<div tabindex=\"0\" role=\"menuitem\" b2b-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +
15233     "    <div class=\"centered\"><i aria-hidden=\"true\" class=\"icoControls-add-maximize\"></i> Add board</div>\n" +
15234     "</div> ");
15235 }]);
15236
15237 angular.module("b2bTemplate/boardstrip/b2bBoard.html", []).run(["$templateCache", function($templateCache) {
15238   $templateCache.put("b2bTemplate/boardstrip/b2bBoard.html",
15239     "<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" +
15240     "    <div ng-transclude></div>\n" +
15241     "    <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +
15242     "        <div class=\"board-caret-indicator\"></div>\n" +
15243     "        <div class=\"board-caret-arrow-up\"></div>\n" +
15244     "    </div>\n" +
15245     "</li>");
15246 }]);
15247
15248 angular.module("b2bTemplate/boardstrip/b2bBoardstrip.html", []).run(["$templateCache", function($templateCache) {
15249   $templateCache.put("b2bTemplate/boardstrip/b2bBoardstrip.html",
15250     "<div class=\"b2b-boardstrip\">\n" +
15251     "   <div class=\"boardstrip-reel\" role=\"menu\">\n" +
15252     "           <div class=\"prev-items\">\n" +
15253     "                   <!-- <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" +
15254     "                   <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" ng-disabled=\"!isPrevBoard()\">\n" +
15255     "                       <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-left\"></i>\n" +
15256     "                       </div>\n" +
15257     "                       <span class=\"offscreen-text\">Previous boards</span>\n" +
15258     "                   </button>\n" +
15259     "           </div>\n" +
15260     "           <div b2b-add-board on-add-board=\"onAddBoard()\"></div>\n" +
15261     "           <div class=\"board-viewport\"><ul role=\"menu\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +
15262     "           <div class=\"next-items\">\n" +
15263     "                   <!-- <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" +
15264     "                   <button class=\"btn-arrow arrow\" b2b-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" ng-disabled=\"!isNextBoard()\">\n" +
15265     "                       <div class=\"btn btn-small btn-alt\"><i class=\"icon-primary-right\"></i>\n" +
15266     "                       </div>\n" +
15267     "                       <span class=\"offscreen-text\">Next boards</span>\n" +
15268     "                   </button>\n" +
15269     "           </div>\n" +
15270     "   </div>\n" +
15271     "</div>\n" +
15272     "");
15273 }]);
15274
15275 angular.module("b2bTemplate/calendar/datepicker-popup.html", []).run(["$templateCache", function($templateCache) {
15276   $templateCache.put("b2bTemplate/calendar/datepicker-popup.html",
15277     "<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" +
15278     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
15279     "        <div ng-repeat=\"header in headers\" class=\"text-left\" style=\"width: 100%;\" b2b-append-element=\"header\"></div>\n" +
15280     "        <table class=\"table-condensed\">\n" +
15281     "            <thead>\n" +
15282     "                <tr>\n" +
15283     "                    <th id=\"prev\" class=\"prev\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" 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" +
15284     "                    <th id=\"month\" tabindex=\"-1\" aria-label=\"{{title}}\" class=\"datepicker-switch\" colspan=\"{{rows[0].length - 2}}\">{{title}}</th>\n" +
15285     "                    <th id=\"next\" class=\"next\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" 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" +
15286     "                </tr>\n" +
15287     "                <tr ng-show=\"labels.length > 0\">\n" +
15288     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
15289     "                </tr>\n" +
15290     "            </thead>\n" +
15291     "            <tbody>\n" +
15292     "                <tr ng-repeat=\"row in rows\">\n" +
15293     "                    <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" +
15294     "                        <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" +
15295     "                </tr>\n" +
15296     "            </tbody>\n" +
15297     "            <tfoot>\n" +
15298     "                <tr ng-repeat=\"footer in footers\">\n" +
15299     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"footer\"></th>\n" +
15300     "                </tr>\n" +
15301     "            </tfoot>\n" +
15302     "        </table>\n" +
15303     "    </div>\n" +
15304     "</div>");
15305 }]);
15306
15307 angular.module("b2bTemplate/calendar/datepicker.html", []).run(["$templateCache", function($templateCache) {
15308   $templateCache.put("b2bTemplate/calendar/datepicker.html",
15309     "<div>\n" +
15310     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
15311     "</div>");
15312 }]);
15313
15314 angular.module("b2bTemplate/coachmark/coachmark.html", []).run(["$templateCache", function($templateCache) {
15315   $templateCache.put("b2bTemplate/coachmark/coachmark.html",
15316     "<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" +
15317     "   <i class=\"b2b-coachmark-caret\"></i>\n" +
15318     "   <div class=\"b2b-coachmark-header\">\n" +
15319     "           <div class=\"b2b-coachmark-countlabel\"><span ng-if=\"coachmarkIndex !== 0\">{{coachmarkIndex}} of {{(coachmarks.length-1)}}<span></div>\n" +
15320     "           <div class=\"corner-button\">\n" +
15321     "                   <button type=\"button\" ng-focus=\"closeButtonFocus()\" class=\"close\" title=\"close\" aria-label=\"Close\" ng-click=\"closeCoachmark()\"></button>\n" +
15322     "           </div>\n" +
15323     "   </div>\n" +
15324     "   <div class=\"b2b-coachmark-content\">   \n" +
15325     "           <i class=\"icon-misc-dimmer\"></i>\n" +
15326     "           <div class=\"b2b-coachmark-content-header\"><span class=\"offscreen-text\">{{currentCoachmark.offscreenText}}</span>{{currentCoachmark.contentHeader}}</div>\n" +
15327     "           <div class=\"b2b-coachmark-description\">{{currentCoachmark.content}}</div>\n" +
15328     "           <div class=\"b2b-coachmark-btn-group\">\n" +
15329     "                   <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" +
15330     "                   <button class=\"btn btn-alt\" ng-if=\"currentCoachmark.buttonLabel !== '' && currentCoachmark.buttonLabel !== undefined\" ng-click=\"actionCoachmark(currentCoachmark.buttonLabel)\">{{currentCoachmark.buttonLabel}}</button>\n" +
15331     "           </div>  \n" +
15332     "   </div>  \n" +
15333     "</div>");
15334 }]);
15335
15336 angular.module("b2bTemplate/dropdowns/b2bDropdownDesktop.html", []).run(["$templateCache", function($templateCache) {
15337   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownDesktop.html",
15338     "<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" +
15339     "    <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-blur=\"setBlur();\" ng-class=\"{'active': toggleFlag, 'closed': !toggleFlag, 'large': (dropdownSize === 'large')}\" style=\"width:100%;\" value=\"{{currentSelected.text}}\" ng-show=\"isInputDropdown\" aria-describedby=\"{{dropdownDescribedBy}}\" readonly=\"readonly\">\n" +
15340     "    <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" +
15341     "    <div ng-class=\"{'selectWrapper': (isInputDropdown), 'moduleWrapper': (!isInputDropdown)}\">\n" +
15342     "        <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" +
15343     "        <ul class=\"module-optinalcta\" ng-if=\"toggleFlag && optionalCta\" tabindex=\"-1\" aria-hidden=\"false\">\n" +
15344     "            <li class=\"module-list-item\" tabindex=\"-1\" role=\"menuitem\" value=\"\" aria-label=\"Optinal CTA\" aria-selected=\"true\">\n" +
15345     "                <span class=\"module-data\" b2b-append-element=\"optionalCta\"></span>\n" +
15346     "            </li>\n" +
15347     "        </ul>\n" +
15348     "</div>\n" +
15349     "<i class=\"icon-primary-down\" aria-hidden=\"true\"></i>\n" +
15350     "</span>");
15351 }]);
15352
15353 angular.module("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html", []).run(["$templateCache", function($templateCache) {
15354   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownGroupDesktop.html",
15355     "<li b2b-dropdown-group-desktop class=\"optgroup-wrapper\">{{groupHeader}}\n" +
15356     "    <ul class=\"optgroup\" role=\"group\" aria-label=\"{{groupHeader}}\"></ul>\n" +
15357     "</li>");
15358 }]);
15359
15360 angular.module("b2bTemplate/dropdowns/b2bDropdownListDesktop.html", []).run(["$templateCache", function($templateCache) {
15361   $templateCache.put("b2bTemplate/dropdowns/b2bDropdownListDesktop.html",
15362     "<li b2b-dropdown-list-desktop b2b-key-item b2b-accessibility-click=\"13\" aria-selected=\"{{currentSelected.value === dropdownListValue}}\" data-hover=\"{{dropdown.highlightedValue === dropdownListValue}}\" ng-class=\"{'awd-select-list-item': (isInputDropdown), 'module-list-item': (!isInputDropdown)}\" tabindex=\"0\" role=\"{{isInputDropdown?'option':'menuitem'}}\" ng-click=\"selectDropdownItem()\" ng-focus=\"highlightDropdown()\"></li>");
15363 }]);
15364
15365 angular.module("b2bTemplate/fileUpload/fileUpload.html", []).run(["$templateCache", function($templateCache) {
15366   $templateCache.put("b2bTemplate/fileUpload/fileUpload.html",
15367     "<label class=\"b2b-file-container\">\n" +
15368     "   <span class=\"b2b-upload-link\" ng-transclude></span>\n" +
15369     "   <input type=\"file\" b2b-file-change>\n" +
15370     "</label>");
15371 }]);
15372
15373 angular.module("b2bTemplate/flyout/flyout.html", []).run(["$templateCache", function($templateCache) {
15374   $templateCache.put("b2bTemplate/flyout/flyout.html",
15375     "<span class=\"b2b-flyout\"  b2b-flyout-trap-focus-inside>\n" +
15376     "    <span ng-transclude></span>\n" +
15377     "</span>");
15378 }]);
15379
15380 angular.module("b2bTemplate/flyout/flyoutContent.html", []).run(["$templateCache", function($templateCache) {
15381   $templateCache.put("b2bTemplate/flyout/flyoutContent.html",
15382     "<div class=\"b2b-flyout-container\" aria-live=\"polite\" aria-atomic=\"false\" ng-class=\"{'b2b-flyout-left':horizontalPlacement==='left',\n" +
15383     "                'b2b-flyout-center':horizontalPlacement==='center', \n" +
15384     "                'b2b-flyout-right':horizontalPlacement==='right',\n" +
15385     "                'b2b-flyout-centerLeft':horizontalPlacement==='centerLeft',\n" +
15386     "                'b2b-flyout-centerRight':horizontalPlacement==='centerRight',  \n" +
15387     "                'b2b-flyout-above':verticalPlacement==='above', \n" +
15388     "                'b2b-flyout-below':verticalPlacement==='below',\n" +
15389     "                'open-flyout': openFlyout,\n" +
15390     "                'b2b-close-flyout': !openFlyout}\">\n" +
15391     "    <i class=\"b2b-flyout-caret\" ng-class=\"{'open-flyout': openFlyout, \n" +
15392     "                                   'b2b-flyout-caret-above':verticalPlacement==='above',\n" +
15393     "                                   'b2b-flyout-caret-below':verticalPlacement==='below'}\"></i>\n" +
15394     "    <span ng-transclude></span>\n" +
15395     "</div>");
15396 }]);
15397
15398 angular.module("b2bTemplate/footer/footer_column_switch_tpl.html", []).run(["$templateCache", function($templateCache) {
15399   $templateCache.put("b2bTemplate/footer/footer_column_switch_tpl.html",
15400     "<div class=\"footer-columns \" ng-class=\"{'five-column':footerColumns===5, 'four-column':footerColumns===4, 'three-column':footerColumns===3}\" ng-repeat=\"item in footerLinkItems\">\n" +
15401     "    <h3 class=\"b2b-footer-header\">{{item.categoryName}}</h3>\n" +
15402     "    <ul>\n" +
15403     "        <li ng-repeat=\"i in item.values\">\n" +
15404     "            <a href=\"{{i.href}}\" title=\"{{item.categoryName}} - {{i.displayLink}}\">{{i.displayLink}}</a>  \n" +
15405     "        </li>\n" +
15406     "    </ul>\n" +
15407     "\n" +
15408     "</div>\n" +
15409     "\n" +
15410     "<div ng-transclude></div>\n" +
15411     "");
15412 }]);
15413
15414 angular.module("b2bTemplate/horizontalTable/horizontalTable.html", []).run(["$templateCache", function($templateCache) {
15415   $templateCache.put("b2bTemplate/horizontalTable/horizontalTable.html",
15416     "<div class=\"b2b-horizontal-table\">\n" +
15417     "    <div class=\"b2b-horizontal-table-arrows row span12\">\n" +
15418     "        <div class=\"span4 b2b-prev-link\">\n" +
15419     "            <a href=\"javascript:void(0)\" ng-click=\"moveViewportLeft()\" ddh-accessibility-click=\"13,32\" ng-if=\"!disableLeft\">Previous</a>\n" +
15420     "            <span ng-if=\"disableLeft\" class=\"b2b-disabled-text\">Previous</span>\n" +
15421     "        </div>\n" +
15422     "        \n" +
15423     "        <span class=\"span5 b2b-horizontal-table-column-info\" aria-live=\"polite\" tabindex=\"-1\">\n" +
15424     "            Showing {{countDisplayText}} {{getColumnSet()[0]+1}}-{{getColumnSet()[1]+1}} of {{numOfCols}} columns\n" +
15425     "        </span>\n" +
15426     "\n" +
15427     "        <div ng-if=\"legendContent\" class=\"span2 b2b-horizontal-table-legend\">\n" +
15428     "           | <b2b-flyout>\n" +
15429     "                <div tabindex=\"0\" role=\"button\" aria-haspopup=\"true\" b2b-flyout-toggler b2b-accessibility-click=\"13,32\" aria-expanded=\"{{flyoutOpened ? 'true' : 'false'}}\">\n" +
15430     "                    Legend\n" +
15431     "                    <i class=\"icoControls-down\" role=\"img\"></i>\n" +
15432     "                </div>\n" +
15433     "              <b2b-flyout-content horizontal-placement=\"center\" vertical-placement=\"below\">\n" +
15434     "                <div ng-bind-html=\"legendContent\"></div>\n" +
15435     "              </b2b-flyout-content>\n" +
15436     "            </b2b-flyout>\n" +
15437     "        </div>\n" +
15438     "        \n" +
15439     "        <div class=\"span3 text-right b2b-next-link\">\n" +
15440     "            <a href=\"javascript:void(0)\" ng-click=\"moveViewportRight()\" ddh-accessibility-click=\"13,32\" ng-if=\"!disableRight\">Next</a>\n" +
15441     "            <span ng-if=\"disableRight\" class=\"b2b-disabled-text\">Next</span>\n" +
15442     "        </div>\n" +
15443     "    </div>\n" +
15444     "    <div class=\"b2b-horizontal-table-inner-container\">\n" +
15445     "        <span ng-transclude></span>\n" +
15446     "    </div>\n" +
15447     "</div>");
15448 }]);
15449
15450 angular.module("b2bTemplate/hourPicker/b2bHourpicker.html", []).run(["$templateCache", function($templateCache) {
15451   $templateCache.put("b2bTemplate/hourPicker/b2bHourpicker.html",
15452     "<div class=\"hp-container\">\n" +
15453     "    <div class=\"hp-selected\">\n" +
15454     "        <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" +
15455     "    </div>\n" +
15456     "    <div b2b-hourpicker-panel></div>\n" +
15457     "</div>");
15458 }]);
15459
15460 angular.module("b2bTemplate/hourPicker/b2bHourpickerPanel.html", []).run(["$templateCache", function($templateCache) {
15461   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerPanel.html",
15462     "<form name=\"{{'hourpickerForm' + $id}}\">\n" +
15463     "    <div class=\"hp-checkbox\" role=\"group\">\n" +
15464     "        <label class=\"checkbox\" for=\"checkbox_{{dayOption.title}}_{{$id}}\" ng-repeat=\"dayOption in hourpicker.dayOptions\">\n" +
15465     "            <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" +
15466     "        </label>\n" +
15467     "    </div>\n" +
15468     "    <div class=\"row hp-dropdowns\">\n" +
15469     "        <div class=\"span4\">\n" +
15470     "            <label for=\"{{'hourpickerStartTime' + $id}}\">From</label>\n" +
15471     "            <select id=\"{{'hourpickerStartTime' + $parent.$id}}\" b2b-dropdown type=\"\" ng-model=\"hourpickerPanelValue.startTime\">\n" +
15472     "                <option b2b-dropdown-list value=\"\">From</option>\n" +
15473     "                <option b2b-dropdown-list option-repeat=\"startTimeOption in hourpicker.startTimeOptions\" value=\"{{startTimeOption}}\">{{startTimeOption}}</option>\n" +
15474     "            </select>\n" +
15475     "        </div>\n" +
15476     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
15477     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_AM_{{$id}}\">\n" +
15478     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_AM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
15479     "            </label>\n" +
15480     "            <label class=\"radio\" for=\"hourpickerStartMeridiem_PM_{{$id}}\">\n" +
15481     "                <input type=\"radio\" id=\"hourpickerStartMeridiem_PM_{{$id}}\" name=\"{{'hourpickerStartMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.startMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
15482     "            </label>\n" +
15483     "        </div>\n" +
15484     "    </div>\n" +
15485     "    <div class=\"row hp-dropdowns\">\n" +
15486     "        <div class=\"span4\">\n" +
15487     "            <label for=\"{{'hourpickerEndTime' + $id}}\">To</label>\n" +
15488     "            <select id=\"{{'hourpickerEndTime' + $parent.$id}}\" b2b-dropdown ng-model=\"hourpickerPanelValue.endTime\">\n" +
15489     "                <option b2b-dropdown-list value=\"\">To</option>\n" +
15490     "                <option b2b-dropdown-list option-repeat=\"endTimeOption in hourpicker.endTimeOptions\" value=\"{{endTimeOption}}\">{{endTimeOption}}</option>\n" +
15491     "            </select>\n" +
15492     "        </div>\n" +
15493     "        <div class=\"span8 radio-buttons\" role=\"radiogroup\" aria-label=\"Select AM or PM\">\n" +
15494     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_AM_{{$id}}\">\n" +
15495     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_AM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"am\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>AM</span>\n" +
15496     "            </label>\n" +
15497     "            <label class=\"radio\" for=\"hourpickerEndMeridiem_PM_{{$id}}\">\n" +
15498     "                <input type=\"radio\" id=\"hourpickerEndMeridiem_PM_{{$id}}\" name=\"{{'hourpickerEndMeridiem' + $id}}\" value=\"pm\" ng-model=\"hourpickerPanelValue.endMeridiem\" /><i class=\"skin\"></i><span>PM</span>\n" +
15499     "            </label>\n" +
15500     "        </div>\n" +
15501     "    </div>\n" +
15502     "    <div class=\"row hp-buttons\">\n" +
15503     "        <div class=\"span12\">\n" +
15504     "            <div style=\"float:right\">\n" +
15505     "                <button class=\"btn btn-secondary btn-small\" ng-click=\"resetHourpickerPanelValue()\">Clear</button>\n" +
15506     "                <button class=\"btn btn-alt btn-small\" ng-disabled = \"disableAddBtn\" ng-click=\"updateHourpickerValue()\">{{hourpicker.editMode > -1 ? 'Update' : 'Add'}}</button>\n" +
15507     "            </div>\n" +
15508     "        </div>\n" +
15509     "    </div>\n" +
15510     "</form>");
15511 }]);
15512
15513 angular.module("b2bTemplate/hourPicker/b2bHourpickerValue.html", []).run(["$templateCache", function($templateCache) {
15514   $templateCache.put("b2bTemplate/hourPicker/b2bHourpickerValue.html",
15515     "<div class=\"selected-days\">\n" +
15516     "    <span class=\"day\">{{hourpickerValue.days}} &nbsp; {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}</span>\n" +
15517     "    <span style=\"float:right\">\n" +
15518     "        <i class=\"icon-misc-pen\" role=\"button\" aria-label=\"Edit {{hourpickerValue.days}} {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" title=\"Edit\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"editHourpickerValue(hourpickerValue.index)\"></i>\n" +
15519     "        <i class=\"icon-misc-trash\" role=\"button\" aria-label=\"Delete {{hourpickerValue.days}} {{hourpickerValue.startTime}} {{hourpickerValue.startMeridiem}} - {{hourpickerValue.endTime}} {{hourpickerValue.endMeridiem}}\" title=\"Delete\" tabindex=\"0\" b2b-accessibility-click=\"13,32\" ng-click=\"deleteHourpickerValue(hourpickerValue.index)\"></i>\n" +
15520     "    </span>\n" +
15521     "    <div style=\"clear:both\"></div>\n" +
15522     "</div>");
15523 }]);
15524
15525 angular.module("b2bTemplate/leftNavigation/leftNavigation.html", []).run(["$templateCache", function($templateCache) {
15526   $templateCache.put("b2bTemplate/leftNavigation/leftNavigation.html",
15527     "<div class=\"b2b-nav-menu\">\n" +
15528     "    <div class=\"b2b-subnav-container\">\n" +
15529     "        <ul class=\"b2b-subnav-content\">\n" +
15530     "            <li ng-repeat=\"menu in menuData\" ng-click=\"toggleNav($index)\"><a ng-class=\"{'expand': idx==$index}\" aria-label=\"{{menu.name}}\" title=\" \" aria-expanded=\"{{(idx==$index)?true:false;}}\" href=\"javascript:void(0);\">{{menu.name}}<i class=\"b2b-icon-primary-plus-minus\" ng-class=\"idx==$index ? 'icon-primary-expanded' : 'icon-primary-collapsed'\"></i></a>\n" +
15531     "                <ul ng-class=\"{expand: idx==$index}\">\n" +
15532     "                    <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" +
15533     "                </ul>\n" +
15534     "            </li>\n" +
15535     "        </ul>\n" +
15536     "    </div>\n" +
15537     "</div>");
15538 }]);
15539
15540 angular.module("b2bTemplate/listbox/listbox.html", []).run(["$templateCache", function($templateCache) {
15541   $templateCache.put("b2bTemplate/listbox/listbox.html",
15542     "<div class=\"b2b-list-box\" tabindex=\"0\" role=\"listbox\" ng-transclude>\n" +
15543     "</div>");
15544 }]);
15545
15546 angular.module("b2bTemplate/modalsAndAlerts/b2b-backdrop.html", []).run(["$templateCache", function($templateCache) {
15547   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-backdrop.html",
15548     "<div class=\"b2b-modal-backdrop fade in hidden-by-modal\" aria-hidden=\"true\" tabindex=\"-1\"></div>");
15549 }]);
15550
15551 angular.module("b2bTemplate/modalsAndAlerts/b2b-window.html", []).run(["$templateCache", function($templateCache) {
15552   $templateCache.put("b2bTemplate/modalsAndAlerts/b2b-window.html",
15553     "<div class=\"modalwrapper active {{windowClass}}\" ng-class=\"{'modal-landscape': isModalLandscape}\" role=\"{{isNotifDialog?'alertdialog':'dialog'}}\" tabindex=\"-1\" aria-labelledby=\"{{title}}\" aria-describedby=\"{{content}}\">\n" +
15554     "    <div class=\"modal fade in {{sizeClass}}\" ng-transclude></div>\n" +
15555     "</div>");
15556 }]);
15557
15558 angular.module("b2bTemplate/monthSelector/monthSelector-popup.html", []).run(["$templateCache", function($templateCache) {
15559   $templateCache.put("b2bTemplate/monthSelector/monthSelector-popup.html",
15560     "<div id=\"monthselector{{$id}}\" class=\"datepicker dropdown-menu monthselector\" \n" +
15561     "     ng-class=\"{'datepicker-dropdown datepicker-orient-top': !inline, 'datepicker-orient-left': !inline && orientation === 'left', 'datepicker-orient-right': !inline && orientation === 'right'}\" \n" +
15562     "     ng-style=\"{position: inline && 'relative', 'z-index': inline && '0', top: !inline && position.top + 'px' || 0, left: !inline && position.left + 'px'}\" \n" +
15563     "     style=\"display: block;\" aria-hidden=\"false\" role=\"dialog presentation\" tabindex=\"-1\">\n" +
15564     "    <div class=\"datepicker-days\" style=\"display: block;\">\n" +
15565     "        <span class=\"offscreen-text\" aria-live=\"polite\" aria-atomic=\"true\">{{title}} displaying</span>\n" +
15566     "        <table class=\"table-condensed\" role=\"grid\">\n" +
15567     "            <thead>\n" +
15568     "                <tr ng-repeat=\"header in headers\">\n" +
15569     "                    <th colspan=\"7\" class=\"text-left\" style=\"width: 278px;\" b2b-append-element=\"header\"></th>\n" +
15570     "                </tr>\n" +
15571     "                <tr>\n" +
15572     "                    <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" +
15573     "                    <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" +
15574     "                    <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" +
15575     "                </tr>\n" +
15576     "                <tr ng-show=\"labels.length > 0\">\n" +
15577     "                    <th id=\"{{label.post}}\" class=\"dow\" ng-repeat=\"label in labels\" aria-hidden=\"true\"><span aria-hidden=\"true\">{{label.pre}}</span></th>\n" +
15578     "                </tr>\n" +
15579     "            </thead>\n" +
15580     "            <tbody b2b-key type=\"table\" columns=\"4\" >\n" +
15581     "                <tr ng-repeat=\"row in rows\">\n" +
15582     "                    <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" +
15583     "                        <div aria-hidden=\"true\"  tabindex=\"-1\" class=\"show-date\" ng-if=\"!(dt.oldMonth || dt.nextMonth)\">{{dt.label | limitTo: 3}}</div>\n" +
15584     "                    </td>\n" +
15585     "                </tr>\n" +
15586     "            </tbody>\n" +
15587     "            <tfoot>\n" +
15588     "                <tr ng-repeat=\"footer in footers\">\n" +
15589     "                    <th colspan=\"7\" class=\"text-left\" b2b-append-element=\"footer\"></th>\n" +
15590     "                </tr>\n" +
15591     "            </tfoot>\n" +
15592     "        </table>\n" +
15593     "    </div>\n" +
15594     "</div>");
15595 }]);
15596
15597 angular.module("b2bTemplate/monthSelector/monthSelector.html", []).run(["$templateCache", function($templateCache) {
15598   $templateCache.put("b2bTemplate/monthSelector/monthSelector.html",
15599     "<div>\n" +
15600     "    <span class=\"icon-primary-calendar span12\" ng-class=\"{'disabled': ngDisabled}\" ng-transclude></span>\n" +
15601     "</div>");
15602 }]);
15603
15604 angular.module("b2bTemplate/monthSelector/monthSelectorLink.html", []).run(["$templateCache", function($templateCache) {
15605   $templateCache.put("b2bTemplate/monthSelector/monthSelectorLink.html",
15606     "<div>\n" +
15607     "    <span class=\"span12\" ng-transclude></span>\n" +
15608     "</div>");
15609 }]);
15610
15611 angular.module("b2bTemplate/pagination/b2b-pagination.html", []).run(["$templateCache", function($templateCache) {
15612   $templateCache.put("b2bTemplate/pagination/b2b-pagination.html",
15613     "<div class=\"b2b-pager\">\n" +
15614     "    <div ng-if=\"notMobile && totalPages > 1\">\n" +
15615     "        <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" +
15616     "            <i class=\"icon-primary-left\"></i>\n" +
15617     "        </a>\n" +
15618     "        <a droppable=\"{{droppableAttribute}}\" tabindex=\"{{currentPage === 1 ? -1 : 0}}\" ng-class=\"{'b2b-pager__item--noclick': currentPage === 1}\" 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)\" aria-atomic=\"true\" aria-live=\"polite\">\n" +
15619     "            1<span class=\"offscreen-text\" ng-if=\"currentPage === 1\"> is selected</span>\n" +
15620     "        </a>\n" +
15621     "\n" +
15622     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage > 6\">...</span>\n" +
15623     "\n" +
15624     "        <a droppable=\"{{droppableAttribute}}\" 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-pager__item--droppable': droppableAttribute == true}\" b2b-accessibility-click=\"13,32\" ng-click=\"!checkSelectedPage(page) && selectPage(page, $event)\" aria-atomic=\"true\" aria-live=\"polite\">\n" +
15625     "            {{page}}<span class=\"offscreen-text\" ng-if=\"checkSelectedPage(page)\"> is selected</span>\n" +
15626     "        </a>\n" +
15627     "\n" +
15628     "        <span class=\"b2b-pager__item\" ng-if=\"totalPages > 10 && currentPage <= (totalPages - boundary)\">...</span>\n" +
15629     "\n" +
15630     "        <a droppable=\"{{droppableAttribute}}\" tabindex=\"{{currentPage === totalPages ? -1 : 0}}\" href=\"javascript:void(0);\" ng-class=\"{'b2b-pager__item--noclick': currentPage === totalPages}\" class=\"b2b-pager__item b2b-pager__item--link\" title=\"Page {{totalPages}}\" ng-if=\"totalPages > 10 && currentPage <= (totalPages - boundary)\" b2b-accessibility-click=\"13,32\" ng-click=\"selectPage(totalPages, $event)\" aria-atomic=\"true\" aria-live=\"polite\">\n" +
15631     "          {{totalPages}}<span class=\"offscreen-text\" ng-if=\"checkSelectedPage(page)\"> is selected</span>\n" +
15632     "        </a>\n" +
15633     "\n" +
15634     "\n" +
15635     "        <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" +
15636     "            <i class=\"icon-primary-right\"></i>\n" +
15637     "        </a>\n" +
15638     "        \n" +
15639     "        <div class=\"fieldLabel b2b-go-to-page\" ng-class=\"{'b2b-go-to-page-inline' : inputClass !== undefined }\" ng-show=\"totalPages > 20\">    \n" +
15640     "            <label for=\"{{inputId}}\">Go to Page:</label>\n" +
15641     "            <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" +
15642     "            <button class=\"btn-arrow\" ng-click=\"gotoBtnClick()\" ng-disabled=\"$parent.gotoPage !== 0 || $parent.gotoPage !== undefined\" aria-label=\"Go to\">\n" +
15643     "                <div class=\"btn btn-small btn-secondary\">\n" +
15644     "                    <i class=\"icon-primary-right\"></i>\n" +
15645     "                </div>\n" +
15646     "            </button>\n" +
15647     "        </div>\n" +
15648     "    </div>\n" +
15649     "    <div ng-if=\"isMobile && totalPages > 1\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\" ng-class=\"isMobile ? 'b2b-mobile-view': '' \">\n" +
15650     "        <a droppable=\"{{droppableAttribute}}\" 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" +
15651     "    </div>\n" +
15652     "</div>\n" +
15653     "");
15654 }]);
15655
15656 angular.module("b2bTemplate/paneSelector/paneSelector.html", []).run(["$templateCache", function($templateCache) {
15657   $templateCache.put("b2bTemplate/paneSelector/paneSelector.html",
15658     "<div class=\"panes\" ng-transclude></div>");
15659 }]);
15660
15661 angular.module("b2bTemplate/paneSelector/paneSelectorPane.html", []).run(["$templateCache", function($templateCache) {
15662   $templateCache.put("b2bTemplate/paneSelector/paneSelectorPane.html",
15663     "<div class=\"pane-block\" ng-transclude></div>");
15664 }]);
15665
15666 angular.module("b2bTemplate/profileCard/profileCard-addUser.html", []).run(["$templateCache", function($templateCache) {
15667   $templateCache.put("b2bTemplate/profileCard/profileCard-addUser.html",
15668     "<div  class=\"span3 b2b-profile-card b2b-add-user\">\n" +
15669     "    <div class=\"atcenter\">\n" +
15670     "        <div class=\"circle\"><i class=\"icon-primary-add-maximize\"></i></div>\n" +
15671     "        <div>Create new user</div>\n" +
15672     "    </div>\n" +
15673     "</div>");
15674 }]);
15675
15676 angular.module("b2bTemplate/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
15677   $templateCache.put("b2bTemplate/profileCard/profileCard.html",
15678     "<div class=\"span3 b2b-profile-card\">\n" +
15679     "    <div class=\"top-block\">\n" +
15680     "       <div class=\"profile-image\">\n" +
15681     "            <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +
15682     "            <span ng-if=\"!image\" class=\"default-img\">{{initials}}</span>\n" +
15683     "\n" +
15684     "            <h4 class=\"name\">{{profile.name}}</h4>\n" +
15685     "\n" +
15686     "            <p class=\"status\">\n" +
15687     "                <span class=\"status-icon\" ng-class=\"{'status-green':colorIcon==='green','status-red':colorIcon==='red','status-blue':colorIcon==='blue','status-yellow':colorIcon==='yellow'}\">   \n" +
15688     "                </span>\n" +
15689     "                <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
15690     "            </p>\n" +
15691     "        </div>\n" +
15692     "    </div>\n" +
15693     "    <div class=\"bottom-block\">\n" +
15694     "         <div class=\"profile-details\">\n" +
15695     "            <label>Username</label>\n" +
15696     "            <div ng-if=\"shouldClip(profile.userName)\" ng-mouseover=\"showUserNameTooltip = true;\" ng-mouseleave=\"showUserNameTooltip = false;\">\n" +
15697     "                <div ng-if=\"shouldClip(profile.userName)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showUserNameTooltip\">\n" +
15698     "                    {{profile.userName.slice(0, 25)+'...'}}\n" +
15699     "                    <div class=\"arrow\"></div>\n" +
15700     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
15701     "                        <div class=\"tooltip-size-control\">\n" +
15702     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
15703     "                                {{profile.userName}}\n" +
15704     "                            </div>\n" +
15705     "                        </div>\n" +
15706     "                    </div>\n" +
15707     "                </div>\n" +
15708     "            </div>\n" +
15709     "            <div ng-if=\"!shouldClip(profile.userName)\">\n" +
15710     "                {{profile.userName}}\n" +
15711     "            </div>\n" +
15712     "            <label>Email</label>\n" +
15713     "            <div ng-if=\"shouldClip(profile.email)\" ng-mouseover=\"showEmailTooltip = true;\" ng-mouseleave=\"showEmailTooltip = false;\">\n" +
15714     "                <div ng-if=\"shouldClip(profile.email)\" class=\"tooltip\" data-placement=\"bottom\" b2b-tooltip show-tooltip=\"showEmailTooltip\">\n" +
15715     "                    {{profile.email.slice(0, 25)+'...'}}\n" +
15716     "                    <div class=\"arrow\"></div>\n" +
15717     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
15718     "                        <div class=\"tooltip-size-control\">\n" +
15719     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
15720     "                                {{profile.email}}\n" +
15721     "                            </div>\n" +
15722     "                        </div>\n" +
15723     "                    </div>\n" +
15724     "                </div>\n" +
15725     "            </div>\n" +
15726     "            <div ng-if=\"!shouldClip(profile.email)\">\n" +
15727     "                {{profile.email}}\n" +
15728     "            </div>\n" +
15729     "            <label>Role</label>\n" +
15730     "            <div ng-if=\"shouldClip(profile.role)\" ng-mouseover=\"showRoleTooltip = true;\" ng-mouseleave=\"showRoleTooltip = false;\">\n" +
15731     "                <div ng-if=\"shouldClip(profile.role)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showRoleTooltip\">\n" +
15732     "                    {{profile.role.slice(0, 25)+'...'}}\n" +
15733     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
15734     "                        <div class=\"tooltip-size-control\">\n" +
15735     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
15736     "                                {{profile.role}}\n" +
15737     "                            </div>\n" +
15738     "                        </div>\n" +
15739     "                    </div>\n" +
15740     "                </div>\n" +
15741     "            </div>\n" +
15742     "            <div ng-if=\"!shouldClip(profile.role)\">\n" +
15743     "                {{profile.role}}\n" +
15744     "            </div>\n" +
15745     "            <label>Last login</label>\n" +
15746     "            <div ng-if=\"shouldClip(profile.lastLogin)\" ng-mouseover=\"showLastLoginTooltip = true;\" ng-mouseleave=\"showLastLoginTooltip = false;\">\n" +
15747     "                <div ng-if=\"shouldClip(profile.lastLogin)\" class=\"tooltip\" b2b-tooltip show-tooltip=\"showLastLoginTooltip\">\n" +
15748     "                    {{profile.lastLogin.slice(0, 25)+'...'}}\n" +
15749     "                    <div class=\"tooltip-wrapper\" role=\"tooltip\" aria-live=\"polite\" aria-atomic=\"false\" style=\"z-index:1111\">\n" +
15750     "                        <div class=\"tooltip-size-control\">\n" +
15751     "                            <div class=\"helpertext\" tabindex=\"-1\" role=\"tooltip\">\n" +
15752     "                                {{profile.lastLogin}}\n" +
15753     "                            </div>\n" +
15754     "                        </div>\n" +
15755     "                    </div>\n" +
15756     "                </div>\n" +
15757     "            </div>\n" +
15758     "            <div ng-if=\"!shouldClip(profile.lastLogin)\">\n" +
15759     "                {{profile.lastLogin}}\n" +
15760     "            </div>\n" +
15761     "         </div>\n" +
15762     "    </div>\n" +
15763     "</div>");
15764 }]);
15765
15766 angular.module("b2bTemplate/searchField/searchField.html", []).run(["$templateCache", function($templateCache) {
15767   $templateCache.put("b2bTemplate/searchField/searchField.html",
15768     "<div class=\"search-bar\">\n" +
15769     "    <div class='input-container' ng-blur=\"blurInput()\">\n" +
15770     "        <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}}\" />\n" +
15771     "            <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" +
15772     "    </div>\n" +
15773     "    <div class=\"search-suggestion-wrapper\" ng-if=\"filterList.length >=0\" ng-show=\"showListFlag\">\n" +
15774     "        <ul class=\"search-suggestion-list\" role=\"listbox\">      \n" +
15775     "            <li class=\"no-result\" ng-if=\"filterList.length == 0 && configObj.display\">{{configObj.resultText}}</li>\n" +
15776     "            <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" +
15777     "                {{item.title}}     \n" +
15778     "            </li>\n" +
15779     "        </ul>\n" +
15780     "    </div>\n" +
15781     "</div>");
15782 }]);
15783
15784 angular.module("b2bTemplate/seekBar/seekBar.html", []).run(["$templateCache", function($templateCache) {
15785   $templateCache.put("b2bTemplate/seekBar/seekBar.html",
15786     "<div class=\"b2b-seek-bar-container\" ng-class=\"{vertical:verticalSeekBar}\">\n" +
15787     "    <div class=\"b2b-seek-bar-track-container\">\n" +
15788     "        <div class=\"b2b-seek-bar-track\"></div>\n" +
15789     "        <div class=\"b2b-seek-bar-track-fill\"></div>\n" +
15790     "    </div>\n" +
15791     "    <div class=\"b2b-seek-bar-knob-container\" role=\"menu\"  >\n" +
15792     "        <div class=\"b2b-seek-bar-knob\" tabindex=\"0\" role=\"menuitem\"></div>\n" +
15793     "    </div>\n" +
15794     "</div>");
15795 }]);
15796
15797 angular.module("b2bTemplate/slider/slider.html", []).run(["$templateCache", function($templateCache) {
15798   $templateCache.put("b2bTemplate/slider/slider.html",
15799     "<div class=\"b2b-slider-container\" ng-class=\"{'vertical':verticalSlider}\">\n" +
15800     "    <div class=\"slider-track-container\">\n" +
15801     "        <div class=\"slider-track\"></div>\n" +
15802     "        <div class=\"slider-track-fill\" ng-style=\"{backgroundColor:trackFillColor}\"></div>\n" +
15803     "    </div>\n" +
15804     "    <div class=\"slider-knob-container\" ng-class=\"{'slider-knob-hidden':hideKnob}\">\n" +
15805     "        <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" +
15806     "    </div>\n" +
15807     "</div>");
15808 }]);
15809
15810 angular.module("b2bTemplate/spinButton/spinButton.html", []).run(["$templateCache", function($templateCache) {
15811   $templateCache.put("b2bTemplate/spinButton/spinButton.html",
15812     "<div class=\"btn-group btn-spinbutton-toggle\" ng-class=\"{'disabled': disabledFlag}\">\n" +
15813     "    <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" +
15814     "    <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" +
15815     "    <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" +
15816     "</div>");
15817 }]);
15818
15819 angular.module("b2bTemplate/statusTracker/statusTracker.html", []).run(["$templateCache", function($templateCache) {
15820   $templateCache.put("b2bTemplate/statusTracker/statusTracker.html",
15821     "<div class=\"b2b-status-tracker row\">\n" +
15822     "   <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" +
15823     "       <div class=\"btn btn-small btn-secondary\">\n" +
15824     "           <i class=\"icon-primary-left\"></i>\n" +
15825     "       </div>\n" +
15826     "   </button>\n" +
15827     "   <div ng-repeat=\"status in statuses\" class=\"b2b-status-tracker-step {{ status.state }}\" ng-show=\"isInViewport($index)\">\n" +
15828     "       <p class=\"b2b-status-tracker-heading\">{{status.heading}}</p>\n" +
15829     "       <div class=\"progress\">\n" +
15830     "           <div class=\"progress-bar\">\n" +
15831     "                   <span class=\"hidden-spoken\">\n" +
15832     "                   {{ removeCamelCase(status.state) }}\n" +
15833     "                   </span>\n" +
15834     "           </div>\n" +
15835     "       </div>\n" +
15836     "       <div class=\"b2b-status-tracker-estimate {{status.state}}\">\n" +
15837     "           <i ng-show=\"status.estimate !== '' && status.estimate !== undefined\" ng-class=\"b2bStatusTrackerConfig.icons[status.state]\"></i>\n" +
15838     "           &nbsp;\n" +
15839     "           <span ng-bind-html=\"status.estimate\"></span>\n" +
15840     "       </div>\n" +
15841     "       \n" +
15842     "       <div class=\"b2b-status-tracker-description\" ng-bind-html=\"status.description\"> \n" +
15843     "       </div>\n" +
15844     "   </div>\n" +
15845     "   <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" +
15846     "       <div class=\"btn btn-small btn-secondary\">\n" +
15847     "           <i class=\"icon-primary-right\"></i>\n" +
15848     "       </div>\n" +
15849     "   </button>\n" +
15850     "</div>");
15851 }]);
15852
15853 angular.module("b2bTemplate/stepTracker/stepTracker.html", []).run(["$templateCache", function($templateCache) {
15854   $templateCache.put("b2bTemplate/stepTracker/stepTracker.html",
15855     "<div class=\"b2b-step-tracker\">\n" +
15856     "    <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" +
15857     "           <div class=\"btn btn-left btn-small btn-secondary\"><i class=\"icon-primary-left\"></i></div>\n" +
15858     "   </button>\n" +
15859     "    <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" +
15860     "           <div class=\"btn btn-small btn-right btn-secondary\"><i class=\"icon-primary-right\"></i></div>\n" +
15861     "   </button>\n" +
15862     "    <ul class=\"b2b-steps\">\n" +
15863     "        <li ng-class=\"{'b2b-step-done':$index < currentIndex - 1 ,'b2b-step-on':$index == currentIndex - 1}\" \n" +
15864     "            ng-repeat=\"stepsItem in stepsItemsObject\" ng-show=\"isInViewport($index)\">\n" +
15865     "                   <p class=\"b2b-step-text\" data-sm-text=\"{{stepsItem.dataMobile}}\" data-large-text=\"{{stepsItem.dataDesktop}}\">{{stepsItem.text}}</p>\n" +
15866     "            <span class=\"hidden-spoken\">\n" +
15867     "                {{($index < currentIndex - 1)? 'Complete. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
15868     "                {{($index == currentIndex - 1)? 'In Progress. '+stepsItem.text+' '+stepsItem.dataMobile:''}} \n" +
15869     "                {{($index > currentIndex - 1)? 'Incomplete. '+stepsItem.text+' '+stepsItem.dataMobile:''}}\n" +
15870     "            </span>\n" +
15871     "        </li>\n" +
15872     "    </ul>\n" +
15873     "</div>");
15874 }]);
15875
15876 angular.module("b2bTemplate/switches/switches-spanish.html", []).run(["$templateCache", function($templateCache) {
15877   $templateCache.put("b2bTemplate/switches/switches-spanish.html",
15878     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
15879     "    <span class=\"btn-slider-on\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"activo\">activo</i></span>\n" +
15880     "    <span class=\"switch-handle\"></span>\n" +
15881     "    <span class=\"btn-slider-off\"><span class=\"hidden-spoken\">seleccione para hacer </span><i class=\"inactivo\">inactivo</i></span>\n" +
15882     "</div>");
15883 }]);
15884
15885 angular.module("b2bTemplate/switches/switches.html", []).run(["$templateCache", function($templateCache) {
15886   $templateCache.put("b2bTemplate/switches/switches.html",
15887     "<div class=\"switch-overlay\" aria-hidden=\"true\">\n" +
15888     "    <span class=\"btn-slider-on\">On</span>\n" +
15889     "    <span class=\"switch-handle\"></span>\n" +
15890     "    <span class=\"btn-slider-off\">Off</span>\n" +
15891     "</div>");
15892 }]);
15893
15894 angular.module("b2bTemplate/tableMessages/tableMessage.html", []).run(["$templateCache", function($templateCache) {
15895   $templateCache.put("b2bTemplate/tableMessages/tableMessage.html",
15896     "<div class=\"b2b-table-message\">\n" +
15897     "    <div class=\"b2b-message\" ng-if=\"msgType === 'noMatchingResults'\">\n" +
15898     "        <div class=\"b2b-magnify-glass\"></div>\n" +
15899     "        <div>\n" +
15900     "            <div ng-transclude></div>\n" +
15901     "        </div>\n" +
15902     "    </div>\n" +
15903     "    <div class=\"b2b-message\" ng-if=\"msgType == 'infoCouldNotLoad'\">\n" +
15904     "        <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" +
15905     "        <div>Oops!</div>\n" +
15906     "        <div>The information could not load at this time.</div>\n" +
15907     "        <div>Please <a href=\"javascript:void(0)\" title=\"Refresh the page\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
15908     "        </div>\n" +
15909     "    </div>\n" +
15910     "    <div class=\"b2b-message\" ng-if=\"msgType == 'magnifySearch'\">\n" +
15911     "        <div class=\"b2b-magnify-glass\"></div>\n" +
15912     "        <div>\n" +
15913     "            <p class=\"b2b-message-title\">Please input values to\n" +
15914     "                <br/> begin your search.</p>\n" +
15915     "        </div>\n" +
15916     "    </div>\n" +
15917     "    <div class=\"b2b-message\" ng-if=\"msgType === 'loadingTable'\">\n" +
15918     "        <div class=\"icon-primary-spinner-ddh b2b-loading-dots\"></div>\n" +
15919     "        <div ng-transclude></div>\n" +
15920     "    </div>\n" +
15921     "</div>\n" +
15922     "");
15923 }]);
15924
15925 angular.module("b2bTemplate/tableScrollbar/tableScrollbar.html", []).run(["$templateCache", function($templateCache) {
15926   $templateCache.put("b2bTemplate/tableScrollbar/tableScrollbar.html",
15927     "<div class=\"b2b-table-scrollbar\">\n" +
15928     "    <div class=\"b2b-scrollbar-arrows\">\n" +
15929     "        <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" +
15930     "        <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" +
15931     "    </div>\n" +
15932     "    <div class=\"b2b-table-inner-container\">\n" +
15933     "        <span ng-transclude></span>\n" +
15934     "    </div>\n" +
15935     "</div>");
15936 }]);
15937
15938 angular.module("b2bTemplate/tables/b2bTable.html", []).run(["$templateCache", function($templateCache) {
15939   $templateCache.put("b2bTemplate/tables/b2bTable.html",
15940     "<table ng-class=\"{'striped': responsive, 'complex-table': responsive && active}\" ng-transclude></table>");
15941 }]);
15942
15943 angular.module("b2bTemplate/tables/b2bTableBody.html", []).run(["$templateCache", function($templateCache) {
15944   $templateCache.put("b2bTemplate/tables/b2bTableBody.html",
15945     "<td ng-hide=\"isHidden()\" ng-transclude></td>");
15946 }]);
15947
15948 angular.module("b2bTemplate/tables/b2bTableHeaderSortable.html", []).run(["$templateCache", function($templateCache) {
15949   $templateCache.put("b2bTemplate/tables/b2bTableHeaderSortable.html",
15950     "<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" +
15951     "    <span ng-transclude></span>\n" +
15952     "    <i ng-class=\"{'icoArrows-sort-arrow active': sortPattern === 'ascending', 'icoArrows-sort-arrow active down': sortPattern === 'descending'}\"></i>\n" +
15953     "</th>");
15954 }]);
15955
15956 angular.module("b2bTemplate/tables/b2bTableHeaderUnsortable.html", []).run(["$templateCache", function($templateCache) {
15957   $templateCache.put("b2bTemplate/tables/b2bTableHeaderUnsortable.html",
15958     "<th scope=\"col\" ng-hide=\"isHidden()\" ng-transclude></th>");
15959 }]);
15960
15961 angular.module("b2bTemplate/tabs/b2bTab.html", []).run(["$templateCache", function($templateCache) {
15962   $templateCache.put("b2bTemplate/tabs/b2bTab.html",
15963     "<li role=\"tab\" aria-selected=\"{{isTabActive()}}\" aria-controls=\"{{tabPanelId}}\" class=\"tab\" \n" +
15964     "    ng-class=\"{'active': isTabActive()}\" ng-click=\"clickTab()\" ng-hide=\"tabItem.disabled\">\n" +
15965     "    <a href=\"javascript:void(0)\"  tabindex=\"{{(isTabActive() && tabItem.disabled)?-1:0}}\"\n" +
15966     "       ng-disabled=\"tabItem.disabled\" aria-expanded=\"{{(isTabActive() && !tabItem.disabled)}}\" \n" +
15967     "       b2b-accessibility-click=\"13,32\" ng-transclude></a>\n" +
15968     "    <span class=\"hidden-spoken\" ng-if=\"isTabActive()\">Active tab</span>\n" +
15969     "</li>");
15970 }]);
15971
15972 angular.module("b2bTemplate/tabs/b2bTabset.html", []).run(["$templateCache", function($templateCache) {
15973   $templateCache.put("b2bTemplate/tabs/b2bTabset.html",
15974     "<ul class=\"tabs promo-tabs\" role=\"tablist\" ng-transclude></ul>");
15975 }]);
15976
15977 angular.module("b2bTemplate/treeNav/groupedTree.html", []).run(["$templateCache", function($templateCache) {
15978   $templateCache.put("b2bTemplate/treeNav/groupedTree.html",
15979     "<ul role=\"group\">\n" +
15980     "    <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" +
15981     "        <ul role=\"group\">\n" +
15982     "            <b2b-member ng-repeat='member in value.childArray' member='member' time-delay='{{timeDelay}}' group-it='groupIt'></b2b-member>\n" +
15983     "        </ul>\n" +
15984     "    </li>\n" +
15985     "</ul>");
15986 }]);
15987
15988 angular.module("b2bTemplate/treeNav/treeMember.html", []).run(["$templateCache", function($templateCache) {
15989   $templateCache.put("b2bTemplate/treeNav/treeMember.html",
15990     "<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" +
15991     "    <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" +
15992     "        <span class=\"{{!member.child?'end':''}} b2b-tree-node-icon\">\n" +
15993     "            <i class=\"b2b-tree-expandCollapse-icon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
15994     "        </span>\n" +
15995     "         <div id=\"description_{{$id}}\" class=\"offscreen-text\">\n" +
15996     "           {{member.descriptionText}}\n" +
15997     "        </div>\n" +
15998     "        <div class=\"b2b-tree-tooltip\" ng-if=\"member.showTooltip\">\n" +
15999     "           <span class=\"b2b-tree-arrow-left\"></span>\n" +
16000     "           <div class=\"b2b-tree-tooltip-content\">\n" +
16001     "                   {{member.tooltipContent}}\n" +
16002     "           </div>  \n" +
16003     "        </div>\n" +
16004     "    </a>\n" +
16005     "</li>");
16006 }]);
16007
16008 angular.module("b2bTemplate/treeNav/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
16009   $templateCache.put("b2bTemplate/treeNav/ungroupedTree.html",
16010     "<ul role=\"{{setRole}}\"><b2b-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-member></ul>");
16011 }]);
16012
16013 angular.module("b2bTemplate/treeNodeCheckbox/groupedTree.html", []).run(["$templateCache", function($templateCache) {
16014   $templateCache.put("b2bTemplate/treeNodeCheckbox/groupedTree.html",
16015     "<ul role=\"group\">\n" +
16016     "    <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" +
16017     "        <span class=\"ng-hide\">\n" +
16018     "            <label class=\"checkbox\">\n" +
16019     "                <input type=\"checkbox\" tabindex=\"-1\" class=\"treeCheckBox grpTreeCheckbox\" style=\"margin-top:2px;\"/><i class=\"skin\"></i><span> {{(key)?key:''}}</span>\n" +
16020     "            </label>\n" +
16021     "        </span>\n" +
16022     "        <span>\n" +
16023     "            {{(key)?key:''}}    \n" +
16024     "        </span>\n" +
16025     "        <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" +
16026     "        <ul role=\"group\">\n" +
16027     "            <b2b-tree-member ng-repeat='member in value.childArray' member='member' group-it='groupIt'></b2b-tree-member>\n" +
16028     "        </ul>\n" +
16029     "    </li>\n" +
16030     "</ul>");
16031 }]);
16032
16033 angular.module("b2bTemplate/treeNodeCheckbox/treeMember.html", []).run(["$templateCache", function($templateCache) {
16034   $templateCache.put("b2bTemplate/treeNodeCheckbox/treeMember.html",
16035     "<li role=\"treeitem\" aria-expanded=\"{{(member.active?true:false)}}\" aria-label=\"{{member.name}}\" ng-class=\"{'bg':member.selected}\"  b2b-tree-node-link>\n" +
16036     "    <a tabindex=\"-1\" title=\"{{member.name}}\" href=\"javascript:void(0)\" ng-class=\"{'active':member.active}\">\n" +
16037     "           <span ng-show=\"member.displayCheckbox\">\n" +
16038     "                           <label class=\"checkbox\">\n" +
16039     "                <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" +
16040     "            </label>\n" +
16041     "        </span>\n" +
16042     "           <span ng-show=\"!member.displayCheckbox\">\n" +
16043     "                   {{member.name}} \n" +
16044     "           </span>\n" +
16045     "        <span class=\"nodeIcon {{!member.child?'end':''}}\">\n" +
16046     "            <i class=\"expandCollapseIcon\" ng-class=\"{'icon-primary-expanded':member.active}\"></i>\n" +
16047     "        </span>\n" +
16048     "    </a>\n" +
16049     "</li>");
16050 }]);
16051
16052 angular.module("b2bTemplate/treeNodeCheckbox/ungroupedTree.html", []).run(["$templateCache", function($templateCache) {
16053   $templateCache.put("b2bTemplate/treeNodeCheckbox/ungroupedTree.html",
16054     "<ul role=\"{{setRole}}\"><b2b-tree-member ng-repeat='member in collection' member='member' group-it='groupIt'></b2b-tree-member></ul>");
16055 }]);