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,633 @@
1
+ 'use strict';
2
+
3
+ angular.module('mgcrea.ngStrap.datepicker', [
4
+ 'mgcrea.ngStrap.helpers.dateParser',
5
+ 'mgcrea.ngStrap.helpers.dateFormatter',
6
+ 'mgcrea.ngStrap.tooltip'])
7
+
8
+ .provider('$datepicker', function() {
9
+
10
+ var defaults = this.defaults = {
11
+ animation: 'am-fade',
12
+ prefixClass: 'datepicker',
13
+ placement: 'bottom-left',
14
+ template: 'datepicker/datepicker.tpl.html',
15
+ trigger: 'focus',
16
+ container: false,
17
+ keyboard: true,
18
+ html: false,
19
+ delay: 0,
20
+ // lang: $locale.id,
21
+ useNative: false,
22
+ dateType: 'date',
23
+ dateFormat: 'shortDate',
24
+ modelDateFormat: null,
25
+ dayFormat: 'dd',
26
+ monthFormat: 'MMM',
27
+ yearFormat: 'yyyy',
28
+ monthTitleFormat: 'MMMM yyyy',
29
+ yearTitleFormat: 'yyyy',
30
+ strictFormat: false,
31
+ autoclose: false,
32
+ minDate: -Infinity,
33
+ maxDate: +Infinity,
34
+ startView: 0,
35
+ minView: 0,
36
+ startWeek: 0,
37
+ daysOfWeekDisabled: '',
38
+ iconLeft: 'glyphicon glyphicon-chevron-left',
39
+ iconRight: 'glyphicon glyphicon-chevron-right'
40
+ };
41
+
42
+ this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {
43
+
44
+ var bodyEl = angular.element($window.document.body);
45
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
46
+ var isTouch = ('createTouch' in $window.document) && isNative;
47
+ if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
48
+
49
+ function DatepickerFactory(element, controller, config) {
50
+
51
+ var $datepicker = $tooltip(element, angular.extend({}, defaults, config));
52
+ var parentScope = config.scope;
53
+ var options = $datepicker.$options;
54
+ var scope = $datepicker.$scope;
55
+ if(options.startView) options.startView -= options.minView;
56
+
57
+ // View vars
58
+
59
+ var pickerViews = datepickerViews($datepicker);
60
+ $datepicker.$views = pickerViews.views;
61
+ var viewDate = pickerViews.viewDate;
62
+ scope.$mode = options.startView;
63
+ scope.$iconLeft = options.iconLeft;
64
+ scope.$iconRight = options.iconRight;
65
+ var $picker = $datepicker.$views[scope.$mode];
66
+
67
+ // Scope methods
68
+
69
+ scope.$select = function(date) {
70
+ $datepicker.select(date);
71
+ };
72
+ scope.$selectPane = function(value) {
73
+ $datepicker.$selectPane(value);
74
+ };
75
+ scope.$toggleMode = function() {
76
+ $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);
77
+ };
78
+
79
+ // Public methods
80
+
81
+ $datepicker.update = function(date) {
82
+ // console.warn('$datepicker.update() newValue=%o', date);
83
+ if(angular.isDate(date) && !isNaN(date.getTime())) {
84
+ $datepicker.$date = date;
85
+ $picker.update.call($picker, date);
86
+ }
87
+ // Build only if pristine
88
+ $datepicker.$build(true);
89
+ };
90
+
91
+ $datepicker.updateDisabledDates = function(dateRanges) {
92
+ options.disabledDateRanges = dateRanges;
93
+ for(var i = 0, l = scope.rows.length; i < l; i++) {
94
+ angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);
95
+ }
96
+ };
97
+
98
+ $datepicker.select = function(date, keep) {
99
+ // console.warn('$datepicker.select', date, scope.$mode);
100
+ if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);
101
+ if(!scope.$mode || keep) {
102
+ controller.$setViewValue(angular.copy(date));
103
+ controller.$render();
104
+ if(options.autoclose && !keep) {
105
+ $timeout(function() { $datepicker.hide(true); });
106
+ }
107
+ } else {
108
+ angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});
109
+ $datepicker.setMode(scope.$mode - 1);
110
+ $datepicker.$build();
111
+ }
112
+ };
113
+
114
+ $datepicker.setMode = function(mode) {
115
+ // console.warn('$datepicker.setMode', mode);
116
+ scope.$mode = mode;
117
+ $picker = $datepicker.$views[scope.$mode];
118
+ $datepicker.$build();
119
+ };
120
+
121
+ // Protected methods
122
+
123
+ $datepicker.$build = function(pristine) {
124
+ // console.warn('$datepicker.$build() viewDate=%o', viewDate);
125
+ if(pristine === true && $picker.built) return;
126
+ if(pristine === false && !$picker.built) return;
127
+ $picker.build.call($picker);
128
+ };
129
+
130
+ $datepicker.$updateSelected = function() {
131
+ for(var i = 0, l = scope.rows.length; i < l; i++) {
132
+ angular.forEach(scope.rows[i], updateSelected);
133
+ }
134
+ };
135
+
136
+ $datepicker.$isSelected = function(date) {
137
+ return $picker.isSelected(date);
138
+ };
139
+
140
+ $datepicker.$setDisabledEl = function(el) {
141
+ el.disabled = $picker.isDisabled(el.date);
142
+ };
143
+
144
+ $datepicker.$selectPane = function(value) {
145
+ var steps = $picker.steps;
146
+ // set targetDate to first day of month to avoid problems with
147
+ // date values rollover. This assumes the viewDate does not
148
+ // depend on the day of the month
149
+ var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));
150
+ angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});
151
+ $datepicker.$build();
152
+ };
153
+
154
+ $datepicker.$onMouseDown = function(evt) {
155
+ // Prevent blur on mousedown on .dropdown-menu
156
+ evt.preventDefault();
157
+ evt.stopPropagation();
158
+ // Emulate click for mobile devices
159
+ if(isTouch) {
160
+ var targetEl = angular.element(evt.target);
161
+ if(targetEl[0].nodeName.toLowerCase() !== 'button') {
162
+ targetEl = targetEl.parent();
163
+ }
164
+ targetEl.triggerHandler('click');
165
+ }
166
+ };
167
+
168
+ $datepicker.$onKeyDown = function(evt) {
169
+ if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
170
+ evt.preventDefault();
171
+ evt.stopPropagation();
172
+
173
+ if(evt.keyCode === 13) {
174
+ if(!scope.$mode) {
175
+ return $datepicker.hide(true);
176
+ } else {
177
+ return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });
178
+ }
179
+ }
180
+
181
+ // Navigate with keyboard
182
+ $picker.onKeyDown(evt);
183
+ parentScope.$digest();
184
+ };
185
+
186
+ // Private
187
+
188
+ function updateSelected(el) {
189
+ el.selected = $datepicker.$isSelected(el.date);
190
+ }
191
+
192
+ function focusElement() {
193
+ element[0].focus();
194
+ }
195
+
196
+ // Overrides
197
+
198
+ var _init = $datepicker.init;
199
+ $datepicker.init = function() {
200
+ if(isNative && options.useNative) {
201
+ element.prop('type', 'date');
202
+ element.css('-webkit-appearance', 'textfield');
203
+ return;
204
+ } else if(isTouch) {
205
+ element.prop('type', 'text');
206
+ element.attr('readonly', 'true');
207
+ element.on('click', focusElement);
208
+ }
209
+ _init();
210
+ };
211
+
212
+ var _destroy = $datepicker.destroy;
213
+ $datepicker.destroy = function() {
214
+ if(isNative && options.useNative) {
215
+ element.off('click', focusElement);
216
+ }
217
+ _destroy();
218
+ };
219
+
220
+ var _show = $datepicker.show;
221
+ $datepicker.show = function() {
222
+ _show();
223
+ // use timeout to hookup the events to prevent
224
+ // event bubbling from being processed imediately.
225
+ $timeout(function() {
226
+ // if $datepicker is no longer showing, don't setup events
227
+ if(!$datepicker.$isShown) return;
228
+ $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
229
+ if(options.keyboard) {
230
+ element.on('keydown', $datepicker.$onKeyDown);
231
+ }
232
+ }, 0, false);
233
+ };
234
+
235
+ var _hide = $datepicker.hide;
236
+ $datepicker.hide = function(blur) {
237
+ if(!$datepicker.$isShown) return;
238
+ $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
239
+ if(options.keyboard) {
240
+ element.off('keydown', $datepicker.$onKeyDown);
241
+ }
242
+ _hide(blur);
243
+ };
244
+
245
+ return $datepicker;
246
+
247
+ }
248
+
249
+ DatepickerFactory.defaults = defaults;
250
+ return DatepickerFactory;
251
+
252
+ };
253
+
254
+ })
255
+
256
+ .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {
257
+
258
+ var defaults = $datepicker.defaults;
259
+ var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);
260
+
261
+ return {
262
+ restrict: 'EAC',
263
+ require: 'ngModel',
264
+ link: function postLink(scope, element, attr, controller) {
265
+
266
+ // Directive options
267
+ var options = {scope: scope, controller: controller};
268
+ angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) {
269
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
270
+ });
271
+
272
+ // Visibility binding support
273
+ attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
274
+ if(!datepicker || !angular.isDefined(newValue)) return;
275
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);
276
+ newValue === true ? datepicker.show() : datepicker.hide();
277
+ });
278
+
279
+ // Initialize datepicker
280
+ var datepicker = $datepicker(element, controller, options);
281
+ options = datepicker.$options;
282
+ // Set expected iOS format
283
+ if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';
284
+
285
+ var lang = options.lang;
286
+
287
+ var formatDate = function(date, format) {
288
+ return $dateFormatter.formatDate(date, format, lang);
289
+ };
290
+
291
+ var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});
292
+
293
+ // Observe attributes for changes
294
+ angular.forEach(['minDate', 'maxDate'], function(key) {
295
+ // console.warn('attr.$observe(%s)', key, attr[key]);
296
+ angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {
297
+ // console.warn('attr.$observe(%s)=%o', key, newValue);
298
+ datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);
299
+ // Build only if dirty
300
+ !isNaN(datepicker.$options[key]) && datepicker.$build(false);
301
+ validateAgainstMinMaxDate(controller.$dateValue);
302
+ });
303
+ });
304
+
305
+ // Watch model for changes
306
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
307
+ datepicker.update(controller.$dateValue);
308
+ }, true);
309
+
310
+ // Normalize undefined/null/empty array,
311
+ // so that we don't treat changing from undefined->null as a change.
312
+ function normalizeDateRanges(ranges) {
313
+ if (!ranges || !ranges.length) return null;
314
+ return ranges;
315
+ }
316
+
317
+ if (angular.isDefined(attr.disabledDates)) {
318
+ scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {
319
+ disabledRanges = normalizeDateRanges(disabledRanges);
320
+ previousValue = normalizeDateRanges(previousValue);
321
+
322
+ if (disabledRanges) {
323
+ datepicker.updateDisabledDates(disabledRanges);
324
+ }
325
+ });
326
+ }
327
+
328
+ function validateAgainstMinMaxDate(parsedDate) {
329
+ if (!angular.isDate(parsedDate)) return;
330
+ var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;
331
+ var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;
332
+ var isValid = isMinValid && isMaxValid;
333
+ controller.$setValidity('date', isValid);
334
+ controller.$setValidity('min', isMinValid);
335
+ controller.$setValidity('max', isMaxValid);
336
+ // Only update the model when we have a valid date
337
+ if(isValid) controller.$dateValue = parsedDate;
338
+ }
339
+
340
+ // viewValue -> $parsers -> modelValue
341
+ controller.$parsers.unshift(function(viewValue) {
342
+ // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue);
343
+ // Null values should correctly reset the model value & validity
344
+ if(!viewValue) {
345
+ controller.$setValidity('date', true);
346
+ // BREAKING CHANGE:
347
+ // return null (not undefined) when input value is empty, so angularjs 1.3
348
+ // ngModelController can go ahead and run validators, like ngRequired
349
+ return null;
350
+ }
351
+ var parsedDate = dateParser.parse(viewValue, controller.$dateValue);
352
+ if(!parsedDate || isNaN(parsedDate.getTime())) {
353
+ controller.$setValidity('date', false);
354
+ // return undefined, causes ngModelController to
355
+ // invalidate model value
356
+ return;
357
+ } else {
358
+ validateAgainstMinMaxDate(parsedDate);
359
+ }
360
+ if(options.dateType === 'string') {
361
+ return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);
362
+ } else if(options.dateType === 'number') {
363
+ return controller.$dateValue.getTime();
364
+ } else if(options.dateType === 'unix') {
365
+ return controller.$dateValue.getTime() / 1000;
366
+ } else if(options.dateType === 'iso') {
367
+ return controller.$dateValue.toISOString();
368
+ } else {
369
+ return new Date(controller.$dateValue);
370
+ }
371
+ });
372
+
373
+ // modelValue -> $formatters -> viewValue
374
+ controller.$formatters.push(function(modelValue) {
375
+ // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
376
+ var date;
377
+ if(angular.isUndefined(modelValue) || modelValue === null) {
378
+ date = NaN;
379
+ } else if(angular.isDate(modelValue)) {
380
+ date = modelValue;
381
+ } else if(options.dateType === 'string') {
382
+ date = dateParser.parse(modelValue, null, options.modelDateFormat);
383
+ } else if(options.dateType === 'unix') {
384
+ date = new Date(modelValue * 1000);
385
+ } else {
386
+ date = new Date(modelValue);
387
+ }
388
+ // Setup default value?
389
+ // if(isNaN(date.getTime())) {
390
+ // var today = new Date();
391
+ // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);
392
+ // }
393
+ controller.$dateValue = date;
394
+ return getDateFormattedString();
395
+ });
396
+
397
+ // viewValue -> element
398
+ controller.$render = function() {
399
+ // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);
400
+ element.val(getDateFormattedString());
401
+ };
402
+
403
+ function getDateFormattedString() {
404
+ return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);
405
+ }
406
+
407
+ // Garbage collection
408
+ scope.$on('$destroy', function() {
409
+ if(datepicker) datepicker.destroy();
410
+ options = null;
411
+ datepicker = null;
412
+ });
413
+
414
+ }
415
+ };
416
+
417
+ })
418
+
419
+ .provider('datepickerViews', function() {
420
+
421
+ var defaults = this.defaults = {
422
+ dayFormat: 'dd',
423
+ daySplit: 7
424
+ };
425
+
426
+ // Split array into smaller arrays
427
+ function split(arr, size) {
428
+ var arrays = [];
429
+ while(arr.length > 0) {
430
+ arrays.push(arr.splice(0, size));
431
+ }
432
+ return arrays;
433
+ }
434
+
435
+ // Modulus operator
436
+ function mod(n, m) {
437
+ return ((n % m) + m) % m;
438
+ }
439
+
440
+ this.$get = function($dateFormatter, $dateParser, $sce) {
441
+
442
+ return function(picker) {
443
+
444
+ var scope = picker.$scope;
445
+ var options = picker.$options;
446
+
447
+ var lang = options.lang;
448
+ var formatDate = function(date, format) {
449
+ return $dateFormatter.formatDate(date, format, lang);
450
+ };
451
+ var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});
452
+
453
+ var weekDaysMin = $dateFormatter.weekdaysShort(lang);
454
+ var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));
455
+ var weekDaysLabelsHtml = $sce.trustAsHtml('<th class="dow text-center">' + weekDaysLabels.join('</th><th class="dow text-center">') + '</th>');
456
+
457
+ var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());
458
+ var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};
459
+ var timezoneOffset = startDate.getTimezoneOffset() * 6e4;
460
+
461
+ var views = [{
462
+ format: options.dayFormat,
463
+ split: 7,
464
+ steps: { month: 1 },
465
+ update: function(date, force) {
466
+ if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {
467
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
468
+ picker.$build();
469
+ } else if(date.getDate() !== viewDate.date) {
470
+ viewDate.date = picker.$date.getDate();
471
+ picker.$updateSelected();
472
+ }
473
+ },
474
+ build: function() {
475
+ var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();
476
+ var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();
477
+ var today = new Date().toDateString();
478
+ // Handle daylight time switch
479
+ if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);
480
+ var days = [], day;
481
+ for(var i = 0; i < 42; i++) { // < 7 * 6
482
+ day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));
483
+ days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});
484
+ }
485
+ scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);
486
+ scope.showLabels = true;
487
+ scope.labels = weekDaysLabelsHtml;
488
+ scope.rows = split(days, this.split);
489
+ this.built = true;
490
+ },
491
+ isSelected: function(date) {
492
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();
493
+ },
494
+ isDisabled: function(date) {
495
+ var time = date.getTime();
496
+
497
+ // Disabled because of min/max date.
498
+ if (time < options.minDate || time > options.maxDate) return true;
499
+
500
+ // Disabled due to being a disabled day of the week
501
+ if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;
502
+
503
+ // Disabled because of disabled date range.
504
+ if (options.disabledDateRanges) {
505
+ for (var i = 0; i < options.disabledDateRanges.length; i++) {
506
+ if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {
507
+ return true;
508
+ }
509
+ }
510
+ }
511
+
512
+ return false;
513
+ },
514
+ onKeyDown: function(evt) {
515
+ if (!picker.$date) {
516
+ return;
517
+ }
518
+ var actualTime = picker.$date.getTime();
519
+ var newDate;
520
+
521
+ if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);
522
+ else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);
523
+ else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);
524
+ else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);
525
+
526
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
527
+ }
528
+ }, {
529
+ name: 'month',
530
+ format: options.monthFormat,
531
+ split: 4,
532
+ steps: { year: 1 },
533
+ update: function(date, force) {
534
+ if(!this.built || date.getFullYear() !== viewDate.year) {
535
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
536
+ picker.$build();
537
+ } else if(date.getMonth() !== viewDate.month) {
538
+ angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});
539
+ picker.$updateSelected();
540
+ }
541
+ },
542
+ build: function() {
543
+ var firstMonth = new Date(viewDate.year, 0, 1);
544
+ var months = [], month;
545
+ for (var i = 0; i < 12; i++) {
546
+ month = new Date(viewDate.year, i, 1);
547
+ months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});
548
+ }
549
+ scope.title = formatDate(month, options.yearTitleFormat);
550
+ scope.showLabels = false;
551
+ scope.rows = split(months, this.split);
552
+ this.built = true;
553
+ },
554
+ isSelected: function(date) {
555
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();
556
+ },
557
+ isDisabled: function(date) {
558
+ var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);
559
+ return lastDate < options.minDate || date.getTime() > options.maxDate;
560
+ },
561
+ onKeyDown: function(evt) {
562
+ if (!picker.$date) {
563
+ return;
564
+ }
565
+ var actualMonth = picker.$date.getMonth();
566
+ var newDate = new Date(picker.$date);
567
+
568
+ if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);
569
+ else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);
570
+ else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);
571
+ else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);
572
+
573
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
574
+ }
575
+ }, {
576
+ name: 'year',
577
+ format: options.yearFormat,
578
+ split: 4,
579
+ steps: { year: 12 },
580
+ update: function(date, force) {
581
+ if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {
582
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
583
+ picker.$build();
584
+ } else if(date.getFullYear() !== viewDate.year) {
585
+ angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});
586
+ picker.$updateSelected();
587
+ }
588
+ },
589
+ build: function() {
590
+ var firstYear = viewDate.year - viewDate.year % (this.split * 3);
591
+ var years = [], year;
592
+ for (var i = 0; i < 12; i++) {
593
+ year = new Date(firstYear + i, 0, 1);
594
+ years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});
595
+ }
596
+ scope.title = years[0].label + '-' + years[years.length - 1].label;
597
+ scope.showLabels = false;
598
+ scope.rows = split(years, this.split);
599
+ this.built = true;
600
+ },
601
+ isSelected: function(date) {
602
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear();
603
+ },
604
+ isDisabled: function(date) {
605
+ var lastDate = +new Date(date.getFullYear() + 1, 0, 0);
606
+ return lastDate < options.minDate || date.getTime() > options.maxDate;
607
+ },
608
+ onKeyDown: function(evt) {
609
+ if (!picker.$date) {
610
+ return;
611
+ }
612
+ var actualYear = picker.$date.getFullYear(),
613
+ newDate = new Date(picker.$date);
614
+
615
+ if(evt.keyCode === 37) newDate.setYear(actualYear - 1);
616
+ else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);
617
+ else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);
618
+ else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);
619
+
620
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
621
+ }
622
+ }];
623
+
624
+ return {
625
+ views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,
626
+ viewDate: viewDate
627
+ };
628
+
629
+ };
630
+
631
+ };
632
+
633
+ });