rails-angularstrap 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +89 -0
  3. data/Rakefile +2 -0
  4. data/lib/rails/angularstrap.rb +8 -0
  5. data/lib/rails/angularstrap/version.rb +5 -0
  6. data/vendor/assets/javascripts/angular-strap/LICENSE.md +21 -0
  7. data/vendor/assets/javascripts/angular-strap/README.md +112 -0
  8. data/vendor/assets/javascripts/angular-strap/angular-strap.nuspec +23 -0
  9. data/vendor/assets/javascripts/angular-strap/bower.json +53 -0
  10. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.js +5014 -0
  11. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.min.js +11 -0
  12. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.min.js.map +1 -0
  13. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.tpl.js +89 -0
  14. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.tpl.min.js +8 -0
  15. data/vendor/assets/javascripts/angular-strap/dist/modules/affix.js +249 -0
  16. data/vendor/assets/javascripts/angular-strap/dist/modules/affix.min.js +9 -0
  17. data/vendor/assets/javascripts/angular-strap/dist/modules/affix.min.js.map +1 -0
  18. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.js +120 -0
  19. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.min.js +9 -0
  20. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.min.js.map +1 -0
  21. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.tpl.js +14 -0
  22. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.tpl.min.js +8 -0
  23. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.js +96 -0
  24. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.min.js +9 -0
  25. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.min.js.map +1 -0
  26. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.tpl.js +14 -0
  27. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.tpl.min.js +8 -0
  28. data/vendor/assets/javascripts/angular-strap/dist/modules/button.js +177 -0
  29. data/vendor/assets/javascripts/angular-strap/dist/modules/button.min.js +9 -0
  30. data/vendor/assets/javascripts/angular-strap/dist/modules/button.min.js.map +1 -0
  31. data/vendor/assets/javascripts/angular-strap/dist/modules/collapse.js +273 -0
  32. data/vendor/assets/javascripts/angular-strap/dist/modules/collapse.min.js +9 -0
  33. data/vendor/assets/javascripts/angular-strap/dist/modules/collapse.min.js.map +1 -0
  34. data/vendor/assets/javascripts/angular-strap/dist/modules/date-formatter.js +61 -0
  35. data/vendor/assets/javascripts/angular-strap/dist/modules/date-formatter.min.js +9 -0
  36. data/vendor/assets/javascripts/angular-strap/dist/modules/date-formatter.min.js.map +1 -0
  37. data/vendor/assets/javascripts/angular-strap/dist/modules/date-parser.js +273 -0
  38. data/vendor/assets/javascripts/angular-strap/dist/modules/date-parser.min.js +9 -0
  39. data/vendor/assets/javascripts/angular-strap/dist/modules/date-parser.min.js.map +1 -0
  40. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.js +640 -0
  41. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.min.js +9 -0
  42. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.min.js.map +1 -0
  43. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.tpl.js +14 -0
  44. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.tpl.min.js +8 -0
  45. data/vendor/assets/javascripts/angular-strap/dist/modules/debounce.js +62 -0
  46. data/vendor/assets/javascripts/angular-strap/dist/modules/debounce.min.js +9 -0
  47. data/vendor/assets/javascripts/angular-strap/dist/modules/debounce.min.js.map +1 -0
  48. data/vendor/assets/javascripts/angular-strap/dist/modules/dimensions.js +156 -0
  49. data/vendor/assets/javascripts/angular-strap/dist/modules/dimensions.min.js +9 -0
  50. data/vendor/assets/javascripts/angular-strap/dist/modules/dimensions.min.js.map +1 -0
  51. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.js +149 -0
  52. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.min.js +9 -0
  53. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.min.js.map +1 -0
  54. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.tpl.js +14 -0
  55. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.tpl.min.js +8 -0
  56. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.js +349 -0
  57. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.min.js +9 -0
  58. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.min.js.map +1 -0
  59. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.tpl.js +14 -0
  60. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.tpl.min.js +8 -0
  61. data/vendor/assets/javascripts/angular-strap/dist/modules/navbar.js +72 -0
  62. data/vendor/assets/javascripts/angular-strap/dist/modules/navbar.min.js +9 -0
  63. data/vendor/assets/javascripts/angular-strap/dist/modules/navbar.min.js.map +1 -0
  64. data/vendor/assets/javascripts/angular-strap/dist/modules/parse-options.js +76 -0
  65. data/vendor/assets/javascripts/angular-strap/dist/modules/parse-options.min.js +9 -0
  66. data/vendor/assets/javascripts/angular-strap/dist/modules/parse-options.min.js.map +1 -0
  67. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.js +112 -0
  68. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.min.js +9 -0
  69. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.min.js.map +1 -0
  70. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.tpl.js +14 -0
  71. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.tpl.min.js +8 -0
  72. data/vendor/assets/javascripts/angular-strap/dist/modules/raf.js +61 -0
  73. data/vendor/assets/javascripts/angular-strap/dist/modules/raf.min.js +9 -0
  74. data/vendor/assets/javascripts/angular-strap/dist/modules/raf.min.js.map +1 -0
  75. data/vendor/assets/javascripts/angular-strap/dist/modules/scrollspy.js +261 -0
  76. data/vendor/assets/javascripts/angular-strap/dist/modules/scrollspy.min.js +9 -0
  77. data/vendor/assets/javascripts/angular-strap/dist/modules/scrollspy.min.js.map +1 -0
  78. data/vendor/assets/javascripts/angular-strap/dist/modules/select.js +325 -0
  79. data/vendor/assets/javascripts/angular-strap/dist/modules/select.min.js +9 -0
  80. data/vendor/assets/javascripts/angular-strap/dist/modules/select.min.js.map +1 -0
  81. data/vendor/assets/javascripts/angular-strap/dist/modules/select.tpl.js +14 -0
  82. data/vendor/assets/javascripts/angular-strap/dist/modules/select.tpl.min.js +8 -0
  83. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.js +186 -0
  84. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.min.js +9 -0
  85. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.min.js.map +1 -0
  86. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.tpl.js +14 -0
  87. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.tpl.min.js +8 -0
  88. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.js +485 -0
  89. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.min.js +9 -0
  90. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.min.js.map +1 -0
  91. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.tpl.js +14 -0
  92. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.tpl.min.js +8 -0
  93. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.js +690 -0
  94. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.min.js +9 -0
  95. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.min.js.map +1 -0
  96. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.tpl.js +14 -0
  97. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.tpl.min.js +8 -0
  98. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.js +266 -0
  99. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.min.js +9 -0
  100. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.min.js.map +1 -0
  101. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.tpl.js +14 -0
  102. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.tpl.min.js +8 -0
  103. data/vendor/assets/javascripts/angular-strap/gulpfile.js +489 -0
  104. data/vendor/assets/javascripts/angular-strap/package.json +73 -0
  105. data/vendor/assets/javascripts/angular-strap/src/affix/affix.js +258 -0
  106. data/vendor/assets/javascripts/angular-strap/src/alert/alert.js +113 -0
  107. data/vendor/assets/javascripts/angular-strap/src/alert/alert.tpl.html +4 -0
  108. data/vendor/assets/javascripts/angular-strap/src/aside/aside.js +89 -0
  109. data/vendor/assets/javascripts/angular-strap/src/aside/aside.tpl.html +14 -0
  110. data/vendor/assets/javascripts/angular-strap/src/button/button.js +174 -0
  111. data/vendor/assets/javascripts/angular-strap/src/collapse/collapse.js +266 -0
  112. data/vendor/assets/javascripts/angular-strap/src/datepicker/datepicker.js +633 -0
  113. data/vendor/assets/javascripts/angular-strap/src/datepicker/datepicker.tpl.html +33 -0
  114. data/vendor/assets/javascripts/angular-strap/src/dropdown/dropdown.js +143 -0
  115. data/vendor/assets/javascripts/angular-strap/src/dropdown/dropdown.tpl.html +6 -0
  116. data/vendor/assets/javascripts/angular-strap/src/helpers/date-formatter.js +54 -0
  117. data/vendor/assets/javascripts/angular-strap/src/helpers/date-parser.js +266 -0
  118. data/vendor/assets/javascripts/angular-strap/src/helpers/debounce.js +55 -0
  119. data/vendor/assets/javascripts/angular-strap/src/helpers/dimensions.js +212 -0
  120. data/vendor/assets/javascripts/angular-strap/src/helpers/parse-options.js +69 -0
  121. data/vendor/assets/javascripts/angular-strap/src/helpers/raf.js +54 -0
  122. data/vendor/assets/javascripts/angular-strap/src/modal/modal.js +348 -0
  123. data/vendor/assets/javascripts/angular-strap/src/modal/modal.tpl.html +14 -0
  124. data/vendor/assets/javascripts/angular-strap/src/module.js +19 -0
  125. data/vendor/assets/javascripts/angular-strap/src/navbar/navbar.js +65 -0
  126. data/vendor/assets/javascripts/angular-strap/src/popover/popover.js +111 -0
  127. data/vendor/assets/javascripts/angular-strap/src/popover/popover.tpl.html +5 -0
  128. data/vendor/assets/javascripts/angular-strap/src/scrollspy/scrollspy.js +254 -0
  129. data/vendor/assets/javascripts/angular-strap/src/select/select.js +321 -0
  130. data/vendor/assets/javascripts/angular-strap/src/select/select.tpl.html +14 -0
  131. data/vendor/assets/javascripts/angular-strap/src/tab/tab.js +183 -0
  132. data/vendor/assets/javascripts/angular-strap/src/tab/tab.tpl.html +7 -0
  133. data/vendor/assets/javascripts/angular-strap/src/timepicker/timepicker.js +493 -0
  134. data/vendor/assets/javascripts/angular-strap/src/timepicker/timepicker.tpl.html +62 -0
  135. data/vendor/assets/javascripts/angular-strap/src/tooltip/tooltip.js +806 -0
  136. data/vendor/assets/javascripts/angular-strap/src/tooltip/tooltip.tpl.html +4 -0
  137. data/vendor/assets/javascripts/angular-strap/src/typeahead/typeahead.js +262 -0
  138. data/vendor/assets/javascripts/angular-strap/src/typeahead/typeahead.tpl.html +5 -0
  139. data/vendor/assets/javascripts/angular/README.md +64 -0
  140. data/vendor/assets/javascripts/angular/angular-csp.css +13 -0
  141. data/vendor/assets/javascripts/angular/angular.js +26181 -0
  142. data/vendor/assets/javascripts/angular/angular.min.js +250 -0
  143. data/vendor/assets/javascripts/angular/angular.min.js.gzip +0 -0
  144. data/vendor/assets/javascripts/angular/angular.min.js.map +8 -0
  145. data/vendor/assets/javascripts/angular/bower.json +8 -0
  146. data/vendor/assets/javascripts/angular/index.js +2 -0
  147. data/vendor/assets/javascripts/angular/package.json +25 -0
  148. metadata +237 -0
@@ -0,0 +1,7 @@
1
+ <ul class="nav" ng-class="$navClass" role="tablist">
2
+ <li ng-repeat="$pane in $panes track by $index" ng-class="[ $index == $panes.$active ? $activeClass : '', $pane.disabled ? 'disabled' : '' ]">
3
+ <a role="tab" data-toggle="tab" ng-click="!$pane.disabled && $setActive($index)" data-index="{{ $index }}" ng-bind-html="$pane.title"></a>
4
+ </li>
5
+ </ul>
6
+ <div ng-transclude class="tab-content">
7
+ </div>
@@ -0,0 +1,493 @@
1
+ 'use strict';
2
+
3
+ angular.module('mgcrea.ngStrap.timepicker', [
4
+ 'mgcrea.ngStrap.helpers.dateParser',
5
+ 'mgcrea.ngStrap.helpers.dateFormatter',
6
+ 'mgcrea.ngStrap.tooltip'])
7
+
8
+ .provider('$timepicker', function() {
9
+
10
+ var defaults = this.defaults = {
11
+ animation: 'am-fade',
12
+ prefixClass: 'timepicker',
13
+ placement: 'bottom-left',
14
+ template: 'timepicker/timepicker.tpl.html',
15
+ trigger: 'focus',
16
+ container: false,
17
+ keyboard: true,
18
+ html: false,
19
+ delay: 0,
20
+ // lang: $locale.id,
21
+ useNative: true,
22
+ timeType: 'date',
23
+ timeFormat: 'shortTime',
24
+ modelTimeFormat: null,
25
+ autoclose: false,
26
+ minTime: -Infinity,
27
+ maxTime: +Infinity,
28
+ length: 5,
29
+ hourStep: 1,
30
+ minuteStep: 5,
31
+ roundDisplay: false,
32
+ iconUp: 'glyphicon glyphicon-chevron-up',
33
+ iconDown: 'glyphicon glyphicon-chevron-down',
34
+ arrowBehavior: 'pager'
35
+ };
36
+
37
+ this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {
38
+
39
+ var bodyEl = angular.element($window.document.body);
40
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
41
+ var isTouch = ('createTouch' in $window.document) && isNative;
42
+ if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
43
+
44
+ function timepickerFactory(element, controller, config) {
45
+
46
+ var $timepicker = $tooltip(element, angular.extend({}, defaults, config));
47
+ var parentScope = config.scope;
48
+ var options = $timepicker.$options;
49
+ var scope = $timepicker.$scope;
50
+
51
+ var lang = options.lang;
52
+ var formatDate = function(date, format) {
53
+ return $dateFormatter.formatDate(date, format, lang);
54
+ };
55
+
56
+ function floorMinutes(time)
57
+ {
58
+ // coeff used to floor current time to nearest minuteStep interval
59
+ var coeff = 1000 * 60 * options.minuteStep;
60
+ return new Date(Math.floor(time.getTime() / coeff) * coeff);
61
+ }
62
+
63
+ // View vars
64
+
65
+ var selectedIndex = 0;
66
+ var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();
67
+ var startDate = controller.$dateValue || defaultDate;
68
+ var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};
69
+
70
+ var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);
71
+
72
+ var hoursFormat = $dateFormatter.hoursFormat(format),
73
+ timeSeparator = $dateFormatter.timeSeparator(format),
74
+ minutesFormat = $dateFormatter.minutesFormat(format),
75
+ showAM = $dateFormatter.showAM(format);
76
+
77
+ scope.$iconUp = options.iconUp;
78
+ scope.$iconDown = options.iconDown;
79
+
80
+ // Scope methods
81
+
82
+ scope.$select = function(date, index) {
83
+ $timepicker.select(date, index);
84
+ };
85
+ scope.$moveIndex = function(value, index) {
86
+ $timepicker.$moveIndex(value, index);
87
+ };
88
+ scope.$switchMeridian = function(date) {
89
+ $timepicker.switchMeridian(date);
90
+ };
91
+
92
+ // Public methods
93
+
94
+ $timepicker.update = function(date) {
95
+ // console.warn('$timepicker.update() newValue=%o', date);
96
+ if(angular.isDate(date) && !isNaN(date.getTime())) {
97
+ $timepicker.$date = date;
98
+ angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});
99
+ $timepicker.$build();
100
+ } else if(!$timepicker.$isBuilt) {
101
+ $timepicker.$build();
102
+ }
103
+ };
104
+
105
+ $timepicker.select = function(date, index, keep) {
106
+ // console.warn('$timepicker.select', date, scope.$mode);
107
+ if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);
108
+ if(!angular.isDate(date)) date = new Date(date);
109
+ if(index === 0) controller.$dateValue.setHours(date.getHours());
110
+ else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());
111
+ controller.$setViewValue(angular.copy(controller.$dateValue));
112
+ controller.$render();
113
+ if(options.autoclose && !keep) {
114
+ $timeout(function() { $timepicker.hide(true); });
115
+ }
116
+ };
117
+
118
+ $timepicker.switchMeridian = function(date) {
119
+ if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {
120
+ return;
121
+ }
122
+ var hours = (date || controller.$dateValue).getHours();
123
+ controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);
124
+ controller.$setViewValue(angular.copy(controller.$dateValue));
125
+ controller.$render();
126
+ };
127
+
128
+ // Protected methods
129
+
130
+ $timepicker.$build = function() {
131
+ // console.warn('$timepicker.$build() viewDate=%o', viewDate);
132
+ var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);
133
+ var hours = [], hour;
134
+ for(i = 0; i < options.length; i++) {
135
+ hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);
136
+ hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});
137
+ }
138
+ var minutes = [], minute;
139
+ for(i = 0; i < options.length; i++) {
140
+ minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);
141
+ minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});
142
+ }
143
+
144
+ var rows = [];
145
+ for(i = 0; i < options.length; i++) {
146
+ rows.push([hours[i], minutes[i]]);
147
+ }
148
+ scope.rows = rows;
149
+ scope.showAM = showAM;
150
+ scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;
151
+ scope.timeSeparator = timeSeparator;
152
+ $timepicker.$isBuilt = true;
153
+ };
154
+
155
+ $timepicker.$isSelected = function(date, index) {
156
+ if(!$timepicker.$date) return false;
157
+ else if(index === 0) {
158
+ return date.getHours() === $timepicker.$date.getHours();
159
+ } else if(index === 1) {
160
+ return date.getMinutes() === $timepicker.$date.getMinutes();
161
+ }
162
+ };
163
+
164
+ $timepicker.$isDisabled = function(date, index) {
165
+ var selectedTime;
166
+ if(index === 0) {
167
+ selectedTime = date.getTime() + viewDate.minute * 6e4;
168
+ } else if(index === 1) {
169
+ selectedTime = date.getTime() + viewDate.hour * 36e5;
170
+ }
171
+ return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;
172
+ };
173
+
174
+ scope.$arrowAction = function (value, index) {
175
+ if (options.arrowBehavior === 'picker') {
176
+ $timepicker.$setTimeByStep(value,index);
177
+ } else {
178
+ $timepicker.$moveIndex(value,index);
179
+ }
180
+ };
181
+
182
+ $timepicker.$setTimeByStep = function(value, index) {
183
+ var newDate = new Date($timepicker.$date);
184
+ var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;
185
+ var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;
186
+ if (index === 0) {
187
+ newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));
188
+ }
189
+ else {
190
+ newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));
191
+ }
192
+ $timepicker.select(newDate, index, true);
193
+ };
194
+
195
+ $timepicker.$moveIndex = function(value, index) {
196
+ var targetDate;
197
+ if(index === 0) {
198
+ targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);
199
+ angular.extend(viewDate, {hour: targetDate.getHours()});
200
+ } else if(index === 1) {
201
+ targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));
202
+ angular.extend(viewDate, {minute: targetDate.getMinutes()});
203
+ }
204
+ $timepicker.$build();
205
+ };
206
+
207
+ $timepicker.$onMouseDown = function(evt) {
208
+ // Prevent blur on mousedown on .dropdown-menu
209
+ if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();
210
+ evt.stopPropagation();
211
+ // Emulate click for mobile devices
212
+ if(isTouch) {
213
+ var targetEl = angular.element(evt.target);
214
+ if(targetEl[0].nodeName.toLowerCase() !== 'button') {
215
+ targetEl = targetEl.parent();
216
+ }
217
+ targetEl.triggerHandler('click');
218
+ }
219
+ };
220
+
221
+ $timepicker.$onKeyDown = function(evt) {
222
+ if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
223
+ evt.preventDefault();
224
+ evt.stopPropagation();
225
+
226
+ // Close on enter
227
+ if(evt.keyCode === 13) return $timepicker.hide(true);
228
+
229
+ // Navigate with keyboard
230
+ var newDate = new Date($timepicker.$date);
231
+ var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;
232
+ var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;
233
+ var lateralMove = /(37|39)/.test(evt.keyCode);
234
+ var count = 2 + showAM * 1;
235
+
236
+ // Navigate indexes (left, right)
237
+ if (lateralMove) {
238
+ if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;
239
+ else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;
240
+ }
241
+
242
+ // Update values (up, down)
243
+ var selectRange = [0, hoursLength];
244
+ if(selectedIndex === 0) {
245
+ if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));
246
+ else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));
247
+ // re-calculate hours length because we have changed hours value
248
+ hoursLength = formatDate(newDate, hoursFormat).length;
249
+ selectRange = [0, hoursLength];
250
+ } else if(selectedIndex === 1) {
251
+ if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));
252
+ else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));
253
+ // re-calculate minutes length because we have changes minutes value
254
+ minutesLength = formatDate(newDate, minutesFormat).length;
255
+ selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];
256
+ } else if(selectedIndex === 2) {
257
+ if(!lateralMove) $timepicker.switchMeridian();
258
+ selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];
259
+ }
260
+ $timepicker.select(newDate, selectedIndex, true);
261
+ createSelection(selectRange[0], selectRange[1]);
262
+ parentScope.$digest();
263
+ };
264
+
265
+ // Private
266
+
267
+ function createSelection(start, end) {
268
+ if(element[0].createTextRange) {
269
+ var selRange = element[0].createTextRange();
270
+ selRange.collapse(true);
271
+ selRange.moveStart('character', start);
272
+ selRange.moveEnd('character', end);
273
+ selRange.select();
274
+ } else if(element[0].setSelectionRange) {
275
+ element[0].setSelectionRange(start, end);
276
+ } else if(angular.isUndefined(element[0].selectionStart)) {
277
+ element[0].selectionStart = start;
278
+ element[0].selectionEnd = end;
279
+ }
280
+ }
281
+
282
+ function focusElement() {
283
+ element[0].focus();
284
+ }
285
+
286
+ // Overrides
287
+
288
+ var _init = $timepicker.init;
289
+ $timepicker.init = function() {
290
+ if(isNative && options.useNative) {
291
+ element.prop('type', 'time');
292
+ element.css('-webkit-appearance', 'textfield');
293
+ return;
294
+ } else if(isTouch) {
295
+ element.prop('type', 'text');
296
+ element.attr('readonly', 'true');
297
+ element.on('click', focusElement);
298
+ }
299
+ _init();
300
+ };
301
+
302
+ var _destroy = $timepicker.destroy;
303
+ $timepicker.destroy = function() {
304
+ if(isNative && options.useNative) {
305
+ element.off('click', focusElement);
306
+ }
307
+ _destroy();
308
+ };
309
+
310
+ var _show = $timepicker.show;
311
+ $timepicker.show = function() {
312
+ _show();
313
+ // use timeout to hookup the events to prevent
314
+ // event bubbling from being processed imediately.
315
+ $timeout(function() {
316
+ $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
317
+ if(options.keyboard) {
318
+ element.on('keydown', $timepicker.$onKeyDown);
319
+ }
320
+ }, 0, false);
321
+ };
322
+
323
+ var _hide = $timepicker.hide;
324
+ $timepicker.hide = function(blur) {
325
+ if(!$timepicker.$isShown) return;
326
+ $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
327
+ if(options.keyboard) {
328
+ element.off('keydown', $timepicker.$onKeyDown);
329
+ }
330
+ _hide(blur);
331
+ };
332
+
333
+ return $timepicker;
334
+
335
+ }
336
+
337
+ timepickerFactory.defaults = defaults;
338
+ return timepickerFactory;
339
+
340
+ };
341
+
342
+ })
343
+
344
+
345
+ .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {
346
+
347
+ var defaults = $timepicker.defaults;
348
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
349
+ var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
350
+
351
+ return {
352
+ restrict: 'EAC',
353
+ require: 'ngModel',
354
+ link: function postLink(scope, element, attr, controller) {
355
+
356
+ // Directive options
357
+ var options = {scope: scope, controller: controller};
358
+ angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) {
359
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
360
+ });
361
+
362
+ // use string regex match for boolean values
363
+ var falseValueRegExp = /^(false|0|)$/;
364
+ angular.forEach(['roundDisplay'], function(key) {
365
+ if(angular.isDefined(attr[key])) options[key] = !falseValueRegExp.test(attr[key]);
366
+ });
367
+
368
+ // Visibility binding support
369
+ attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
370
+ if(!timepicker || !angular.isDefined(newValue)) return;
371
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);
372
+ newValue === true ? timepicker.show() : timepicker.hide();
373
+ });
374
+
375
+ // Initialize timepicker
376
+ if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';
377
+ var timepicker = $timepicker(element, controller, options);
378
+ options = timepicker.$options;
379
+
380
+ var lang = options.lang;
381
+ var formatDate = function(date, format) {
382
+ return $dateFormatter.formatDate(date, format, lang);
383
+ };
384
+
385
+ // Initialize parser
386
+ var dateParser = $dateParser({format: options.timeFormat, lang: lang});
387
+
388
+ // Observe attributes for changes
389
+ angular.forEach(['minTime', 'maxTime'], function(key) {
390
+ // console.warn('attr.$observe(%s)', key, attr[key]);
391
+ angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
392
+ timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);
393
+ !isNaN(timepicker.$options[key]) && timepicker.$build();
394
+ validateAgainstMinMaxTime(controller.$dateValue);
395
+ });
396
+ });
397
+
398
+ // Watch model for changes
399
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
400
+ // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);
401
+ timepicker.update(controller.$dateValue);
402
+ }, true);
403
+
404
+ function validateAgainstMinMaxTime(parsedTime) {
405
+ if (!angular.isDate(parsedTime)) return;
406
+ var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;
407
+ var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;
408
+ var isValid = isMinValid && isMaxValid;
409
+ controller.$setValidity('date', isValid);
410
+ controller.$setValidity('min', isMinValid);
411
+ controller.$setValidity('max', isMaxValid);
412
+ // Only update the model when we have a valid date
413
+ if(!isValid) {
414
+ return;
415
+ }
416
+ controller.$dateValue = parsedTime;
417
+ }
418
+
419
+ // viewValue -> $parsers -> modelValue
420
+ controller.$parsers.unshift(function(viewValue) {
421
+ // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue);
422
+ // Null values should correctly reset the model value & validity
423
+ if(!viewValue) {
424
+ // BREAKING CHANGE:
425
+ // return null (not undefined) when input value is empty, so angularjs 1.3
426
+ // ngModelController can go ahead and run validators, like ngRequired
427
+ controller.$setValidity('date', true);
428
+ return null;
429
+ }
430
+ var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);
431
+ if(!parsedTime || isNaN(parsedTime.getTime())) {
432
+ controller.$setValidity('date', false);
433
+ // return undefined, causes ngModelController to
434
+ // invalidate model value
435
+ return;
436
+ } else {
437
+ validateAgainstMinMaxTime(parsedTime);
438
+ }
439
+ if(options.timeType === 'string') {
440
+ return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);
441
+ } else if(options.timeType === 'number') {
442
+ return controller.$dateValue.getTime();
443
+ } else if(options.timeType === 'unix') {
444
+ return controller.$dateValue.getTime() / 1000;
445
+ } else if(options.timeType === 'iso') {
446
+ return controller.$dateValue.toISOString();
447
+ } else {
448
+ return new Date(controller.$dateValue);
449
+ }
450
+ });
451
+
452
+ // modelValue -> $formatters -> viewValue
453
+ controller.$formatters.push(function(modelValue) {
454
+ // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
455
+ var date;
456
+ if(angular.isUndefined(modelValue) || modelValue === null) {
457
+ date = NaN;
458
+ } else if(angular.isDate(modelValue)) {
459
+ date = modelValue;
460
+ } else if(options.timeType === 'string') {
461
+ date = dateParser.parse(modelValue, null, options.modelTimeFormat);
462
+ } else if(options.timeType === 'unix') {
463
+ date = new Date(modelValue * 1000);
464
+ } else {
465
+ date = new Date(modelValue);
466
+ }
467
+ // Setup default value?
468
+ // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);
469
+ controller.$dateValue = date;
470
+ return getTimeFormattedString();
471
+ });
472
+
473
+ // viewValue -> element
474
+ controller.$render = function() {
475
+ // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);
476
+ element.val(getTimeFormattedString());
477
+ };
478
+
479
+ function getTimeFormattedString() {
480
+ return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);
481
+ }
482
+
483
+ // Garbage collection
484
+ scope.$on('$destroy', function() {
485
+ if (timepicker) timepicker.destroy();
486
+ options = null;
487
+ timepicker = null;
488
+ });
489
+
490
+ }
491
+ };
492
+
493
+ });