engine2 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/Rakefile +138 -0
  4. data/conf/message.yaml +93 -0
  5. data/conf/message_pl.yaml +93 -0
  6. data/engine2.gemspec +34 -0
  7. data/lib/engine2.rb +34 -0
  8. data/lib/engine2/action.rb +217 -0
  9. data/lib/engine2/core.rb +572 -0
  10. data/lib/engine2/handler.rb +134 -0
  11. data/lib/engine2/meta.rb +969 -0
  12. data/lib/engine2/meta/decode_meta.rb +110 -0
  13. data/lib/engine2/meta/delete_meta.rb +73 -0
  14. data/lib/engine2/meta/form_meta.rb +144 -0
  15. data/lib/engine2/meta/infra_meta.rb +292 -0
  16. data/lib/engine2/meta/link_meta.rb +133 -0
  17. data/lib/engine2/meta/list_meta.rb +284 -0
  18. data/lib/engine2/meta/save_meta.rb +63 -0
  19. data/lib/engine2/meta/view_meta.rb +22 -0
  20. data/lib/engine2/model.rb +390 -0
  21. data/lib/engine2/models/Files.rb +38 -0
  22. data/lib/engine2/models/UserInfo.rb +24 -0
  23. data/lib/engine2/post_bootstrap.rb +83 -0
  24. data/lib/engine2/pre_bootstrap.rb +27 -0
  25. data/lib/engine2/scheme.rb +202 -0
  26. data/lib/engine2/templates.rb +229 -0
  27. data/lib/engine2/type_info.rb +342 -0
  28. data/lib/engine2/version.rb +9 -0
  29. data/public/assets/javascripts.js +13 -0
  30. data/public/assets/styles.css +4 -0
  31. data/public/css/angular-motion.css +1022 -0
  32. data/public/css/angular-ui-tree.min.css +1 -0
  33. data/public/css/app.css +196 -0
  34. data/public/css/bootstrap-additions.css +1560 -0
  35. data/public/css/bootstrap.min.css +11 -0
  36. data/public/css/font-awesome.min.css +4 -0
  37. data/public/favicon.ico +0 -0
  38. data/public/fonts/FontAwesome.otf +0 -0
  39. data/public/fonts/fontawesome-webfont.eot +0 -0
  40. data/public/fonts/fontawesome-webfont.svg +655 -0
  41. data/public/fonts/fontawesome-webfont.ttf +0 -0
  42. data/public/fonts/fontawesome-webfont.woff +0 -0
  43. data/public/fonts/fontawesome-webfont.woff2 +0 -0
  44. data/public/fonts/glyphicons-halflings-regular.eot +0 -0
  45. data/public/fonts/glyphicons-halflings-regular.svg +288 -0
  46. data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  47. data/public/fonts/glyphicons-halflings-regular.woff +0 -0
  48. data/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  49. data/public/images/file.png +0 -0
  50. data/public/images/folder-closed.png +0 -0
  51. data/public/images/folder.png +0 -0
  52. data/public/images/node-closed-2.png +0 -0
  53. data/public/images/node-closed-light.png +0 -0
  54. data/public/images/node-closed.png +0 -0
  55. data/public/images/node-opened-2.png +0 -0
  56. data/public/images/node-opened-light.png +0 -0
  57. data/public/images/node-opened.png +0 -0
  58. data/public/img/ajax-loader-dark.gif +0 -0
  59. data/public/img/ajax-loader-light.gif +0 -0
  60. data/public/img/ajax-loader.gif +0 -0
  61. data/public/js/angular-animate.js +4115 -0
  62. data/public/js/angular-cookies.js +322 -0
  63. data/public/js/angular-local-storage.js +455 -0
  64. data/public/js/angular-route.js +1022 -0
  65. data/public/js/angular-sanitize.js +717 -0
  66. data/public/js/angular-strap.js +4339 -0
  67. data/public/js/angular-strap.tpl.js +43 -0
  68. data/public/js/angular-ui-tree.js +1569 -0
  69. data/public/js/angular.js +30714 -0
  70. data/public/js/i18n/angular-locale_pl.js +115 -0
  71. data/public/js/lodash.custom.min.js +97 -0
  72. data/public/js/ng-file-upload-shim.min.js +2 -0
  73. data/public/js/ng-file-upload.min.js +3 -0
  74. data/views/app.coffee +3 -0
  75. data/views/engine2.coffee +557 -0
  76. data/views/engine2actions.coffee +849 -0
  77. data/views/engine2templates.coffee +0 -0
  78. data/views/fields/blob.slim +22 -0
  79. data/views/fields/bs_select.slim +10 -0
  80. data/views/fields/bsselect_picker.slim +18 -0
  81. data/views/fields/bsselect_picker_opt.slim +22 -0
  82. data/views/fields/checkbox.slim +11 -0
  83. data/views/fields/checkbox_buttons.slim +6 -0
  84. data/views/fields/checkbox_buttons_opt.slim +8 -0
  85. data/views/fields/currency.slim +10 -0
  86. data/views/fields/date.slim +21 -0
  87. data/views/fields/date_range.slim +44 -0
  88. data/views/fields/date_time.slim +42 -0
  89. data/views/fields/datetime.slim +42 -0
  90. data/views/fields/decimal.slim +11 -0
  91. data/views/fields/decimal_date.slim +22 -0
  92. data/views/fields/decimal_time.slim +26 -0
  93. data/views/fields/email.slim +13 -0
  94. data/views/fields/file_store.slim +61 -0
  95. data/views/fields/input_text.slim +14 -0
  96. data/views/fields/integer.slim +11 -0
  97. data/views/fields/list_bsselect.slim +18 -0
  98. data/views/fields/list_bsselect_opt.slim +21 -0
  99. data/views/fields/list_buttons.slim +3 -0
  100. data/views/fields/list_buttons_opt.slim +5 -0
  101. data/views/fields/list_select.slim +11 -0
  102. data/views/fields/list_select_opt.slim +15 -0
  103. data/views/fields/password.slim +14 -0
  104. data/views/fields/radio_checkbox.slim +10 -0
  105. data/views/fields/scaffold.slim +2 -0
  106. data/views/fields/scaffold_picker.slim +20 -0
  107. data/views/fields/select_picker.slim +12 -0
  108. data/views/fields/select_picker_opt.slim +16 -0
  109. data/views/fields/text_area.slim +10 -0
  110. data/views/fields/time.slim +22 -0
  111. data/views/fields/typeahead_picker.slim +25 -0
  112. data/views/index.slim +44 -0
  113. data/views/infra/index.slim +5 -0
  114. data/views/infra/inspect.slim +81 -0
  115. data/views/modals/close_m.slim +15 -0
  116. data/views/modals/confirm_m.slim +19 -0
  117. data/views/modals/empty_m.slim +12 -0
  118. data/views/modals/menu_m.slim +13 -0
  119. data/views/modals/yes_no_m.slim +19 -0
  120. data/views/panels/menu_m.slim +9 -0
  121. data/views/scaffold/confirm.slim +3 -0
  122. data/views/scaffold/fields.slim +10 -0
  123. data/views/scaffold/form.slim +11 -0
  124. data/views/scaffold/list.slim +42 -0
  125. data/views/scaffold/message.slim +3 -0
  126. data/views/scaffold/search.slim +20 -0
  127. data/views/scaffold/view.slim +18 -0
  128. data/views/search_fields/bsmselect_picker.slim +25 -0
  129. data/views/search_fields/bsselect_picker.slim +24 -0
  130. data/views/search_fields/checkbox.slim +11 -0
  131. data/views/search_fields/checkbox2.slim +14 -0
  132. data/views/search_fields/checkbox_buttons.slim +10 -0
  133. data/views/search_fields/date_range.slim +46 -0
  134. data/views/search_fields/decimal_date_range.slim +47 -0
  135. data/views/search_fields/input_text.slim +18 -0
  136. data/views/search_fields/integer.slim +18 -0
  137. data/views/search_fields/integer_range.slim +27 -0
  138. data/views/search_fields/list_bsmselect.slim +24 -0
  139. data/views/search_fields/list_bsselect.slim +22 -0
  140. data/views/search_fields/list_buttons.slim +8 -0
  141. data/views/search_fields/list_select.slim +17 -0
  142. data/views/search_fields/scaffold_picker.slim +19 -0
  143. data/views/search_fields/select_picker.slim +17 -0
  144. data/views/search_fields/typeahead_picker.slim +25 -0
  145. metadata +327 -0
@@ -0,0 +1,4339 @@
1
+ /**
2
+ * angular-strap
3
+ * @version v2.3.8 - 2016-03-31
4
+ * @link http://mgcrea.github.io/angular-strap
5
+ * @author Olivier Louvignes <olivier@mg-crea.com> (https://github.com/mgcrea)
6
+ * @license MIT License, http://www.opensource.org/licenses/MIT
7
+ */
8
+ (function(window, document, undefined) {
9
+ 'use strict';
10
+ bsCompilerService.$inject = [ '$q', '$http', '$injector', '$compile', '$controller', '$templateCache' ];
11
+ angular.module('mgcrea.ngStrap.tooltip', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$tooltip', function() {
12
+ var defaults = this.defaults = {
13
+ animation: 'am-fade',
14
+ customClass: '',
15
+ prefixClass: 'tooltip',
16
+ prefixEvent: 'tooltip',
17
+ container: false,
18
+ target: false,
19
+ placement: 'top',
20
+ templateUrl: 'tooltip/tooltip.tpl.html',
21
+ template: '',
22
+ titleTemplate: false,
23
+ trigger: 'hover focus',
24
+ keyboard: false,
25
+ html: false,
26
+ show: false,
27
+ title: '',
28
+ type: '',
29
+ delay: 0,
30
+ autoClose: false,
31
+ bsEnabled: true,
32
+ viewport: {
33
+ selector: 'body',
34
+ padding: 0
35
+ }
36
+ };
37
+ this.$get = [ '$window', '$rootScope', '$bsCompiler', '$q', '$templateCache', '$http', '$animate', '$sce', 'dimensions', '$$rAF', '$timeout', function($window, $rootScope, $bsCompiler, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {
38
+ var isTouch = 'createTouch' in $window.document;
39
+ var $body = angular.element($window.document);
40
+ function TooltipFactory(element, config) {
41
+ var $tooltip = {};
42
+ var options = $tooltip.$options = angular.extend({}, defaults, config);
43
+ var promise = $tooltip.$promise = $bsCompiler.compile(options);
44
+ var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
45
+ var nodeName = element[0].nodeName.toLowerCase();
46
+ if (options.delay && angular.isString(options.delay)) {
47
+ var split = options.delay.split(',').map(parseFloat);
48
+ options.delay = split.length > 1 ? {
49
+ show: split[0],
50
+ hide: split[1]
51
+ } : split[0];
52
+ }
53
+ $tooltip.$id = options.id || element.attr('id') || '';
54
+ if (options.title) {
55
+ scope.title = $sce.trustAsHtml(options.title);
56
+ }
57
+ scope.$setEnabled = function(isEnabled) {
58
+ scope.$$postDigest(function() {
59
+ $tooltip.setEnabled(isEnabled);
60
+ });
61
+ };
62
+ scope.$hide = function() {
63
+ scope.$$postDigest(function() {
64
+ $tooltip.hide();
65
+ });
66
+ };
67
+ scope.$show = function() {
68
+ scope.$$postDigest(function() {
69
+ $tooltip.show();
70
+ });
71
+ };
72
+ scope.$toggle = function() {
73
+ scope.$$postDigest(function() {
74
+ $tooltip.toggle();
75
+ });
76
+ };
77
+ $tooltip.$isShown = scope.$isShown = false;
78
+ var timeout;
79
+ var hoverState;
80
+ var compileData;
81
+ var tipElement;
82
+ var tipContainer;
83
+ var tipScope;
84
+ promise.then(function(data) {
85
+ compileData = data;
86
+ $tooltip.init();
87
+ });
88
+ $tooltip.init = function() {
89
+ if (options.delay && angular.isNumber(options.delay)) {
90
+ options.delay = {
91
+ show: options.delay,
92
+ hide: options.delay
93
+ };
94
+ }
95
+ if (options.container === 'self') {
96
+ tipContainer = element;
97
+ } else if (angular.isElement(options.container)) {
98
+ tipContainer = options.container;
99
+ } else if (options.container) {
100
+ tipContainer = findElement(options.container);
101
+ }
102
+ bindTriggerEvents();
103
+ if (options.target) {
104
+ options.target = angular.isElement(options.target) ? options.target : findElement(options.target);
105
+ }
106
+ if (options.show) {
107
+ scope.$$postDigest(function() {
108
+ if (options.trigger === 'focus') {
109
+ element[0].focus();
110
+ } else {
111
+ $tooltip.show();
112
+ }
113
+ });
114
+ }
115
+ };
116
+ $tooltip.destroy = function() {
117
+ unbindTriggerEvents();
118
+ destroyTipElement();
119
+ scope.$destroy();
120
+ };
121
+ $tooltip.enter = function() {
122
+ clearTimeout(timeout);
123
+ hoverState = 'in';
124
+ if (!options.delay || !options.delay.show) {
125
+ return $tooltip.show();
126
+ }
127
+ timeout = setTimeout(function() {
128
+ if (hoverState === 'in') $tooltip.show();
129
+ }, options.delay.show);
130
+ };
131
+ $tooltip.show = function() {
132
+ if (!options.bsEnabled || $tooltip.$isShown) return;
133
+ scope.$emit(options.prefixEvent + '.show.before', $tooltip);
134
+ var parent;
135
+ var after;
136
+ if (options.container) {
137
+ parent = tipContainer;
138
+ if (tipContainer[0].lastChild) {
139
+ after = angular.element(tipContainer[0].lastChild);
140
+ } else {
141
+ after = null;
142
+ }
143
+ } else {
144
+ parent = null;
145
+ after = element;
146
+ }
147
+ if (tipElement) destroyTipElement();
148
+ tipScope = $tooltip.$scope.$new();
149
+ tipElement = $tooltip.$element = compileData.link(tipScope, function(clonedElement, scope) {});
150
+ tipElement.css({
151
+ top: '-9999px',
152
+ left: '-9999px',
153
+ right: 'auto',
154
+ display: 'block',
155
+ visibility: 'hidden'
156
+ });
157
+ if (options.animation) tipElement.addClass(options.animation);
158
+ if (options.type) tipElement.addClass(options.prefixClass + '-' + options.type);
159
+ if (options.customClass) tipElement.addClass(options.customClass);
160
+ if (after) {
161
+ after.after(tipElement);
162
+ } else {
163
+ parent.prepend(tipElement);
164
+ }
165
+ $tooltip.$isShown = scope.$isShown = true;
166
+ safeDigest(scope);
167
+ $tooltip.$applyPlacement();
168
+ if (angular.version.minor <= 2) {
169
+ $animate.enter(tipElement, parent, after, enterAnimateCallback);
170
+ } else {
171
+ $animate.enter(tipElement, parent, after).then(enterAnimateCallback);
172
+ }
173
+ safeDigest(scope);
174
+ $$rAF(function() {
175
+ if (tipElement) tipElement.css({
176
+ visibility: 'visible'
177
+ });
178
+ if (options.keyboard) {
179
+ if (options.trigger !== 'focus') {
180
+ $tooltip.focus();
181
+ }
182
+ bindKeyboardEvents();
183
+ }
184
+ });
185
+ if (options.autoClose) {
186
+ bindAutoCloseEvents();
187
+ }
188
+ };
189
+ function enterAnimateCallback() {
190
+ scope.$emit(options.prefixEvent + '.show', $tooltip);
191
+ }
192
+ $tooltip.leave = function() {
193
+ clearTimeout(timeout);
194
+ hoverState = 'out';
195
+ if (!options.delay || !options.delay.hide) {
196
+ return $tooltip.hide();
197
+ }
198
+ timeout = setTimeout(function() {
199
+ if (hoverState === 'out') {
200
+ $tooltip.hide();
201
+ }
202
+ }, options.delay.hide);
203
+ };
204
+ var _blur;
205
+ var _tipToHide;
206
+ $tooltip.hide = function(blur) {
207
+ if (!$tooltip.$isShown) return;
208
+ scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
209
+ _blur = blur;
210
+ _tipToHide = tipElement;
211
+ if (angular.version.minor <= 2) {
212
+ $animate.leave(tipElement, leaveAnimateCallback);
213
+ } else {
214
+ $animate.leave(tipElement).then(leaveAnimateCallback);
215
+ }
216
+ $tooltip.$isShown = scope.$isShown = false;
217
+ safeDigest(scope);
218
+ if (options.keyboard && tipElement !== null) {
219
+ unbindKeyboardEvents();
220
+ }
221
+ if (options.autoClose && tipElement !== null) {
222
+ unbindAutoCloseEvents();
223
+ }
224
+ };
225
+ function leaveAnimateCallback() {
226
+ scope.$emit(options.prefixEvent + '.hide', $tooltip);
227
+ if (tipElement === _tipToHide) {
228
+ if (_blur && options.trigger === 'focus') {
229
+ return element[0].blur();
230
+ }
231
+ destroyTipElement();
232
+ }
233
+ }
234
+ $tooltip.toggle = function(evt) {
235
+ if (evt) {
236
+ evt.preventDefault();
237
+ }
238
+ if ($tooltip.$isShown) {
239
+ $tooltip.leave();
240
+ } else {
241
+ $tooltip.enter();
242
+ }
243
+ };
244
+ $tooltip.focus = function() {
245
+ tipElement[0].focus();
246
+ };
247
+ $tooltip.setEnabled = function(isEnabled) {
248
+ options.bsEnabled = isEnabled;
249
+ };
250
+ $tooltip.setViewport = function(viewport) {
251
+ options.viewport = viewport;
252
+ };
253
+ $tooltip.$applyPlacement = function() {
254
+ if (!tipElement) return;
255
+ var placement = options.placement;
256
+ var autoToken = /\s?auto?\s?/i;
257
+ var autoPlace = autoToken.test(placement);
258
+ if (autoPlace) {
259
+ placement = placement.replace(autoToken, '') || defaults.placement;
260
+ }
261
+ tipElement.addClass(options.placement);
262
+ var elementPosition = getPosition();
263
+ var tipWidth = tipElement.prop('offsetWidth');
264
+ var tipHeight = tipElement.prop('offsetHeight');
265
+ $tooltip.$viewport = options.viewport && findElement(options.viewport.selector || options.viewport);
266
+ if (autoPlace) {
267
+ var originalPlacement = placement;
268
+ var viewportPosition = getPosition($tooltip.$viewport);
269
+ if (/bottom/.test(originalPlacement) && elementPosition.bottom + tipHeight > viewportPosition.bottom) {
270
+ placement = originalPlacement.replace('bottom', 'top');
271
+ } else if (/top/.test(originalPlacement) && elementPosition.top - tipHeight < viewportPosition.top) {
272
+ placement = originalPlacement.replace('top', 'bottom');
273
+ }
274
+ if (/left/.test(originalPlacement) && elementPosition.left - tipWidth < viewportPosition.left) {
275
+ placement = placement.replace('left', 'right');
276
+ } else if (/right/.test(originalPlacement) && elementPosition.right + tipWidth > viewportPosition.width) {
277
+ placement = placement.replace('right', 'left');
278
+ }
279
+ tipElement.removeClass(originalPlacement).addClass(placement);
280
+ }
281
+ var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);
282
+ applyPlacement(tipPosition, placement);
283
+ };
284
+ $tooltip.$onKeyUp = function(evt) {
285
+ if (evt.which === 27 && $tooltip.$isShown) {
286
+ $tooltip.hide();
287
+ evt.stopPropagation();
288
+ }
289
+ };
290
+ $tooltip.$onFocusKeyUp = function(evt) {
291
+ if (evt.which === 27) {
292
+ element[0].blur();
293
+ evt.stopPropagation();
294
+ }
295
+ };
296
+ $tooltip.$onFocusElementMouseDown = function(evt) {
297
+ evt.preventDefault();
298
+ evt.stopPropagation();
299
+ if ($tooltip.$isShown) {
300
+ element[0].blur();
301
+ } else {
302
+ element[0].focus();
303
+ }
304
+ };
305
+ function bindTriggerEvents() {
306
+ var triggers = options.trigger.split(' ');
307
+ angular.forEach(triggers, function(trigger) {
308
+ if (trigger === 'click' || trigger === 'contextmenu') {
309
+ element.on(trigger, $tooltip.toggle);
310
+ } else if (trigger !== 'manual') {
311
+ element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
312
+ element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
313
+ if (nodeName === 'button' && trigger !== 'hover') {
314
+ element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
315
+ }
316
+ }
317
+ });
318
+ }
319
+ function unbindTriggerEvents() {
320
+ var triggers = options.trigger.split(' ');
321
+ for (var i = triggers.length; i--; ) {
322
+ var trigger = triggers[i];
323
+ if (trigger === 'click' || trigger === 'contextmenu') {
324
+ element.off(trigger, $tooltip.toggle);
325
+ } else if (trigger !== 'manual') {
326
+ element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
327
+ element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
328
+ if (nodeName === 'button' && trigger !== 'hover') {
329
+ element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
330
+ }
331
+ }
332
+ }
333
+ }
334
+ function bindKeyboardEvents() {
335
+ if (options.trigger !== 'focus') {
336
+ tipElement.on('keyup', $tooltip.$onKeyUp);
337
+ } else {
338
+ element.on('keyup', $tooltip.$onFocusKeyUp);
339
+ }
340
+ }
341
+ function unbindKeyboardEvents() {
342
+ if (options.trigger !== 'focus') {
343
+ tipElement.off('keyup', $tooltip.$onKeyUp);
344
+ } else {
345
+ element.off('keyup', $tooltip.$onFocusKeyUp);
346
+ }
347
+ }
348
+ var _autoCloseEventsBinded = false;
349
+ function bindAutoCloseEvents() {
350
+ $timeout(function() {
351
+ tipElement.on('click', stopEventPropagation);
352
+ $body.on('click', $tooltip.hide);
353
+ _autoCloseEventsBinded = true;
354
+ }, 0, false);
355
+ }
356
+ function unbindAutoCloseEvents() {
357
+ if (_autoCloseEventsBinded) {
358
+ tipElement.off('click', stopEventPropagation);
359
+ $body.off('click', $tooltip.hide);
360
+ _autoCloseEventsBinded = false;
361
+ }
362
+ }
363
+ function stopEventPropagation(event) {
364
+ event.stopPropagation();
365
+ }
366
+ function getPosition($element) {
367
+ $element = $element || (options.target || element);
368
+ var el = $element[0];
369
+ var isBody = el.tagName === 'BODY';
370
+ var elRect = el.getBoundingClientRect();
371
+ var rect = {};
372
+ for (var p in elRect) {
373
+ rect[p] = elRect[p];
374
+ }
375
+ if (rect.width === null) {
376
+ rect = angular.extend({}, rect, {
377
+ width: elRect.right - elRect.left,
378
+ height: elRect.bottom - elRect.top
379
+ });
380
+ }
381
+ var elOffset = isBody ? {
382
+ top: 0,
383
+ left: 0
384
+ } : dimensions.offset(el);
385
+ var scroll = {
386
+ scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0
387
+ };
388
+ var outerDims = isBody ? {
389
+ width: document.documentElement.clientWidth,
390
+ height: $window.innerHeight
391
+ } : null;
392
+ return angular.extend({}, rect, scroll, outerDims, elOffset);
393
+ }
394
+ function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
395
+ var offset;
396
+ var split = placement.split('-');
397
+ switch (split[0]) {
398
+ case 'right':
399
+ offset = {
400
+ top: position.top + position.height / 2 - actualHeight / 2,
401
+ left: position.left + position.width
402
+ };
403
+ break;
404
+
405
+ case 'bottom':
406
+ offset = {
407
+ top: position.top + position.height,
408
+ left: position.left + position.width / 2 - actualWidth / 2
409
+ };
410
+ break;
411
+
412
+ case 'left':
413
+ offset = {
414
+ top: position.top + position.height / 2 - actualHeight / 2,
415
+ left: position.left - actualWidth
416
+ };
417
+ break;
418
+
419
+ default:
420
+ offset = {
421
+ top: position.top - actualHeight,
422
+ left: position.left + position.width / 2 - actualWidth / 2
423
+ };
424
+ break;
425
+ }
426
+ if (!split[1]) {
427
+ return offset;
428
+ }
429
+ if (split[0] === 'top' || split[0] === 'bottom') {
430
+ switch (split[1]) {
431
+ case 'left':
432
+ offset.left = position.left;
433
+ break;
434
+
435
+ case 'right':
436
+ offset.left = position.left + position.width - actualWidth;
437
+ break;
438
+
439
+ default:
440
+ break;
441
+ }
442
+ } else if (split[0] === 'left' || split[0] === 'right') {
443
+ switch (split[1]) {
444
+ case 'top':
445
+ offset.top = position.top - actualHeight + position.height;
446
+ break;
447
+
448
+ case 'bottom':
449
+ offset.top = position.top;
450
+ break;
451
+
452
+ default:
453
+ break;
454
+ }
455
+ }
456
+ return offset;
457
+ }
458
+ function applyPlacement(offset, placement) {
459
+ var tip = tipElement[0];
460
+ var width = tip.offsetWidth;
461
+ var height = tip.offsetHeight;
462
+ var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10);
463
+ var marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);
464
+ if (isNaN(marginTop)) marginTop = 0;
465
+ if (isNaN(marginLeft)) marginLeft = 0;
466
+ offset.top = offset.top + marginTop;
467
+ offset.left = offset.left + marginLeft;
468
+ dimensions.setOffset(tip, angular.extend({
469
+ using: function(props) {
470
+ tipElement.css({
471
+ top: Math.round(props.top) + 'px',
472
+ left: Math.round(props.left) + 'px',
473
+ right: ''
474
+ });
475
+ }
476
+ }, offset), 0);
477
+ var actualWidth = tip.offsetWidth;
478
+ var actualHeight = tip.offsetHeight;
479
+ if (placement === 'top' && actualHeight !== height) {
480
+ offset.top = offset.top + height - actualHeight;
481
+ }
482
+ if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;
483
+ var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);
484
+ if (delta.left) {
485
+ offset.left += delta.left;
486
+ } else {
487
+ offset.top += delta.top;
488
+ }
489
+ dimensions.setOffset(tip, offset);
490
+ if (/top|right|bottom|left/.test(placement)) {
491
+ var isVertical = /top|bottom/.test(placement);
492
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight;
493
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';
494
+ replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);
495
+ }
496
+ }
497
+ function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {
498
+ var delta = {
499
+ top: 0,
500
+ left: 0
501
+ };
502
+ if (!$tooltip.$viewport) return delta;
503
+ var viewportPadding = options.viewport && options.viewport.padding || 0;
504
+ var viewportDimensions = getPosition($tooltip.$viewport);
505
+ if (/right|left/.test(placement)) {
506
+ var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll;
507
+ var bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;
508
+ if (topEdgeOffset < viewportDimensions.top) {
509
+ delta.top = viewportDimensions.top - topEdgeOffset;
510
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) {
511
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;
512
+ }
513
+ } else {
514
+ var leftEdgeOffset = position.left - viewportPadding;
515
+ var rightEdgeOffset = position.left + viewportPadding + actualWidth;
516
+ if (leftEdgeOffset < viewportDimensions.left) {
517
+ delta.left = viewportDimensions.left - leftEdgeOffset;
518
+ } else if (rightEdgeOffset > viewportDimensions.right) {
519
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;
520
+ }
521
+ }
522
+ return delta;
523
+ }
524
+ function replaceArrow(delta, dimension, isHorizontal) {
525
+ var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);
526
+ $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%').css(isHorizontal ? 'top' : 'left', '');
527
+ }
528
+ function destroyTipElement() {
529
+ clearTimeout(timeout);
530
+ if ($tooltip.$isShown && tipElement !== null) {
531
+ if (options.autoClose) {
532
+ unbindAutoCloseEvents();
533
+ }
534
+ if (options.keyboard) {
535
+ unbindKeyboardEvents();
536
+ }
537
+ }
538
+ if (tipScope) {
539
+ tipScope.$destroy();
540
+ tipScope = null;
541
+ }
542
+ if (tipElement) {
543
+ tipElement.remove();
544
+ tipElement = $tooltip.$element = null;
545
+ }
546
+ }
547
+ return $tooltip;
548
+ }
549
+ function safeDigest(scope) {
550
+ scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest();
551
+ }
552
+ function findElement(query, element) {
553
+ return angular.element((element || document).querySelectorAll(query));
554
+ }
555
+ return TooltipFactory;
556
+ } ];
557
+ }).directive('bsTooltip', [ '$window', '$location', '$sce', '$tooltip', '$$rAF', function($window, $location, $sce, $tooltip, $$rAF) {
558
+ return {
559
+ restrict: 'EAC',
560
+ scope: true,
561
+ link: function postLink(scope, element, attr, transclusion) {
562
+ var tooltip;
563
+ var options = {
564
+ scope: scope
565
+ };
566
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'titleTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id' ], function(key) {
567
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
568
+ });
569
+ var falseValueRegExp = /^(false|0|)$/i;
570
+ angular.forEach([ 'html', 'container' ], function(key) {
571
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) {
572
+ options[key] = false;
573
+ }
574
+ });
575
+ var dataTarget = element.attr('data-target');
576
+ if (angular.isDefined(dataTarget)) {
577
+ if (falseValueRegExp.test(dataTarget)) {
578
+ options.target = false;
579
+ } else {
580
+ options.target = dataTarget;
581
+ }
582
+ }
583
+ if (!scope.hasOwnProperty('title')) {
584
+ scope.title = '';
585
+ }
586
+ attr.$observe('title', function(newValue) {
587
+ if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {
588
+ var oldValue = scope.title;
589
+ scope.title = $sce.trustAsHtml(newValue);
590
+ if (angular.isDefined(oldValue)) {
591
+ $$rAF(function() {
592
+ if (tooltip) tooltip.$applyPlacement();
593
+ });
594
+ }
595
+ }
596
+ });
597
+ attr.$observe('disabled', function(newValue) {
598
+ if (newValue && tooltip.$isShown) {
599
+ tooltip.hide();
600
+ }
601
+ });
602
+ if (attr.bsTooltip) {
603
+ scope.$watch(attr.bsTooltip, function(newValue, oldValue) {
604
+ if (angular.isObject(newValue)) {
605
+ angular.extend(scope, newValue);
606
+ } else {
607
+ scope.title = newValue;
608
+ }
609
+ if (angular.isDefined(oldValue)) {
610
+ $$rAF(function() {
611
+ if (tooltip) tooltip.$applyPlacement();
612
+ });
613
+ }
614
+ }, true);
615
+ }
616
+ if (attr.bsShow) {
617
+ scope.$watch(attr.bsShow, function(newValue, oldValue) {
618
+ if (!tooltip || !angular.isDefined(newValue)) return;
619
+ if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);
620
+ if (newValue === true) {
621
+ tooltip.show();
622
+ } else {
623
+ tooltip.hide();
624
+ }
625
+ });
626
+ }
627
+ if (attr.bsEnabled) {
628
+ scope.$watch(attr.bsEnabled, function(newValue, oldValue) {
629
+ if (!tooltip || !angular.isDefined(newValue)) return;
630
+ if (angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);
631
+ if (newValue === false) {
632
+ tooltip.setEnabled(false);
633
+ } else {
634
+ tooltip.setEnabled(true);
635
+ }
636
+ });
637
+ }
638
+ if (attr.viewport) {
639
+ scope.$watch(attr.viewport, function(newValue) {
640
+ if (!tooltip || !angular.isDefined(newValue)) return;
641
+ tooltip.setViewport(newValue);
642
+ });
643
+ }
644
+ tooltip = $tooltip(element, options);
645
+ scope.$on('$destroy', function() {
646
+ if (tooltip) tooltip.destroy();
647
+ options = null;
648
+ tooltip = null;
649
+ });
650
+ }
651
+ };
652
+ } ]);
653
+ angular.module('mgcrea.ngStrap.typeahead', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$typeahead', function() {
654
+ var defaults = this.defaults = {
655
+ animation: 'am-fade',
656
+ prefixClass: 'typeahead',
657
+ prefixEvent: '$typeahead',
658
+ placement: 'bottom-left',
659
+ templateUrl: 'typeahead/typeahead.tpl.html',
660
+ trigger: 'focus',
661
+ container: false,
662
+ keyboard: true,
663
+ html: false,
664
+ delay: 0,
665
+ minLength: 1,
666
+ filter: 'bsAsyncFilter',
667
+ limit: 6,
668
+ autoSelect: false,
669
+ comparator: '',
670
+ trimValue: true
671
+ };
672
+ this.$get = [ '$window', '$rootScope', '$tooltip', '$$rAF', '$timeout', function($window, $rootScope, $tooltip, $$rAF, $timeout) {
673
+ function TypeaheadFactory(element, controller, config) {
674
+ var $typeahead = {};
675
+ var options = angular.extend({}, defaults, config);
676
+ $typeahead = $tooltip(element, options);
677
+ var parentScope = config.scope;
678
+ var scope = $typeahead.$scope;
679
+ scope.$resetMatches = function() {
680
+ scope.$matches = [];
681
+ scope.$activeIndex = options.autoSelect ? 0 : -1;
682
+ };
683
+ scope.$resetMatches();
684
+ scope.$activate = function(index) {
685
+ scope.$$postDigest(function() {
686
+ $typeahead.activate(index);
687
+ });
688
+ };
689
+ scope.$select = function(index, evt) {
690
+ scope.$$postDigest(function() {
691
+ $typeahead.select(index);
692
+ });
693
+ };
694
+ scope.$isVisible = function() {
695
+ return $typeahead.$isVisible();
696
+ };
697
+ $typeahead.update = function(matches) {
698
+ scope.$matches = matches;
699
+ if (scope.$activeIndex >= matches.length) {
700
+ scope.$activeIndex = options.autoSelect ? 0 : -1;
701
+ }
702
+ safeDigest(scope);
703
+ $$rAF($typeahead.$applyPlacement);
704
+ };
705
+ $typeahead.activate = function(index) {
706
+ scope.$activeIndex = index;
707
+ };
708
+ $typeahead.select = function(index) {
709
+ if (index === -1) return;
710
+ var value = scope.$matches[index].value;
711
+ controller.$setViewValue(value);
712
+ controller.$render();
713
+ scope.$resetMatches();
714
+ if (parentScope) parentScope.$digest();
715
+ scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);
716
+ };
717
+ $typeahead.$isVisible = function() {
718
+ if (!options.minLength || !controller) {
719
+ return !!scope.$matches.length;
720
+ }
721
+ return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;
722
+ };
723
+ $typeahead.$getIndex = function(value) {
724
+ var index;
725
+ for (index = scope.$matches.length; index--; ) {
726
+ if (angular.equals(scope.$matches[index].value, value)) break;
727
+ }
728
+ return index;
729
+ };
730
+ $typeahead.$onMouseDown = function(evt) {
731
+ evt.preventDefault();
732
+ evt.stopPropagation();
733
+ };
734
+ $typeahead.$onKeyDown = function(evt) {
735
+ if (!/(38|40|13)/.test(evt.keyCode)) return;
736
+ if ($typeahead.$isVisible() && !(evt.keyCode === 13 && scope.$activeIndex === -1)) {
737
+ evt.preventDefault();
738
+ evt.stopPropagation();
739
+ }
740
+ if (evt.keyCode === 13 && scope.$matches.length) {
741
+ $typeahead.select(scope.$activeIndex);
742
+ } else if (evt.keyCode === 38 && scope.$activeIndex > 0) {
743
+ scope.$activeIndex--;
744
+ } else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) {
745
+ scope.$activeIndex++;
746
+ } else if (angular.isUndefined(scope.$activeIndex)) {
747
+ scope.$activeIndex = 0;
748
+ }
749
+ scope.$digest();
750
+ };
751
+ var show = $typeahead.show;
752
+ $typeahead.show = function() {
753
+ show();
754
+ $timeout(function() {
755
+ if ($typeahead.$element) {
756
+ $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);
757
+ if (options.keyboard) {
758
+ if (element) element.on('keydown', $typeahead.$onKeyDown);
759
+ }
760
+ }
761
+ }, 0, false);
762
+ };
763
+ var hide = $typeahead.hide;
764
+ $typeahead.hide = function() {
765
+ if ($typeahead.$element) $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);
766
+ if (options.keyboard) {
767
+ if (element) element.off('keydown', $typeahead.$onKeyDown);
768
+ }
769
+ if (!options.autoSelect) {
770
+ $typeahead.activate(-1);
771
+ }
772
+ hide();
773
+ };
774
+ return $typeahead;
775
+ }
776
+ function safeDigest(scope) {
777
+ scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest();
778
+ }
779
+ TypeaheadFactory.defaults = defaults;
780
+ return TypeaheadFactory;
781
+ } ];
782
+ }).filter('bsAsyncFilter', [ '$filter', function($filter) {
783
+ return function(array, expression, comparator) {
784
+ if (array && angular.isFunction(array.then)) {
785
+ return array.then(function(results) {
786
+ return $filter('filter')(results, expression, comparator);
787
+ });
788
+ }
789
+ return $filter('filter')(array, expression, comparator);
790
+ };
791
+ } ]).directive('bsTypeahead', [ '$window', '$parse', '$q', '$typeahead', '$parseOptions', function($window, $parse, $q, $typeahead, $parseOptions) {
792
+ var defaults = $typeahead.defaults;
793
+ return {
794
+ restrict: 'EAC',
795
+ require: 'ngModel',
796
+ link: function postLink(scope, element, attr, controller) {
797
+ element.off('change');
798
+ var options = {
799
+ scope: scope
800
+ };
801
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'autoSelect', 'comparator', 'id', 'prefixEvent', 'prefixClass' ], function(key) {
802
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
803
+ });
804
+ var falseValueRegExp = /^(false|0|)$/i;
805
+ angular.forEach([ 'html', 'container', 'trimValue', 'filter' ], function(key) {
806
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
807
+ });
808
+ if (!element.attr('autocomplete')) element.attr('autocomplete', 'off');
809
+ var filter = angular.isDefined(options.filter) ? options.filter : defaults.filter;
810
+ var limit = options.limit || defaults.limit;
811
+ var comparator = options.comparator || defaults.comparator;
812
+ var bsOptions = attr.bsOptions;
813
+ if (filter) {
814
+ bsOptions += ' | ' + filter + ':$viewValue';
815
+ if (comparator) bsOptions += ':' + comparator;
816
+ }
817
+ if (limit) bsOptions += ' | limitTo:' + limit;
818
+ var parsedOptions = $parseOptions(bsOptions);
819
+ var typeahead = $typeahead(element, controller, options);
820
+ if (options.watchOptions) {
821
+ var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim();
822
+ scope.$watchCollection(watchedOptions, function(newValue, oldValue) {
823
+ parsedOptions.valuesFn(scope, controller).then(function(values) {
824
+ typeahead.update(values);
825
+ controller.$render();
826
+ });
827
+ });
828
+ }
829
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
830
+ scope.$modelValue = newValue;
831
+ parsedOptions.valuesFn(scope, controller).then(function(values) {
832
+ if (options.selectMode && !values.length && newValue.length > 0) {
833
+ controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));
834
+ return;
835
+ }
836
+ if (values.length > limit) values = values.slice(0, limit);
837
+ typeahead.update(values);
838
+ controller.$render();
839
+ });
840
+ });
841
+ controller.$formatters.push(function(modelValue) {
842
+ var displayValue = parsedOptions.displayValue(modelValue);
843
+ if (displayValue) {
844
+ return displayValue;
845
+ }
846
+ if (angular.isDefined(modelValue) && typeof modelValue !== 'object') {
847
+ return modelValue;
848
+ }
849
+ return '';
850
+ });
851
+ controller.$render = function() {
852
+ if (controller.$isEmpty(controller.$viewValue)) {
853
+ return element.val('');
854
+ }
855
+ var index = typeahead.$getIndex(controller.$modelValue);
856
+ var selected = index !== -1 ? typeahead.$scope.$matches[index].label : controller.$viewValue;
857
+ selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;
858
+ var value = selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '') : '';
859
+ element.val(options.trimValue === false ? value : value.trim());
860
+ };
861
+ scope.$on('$destroy', function() {
862
+ if (typeahead) typeahead.destroy();
863
+ options = null;
864
+ typeahead = null;
865
+ });
866
+ }
867
+ };
868
+ } ]);
869
+ angular.module('mgcrea.ngStrap.timepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$timepicker', function() {
870
+ var defaults = this.defaults = {
871
+ animation: 'am-fade',
872
+ prefixClass: 'timepicker',
873
+ placement: 'bottom-left',
874
+ templateUrl: 'timepicker/timepicker.tpl.html',
875
+ trigger: 'focus',
876
+ container: false,
877
+ keyboard: true,
878
+ html: false,
879
+ delay: 0,
880
+ useNative: true,
881
+ timeType: 'date',
882
+ timeFormat: 'shortTime',
883
+ timezone: null,
884
+ modelTimeFormat: null,
885
+ autoclose: false,
886
+ minTime: -Infinity,
887
+ maxTime: +Infinity,
888
+ length: 5,
889
+ hourStep: 1,
890
+ minuteStep: 5,
891
+ secondStep: 5,
892
+ roundDisplay: false,
893
+ iconUp: 'glyphicon glyphicon-chevron-up',
894
+ iconDown: 'glyphicon glyphicon-chevron-down',
895
+ arrowBehavior: 'pager'
896
+ };
897
+ this.$get = [ '$window', '$document', '$rootScope', '$sce', '$dateFormatter', '$tooltip', '$timeout', function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {
898
+ var isNative = /(ip[ao]d|iphone|android)/gi.test($window.navigator.userAgent);
899
+ var isTouch = 'createTouch' in $window.document && isNative;
900
+ if (!defaults.lang) {
901
+ defaults.lang = $dateFormatter.getDefaultLocale();
902
+ }
903
+ function timepickerFactory(element, controller, config) {
904
+ var $timepicker = $tooltip(element, angular.extend({}, defaults, config));
905
+ var parentScope = config.scope;
906
+ var options = $timepicker.$options;
907
+ var scope = $timepicker.$scope;
908
+ var lang = options.lang;
909
+ var formatDate = function(date, format, timezone) {
910
+ return $dateFormatter.formatDate(date, format, lang, timezone);
911
+ };
912
+ function floorMinutes(time) {
913
+ var coeff = 1e3 * 60 * options.minuteStep;
914
+ return new Date(Math.floor(time.getTime() / coeff) * coeff);
915
+ }
916
+ var selectedIndex = 0;
917
+ var defaultDate = options.roundDisplay ? floorMinutes(new Date()) : new Date();
918
+ var startDate = controller.$dateValue || defaultDate;
919
+ var viewDate = {
920
+ hour: startDate.getHours(),
921
+ meridian: startDate.getHours() < 12,
922
+ minute: startDate.getMinutes(),
923
+ second: startDate.getSeconds(),
924
+ millisecond: startDate.getMilliseconds()
925
+ };
926
+ var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);
927
+ var hoursFormat = $dateFormatter.hoursFormat(format);
928
+ var timeSeparator = $dateFormatter.timeSeparator(format);
929
+ var minutesFormat = $dateFormatter.minutesFormat(format);
930
+ var secondsFormat = $dateFormatter.secondsFormat(format);
931
+ var showSeconds = $dateFormatter.showSeconds(format);
932
+ var showAM = $dateFormatter.showAM(format);
933
+ scope.$iconUp = options.iconUp;
934
+ scope.$iconDown = options.iconDown;
935
+ scope.$select = function(date, index) {
936
+ $timepicker.select(date, index);
937
+ };
938
+ scope.$moveIndex = function(value, index) {
939
+ $timepicker.$moveIndex(value, index);
940
+ };
941
+ scope.$switchMeridian = function(date) {
942
+ $timepicker.switchMeridian(date);
943
+ };
944
+ $timepicker.update = function(date) {
945
+ if (angular.isDate(date) && !isNaN(date.getTime())) {
946
+ $timepicker.$date = date;
947
+ angular.extend(viewDate, {
948
+ hour: date.getHours(),
949
+ minute: date.getMinutes(),
950
+ second: date.getSeconds(),
951
+ millisecond: date.getMilliseconds()
952
+ });
953
+ $timepicker.$build();
954
+ } else if (!$timepicker.$isBuilt) {
955
+ $timepicker.$build();
956
+ }
957
+ };
958
+ $timepicker.select = function(date, index, keep) {
959
+ if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);
960
+ if (!angular.isDate(date)) date = new Date(date);
961
+ if (index === 0) controller.$dateValue.setHours(date.getHours()); else if (index === 1) controller.$dateValue.setMinutes(date.getMinutes()); else if (index === 2) controller.$dateValue.setSeconds(date.getSeconds());
962
+ controller.$setViewValue(angular.copy(controller.$dateValue));
963
+ controller.$render();
964
+ if (options.autoclose && !keep) {
965
+ $timeout(function() {
966
+ $timepicker.hide(true);
967
+ });
968
+ }
969
+ };
970
+ $timepicker.switchMeridian = function(date) {
971
+ if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {
972
+ return;
973
+ }
974
+ var hours = (date || controller.$dateValue).getHours();
975
+ controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);
976
+ controller.$setViewValue(angular.copy(controller.$dateValue));
977
+ controller.$render();
978
+ };
979
+ $timepicker.$build = function() {
980
+ var i;
981
+ var midIndex = scope.midIndex = parseInt(options.length / 2, 10);
982
+ var hours = [];
983
+ var hour;
984
+ for (i = 0; i < options.length; i++) {
985
+ hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);
986
+ hours.push({
987
+ date: hour,
988
+ label: formatDate(hour, hoursFormat),
989
+ selected: $timepicker.$date && $timepicker.$isSelected(hour, 0),
990
+ disabled: $timepicker.$isDisabled(hour, 0)
991
+ });
992
+ }
993
+ var minutes = [];
994
+ var minute;
995
+ for (i = 0; i < options.length; i++) {
996
+ minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);
997
+ minutes.push({
998
+ date: minute,
999
+ label: formatDate(minute, minutesFormat),
1000
+ selected: $timepicker.$date && $timepicker.$isSelected(minute, 1),
1001
+ disabled: $timepicker.$isDisabled(minute, 1)
1002
+ });
1003
+ }
1004
+ var seconds = [];
1005
+ var second;
1006
+ for (i = 0; i < options.length; i++) {
1007
+ second = new Date(1970, 0, 1, 0, 0, viewDate.second - (midIndex - i) * options.secondStep);
1008
+ seconds.push({
1009
+ date: second,
1010
+ label: formatDate(second, secondsFormat),
1011
+ selected: $timepicker.$date && $timepicker.$isSelected(second, 2),
1012
+ disabled: $timepicker.$isDisabled(second, 2)
1013
+ });
1014
+ }
1015
+ var rows = [];
1016
+ for (i = 0; i < options.length; i++) {
1017
+ if (showSeconds) {
1018
+ rows.push([ hours[i], minutes[i], seconds[i] ]);
1019
+ } else {
1020
+ rows.push([ hours[i], minutes[i] ]);
1021
+ }
1022
+ }
1023
+ scope.rows = rows;
1024
+ scope.showSeconds = showSeconds;
1025
+ scope.showAM = showAM;
1026
+ scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;
1027
+ scope.timeSeparator = timeSeparator;
1028
+ $timepicker.$isBuilt = true;
1029
+ };
1030
+ $timepicker.$isSelected = function(date, index) {
1031
+ if (!$timepicker.$date) return false; else if (index === 0) {
1032
+ return date.getHours() === $timepicker.$date.getHours();
1033
+ } else if (index === 1) {
1034
+ return date.getMinutes() === $timepicker.$date.getMinutes();
1035
+ } else if (index === 2) {
1036
+ return date.getSeconds() === $timepicker.$date.getSeconds();
1037
+ }
1038
+ };
1039
+ $timepicker.$isDisabled = function(date, index) {
1040
+ var selectedTime;
1041
+ if (index === 0) {
1042
+ selectedTime = date.getTime() + viewDate.minute * 6e4 + viewDate.second * 1e3;
1043
+ } else if (index === 1) {
1044
+ selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.second * 1e3;
1045
+ } else if (index === 2) {
1046
+ selectedTime = date.getTime() + viewDate.hour * 36e5 + viewDate.minute * 6e4;
1047
+ }
1048
+ return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;
1049
+ };
1050
+ scope.$arrowAction = function(value, index) {
1051
+ if (options.arrowBehavior === 'picker') {
1052
+ $timepicker.$setTimeByStep(value, index);
1053
+ } else {
1054
+ $timepicker.$moveIndex(value, index);
1055
+ }
1056
+ };
1057
+ $timepicker.$setTimeByStep = function(value, index) {
1058
+ var newDate = new Date($timepicker.$date || startDate);
1059
+ var hours = newDate.getHours();
1060
+ var minutes = newDate.getMinutes();
1061
+ var seconds = newDate.getSeconds();
1062
+ if (index === 0) {
1063
+ newDate.setHours(hours - parseInt(options.hourStep, 10) * value);
1064
+ } else if (index === 1) {
1065
+ newDate.setMinutes(minutes - parseInt(options.minuteStep, 10) * value);
1066
+ } else if (index === 2) {
1067
+ newDate.setSeconds(seconds - parseInt(options.secondStep, 10) * value);
1068
+ }
1069
+ $timepicker.select(newDate, index, true);
1070
+ };
1071
+ $timepicker.$moveIndex = function(value, index) {
1072
+ var targetDate;
1073
+ if (index === 0) {
1074
+ targetDate = new Date(1970, 0, 1, viewDate.hour + value * options.length, viewDate.minute, viewDate.second);
1075
+ angular.extend(viewDate, {
1076
+ hour: targetDate.getHours()
1077
+ });
1078
+ } else if (index === 1) {
1079
+ targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + value * options.length * options.minuteStep, viewDate.second);
1080
+ angular.extend(viewDate, {
1081
+ minute: targetDate.getMinutes()
1082
+ });
1083
+ } else if (index === 2) {
1084
+ targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute, viewDate.second + value * options.length * options.secondStep);
1085
+ angular.extend(viewDate, {
1086
+ second: targetDate.getSeconds()
1087
+ });
1088
+ }
1089
+ $timepicker.$build();
1090
+ };
1091
+ $timepicker.$onMouseDown = function(evt) {
1092
+ if (evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();
1093
+ evt.stopPropagation();
1094
+ if (isTouch) {
1095
+ var targetEl = angular.element(evt.target);
1096
+ if (targetEl[0].nodeName.toLowerCase() !== 'button') {
1097
+ targetEl = targetEl.parent();
1098
+ }
1099
+ targetEl.triggerHandler('click');
1100
+ }
1101
+ };
1102
+ $timepicker.$onKeyDown = function(evt) {
1103
+ if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
1104
+ evt.preventDefault();
1105
+ evt.stopPropagation();
1106
+ if (evt.keyCode === 13) {
1107
+ $timepicker.hide(true);
1108
+ return;
1109
+ }
1110
+ var newDate = new Date($timepicker.$date);
1111
+ var hours = newDate.getHours();
1112
+ var hoursLength = formatDate(newDate, hoursFormat).length;
1113
+ var minutes = newDate.getMinutes();
1114
+ var minutesLength = formatDate(newDate, minutesFormat).length;
1115
+ var seconds = newDate.getSeconds();
1116
+ var secondsLength = formatDate(newDate, secondsFormat).length;
1117
+ var sepLength = 1;
1118
+ var lateralMove = /(37|39)/.test(evt.keyCode);
1119
+ var count = 2 + showSeconds * 1 + showAM * 1;
1120
+ if (lateralMove) {
1121
+ if (evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1; else if (evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;
1122
+ }
1123
+ var selectRange = [ 0, hoursLength ];
1124
+ var incr = 0;
1125
+ if (evt.keyCode === 38) incr = -1;
1126
+ if (evt.keyCode === 40) incr = +1;
1127
+ var isSeconds = selectedIndex === 2 && showSeconds;
1128
+ var isMeridian = selectedIndex === 2 && !showSeconds || selectedIndex === 3 && showSeconds;
1129
+ if (selectedIndex === 0) {
1130
+ newDate.setHours(hours + incr * parseInt(options.hourStep, 10));
1131
+ hoursLength = formatDate(newDate, hoursFormat).length;
1132
+ selectRange = [ 0, hoursLength ];
1133
+ } else if (selectedIndex === 1) {
1134
+ newDate.setMinutes(minutes + incr * parseInt(options.minuteStep, 10));
1135
+ minutesLength = formatDate(newDate, minutesFormat).length;
1136
+ selectRange = [ hoursLength + sepLength, minutesLength ];
1137
+ } else if (isSeconds) {
1138
+ newDate.setSeconds(seconds + incr * parseInt(options.secondStep, 10));
1139
+ secondsLength = formatDate(newDate, secondsFormat).length;
1140
+ selectRange = [ hoursLength + sepLength + minutesLength + sepLength, secondsLength ];
1141
+ } else if (isMeridian) {
1142
+ if (!lateralMove) $timepicker.switchMeridian();
1143
+ selectRange = [ hoursLength + sepLength + minutesLength + sepLength + (secondsLength + sepLength) * showSeconds, 2 ];
1144
+ }
1145
+ $timepicker.select(newDate, selectedIndex, true);
1146
+ createSelection(selectRange[0], selectRange[1]);
1147
+ parentScope.$digest();
1148
+ };
1149
+ function createSelection(start, length) {
1150
+ var end = start + length;
1151
+ if (element[0].createTextRange) {
1152
+ var selRange = element[0].createTextRange();
1153
+ selRange.collapse(true);
1154
+ selRange.moveStart('character', start);
1155
+ selRange.moveEnd('character', end);
1156
+ selRange.select();
1157
+ } else if (element[0].setSelectionRange) {
1158
+ element[0].setSelectionRange(start, end);
1159
+ } else if (angular.isUndefined(element[0].selectionStart)) {
1160
+ element[0].selectionStart = start;
1161
+ element[0].selectionEnd = end;
1162
+ }
1163
+ }
1164
+ function focusElement() {
1165
+ element[0].focus();
1166
+ }
1167
+ var _init = $timepicker.init;
1168
+ $timepicker.init = function() {
1169
+ if (isNative && options.useNative) {
1170
+ element.prop('type', 'time');
1171
+ element.css('-webkit-appearance', 'textfield');
1172
+ return;
1173
+ } else if (isTouch) {
1174
+ element.prop('type', 'text');
1175
+ element.attr('readonly', 'true');
1176
+ element.on('click', focusElement);
1177
+ }
1178
+ _init();
1179
+ };
1180
+ var _destroy = $timepicker.destroy;
1181
+ $timepicker.destroy = function() {
1182
+ if (isNative && options.useNative) {
1183
+ element.off('click', focusElement);
1184
+ }
1185
+ _destroy();
1186
+ };
1187
+ var _show = $timepicker.show;
1188
+ $timepicker.show = function() {
1189
+ if (!isTouch && element.attr('readonly') || element.attr('disabled')) return;
1190
+ _show();
1191
+ $timeout(function() {
1192
+ if ($timepicker.$element) $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
1193
+ if (options.keyboard) {
1194
+ if (element) element.on('keydown', $timepicker.$onKeyDown);
1195
+ }
1196
+ }, 0, false);
1197
+ };
1198
+ var _hide = $timepicker.hide;
1199
+ $timepicker.hide = function(blur) {
1200
+ if (!$timepicker.$isShown) return;
1201
+ if ($timepicker.$element) $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);
1202
+ if (options.keyboard) {
1203
+ if (element) element.off('keydown', $timepicker.$onKeyDown);
1204
+ }
1205
+ _hide(blur);
1206
+ };
1207
+ return $timepicker;
1208
+ }
1209
+ timepickerFactory.defaults = defaults;
1210
+ return timepickerFactory;
1211
+ } ];
1212
+ }).directive('bsTimepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$timepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {
1213
+ var defaults = $timepicker.defaults;
1214
+ var isNative = /(ip[ao]d|iphone|android)/gi.test($window.navigator.userAgent);
1215
+ return {
1216
+ restrict: 'EAC',
1217
+ require: 'ngModel',
1218
+ link: function postLink(scope, element, attr, controller) {
1219
+ var options = {
1220
+ scope: scope
1221
+ };
1222
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'autoclose', 'timeType', 'timeFormat', 'timezone', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'secondStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'roundDisplay', 'id', 'prefixClass', 'prefixEvent' ], function(key) {
1223
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
1224
+ });
1225
+ var falseValueRegExp = /^(false|0|)$/i;
1226
+ angular.forEach([ 'html', 'container', 'autoclose', 'useNative', 'roundDisplay' ], function(key) {
1227
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) {
1228
+ options[key] = false;
1229
+ }
1230
+ });
1231
+ if (isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';
1232
+ var timepicker = $timepicker(element, controller, options);
1233
+ options = timepicker.$options;
1234
+ var lang = options.lang;
1235
+ var formatDate = function(date, format, timezone) {
1236
+ return $dateFormatter.formatDate(date, format, lang, timezone);
1237
+ };
1238
+ if (attr.bsShow) {
1239
+ scope.$watch(attr.bsShow, function(newValue, oldValue) {
1240
+ if (!timepicker || !angular.isDefined(newValue)) return;
1241
+ if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);
1242
+ if (newValue === true) {
1243
+ timepicker.show();
1244
+ } else {
1245
+ timepicker.hide();
1246
+ }
1247
+ });
1248
+ }
1249
+ var dateParser = $dateParser({
1250
+ format: options.timeFormat,
1251
+ lang: lang
1252
+ });
1253
+ angular.forEach([ 'minTime', 'maxTime' ], function(key) {
1254
+ if (angular.isDefined(attr[key])) {
1255
+ attr.$observe(key, function(newValue) {
1256
+ timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);
1257
+ if (!isNaN(timepicker.$options[key])) timepicker.$build();
1258
+ validateAgainstMinMaxTime(controller.$dateValue);
1259
+ });
1260
+ }
1261
+ });
1262
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
1263
+ timepicker.update(controller.$dateValue);
1264
+ }, true);
1265
+ function validateAgainstMinMaxTime(parsedTime) {
1266
+ if (!angular.isDate(parsedTime)) return;
1267
+ var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;
1268
+ var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;
1269
+ var isValid = isMinValid && isMaxValid;
1270
+ controller.$setValidity('date', isValid);
1271
+ controller.$setValidity('min', isMinValid);
1272
+ controller.$setValidity('max', isMaxValid);
1273
+ if (!isValid) {
1274
+ return;
1275
+ }
1276
+ controller.$dateValue = parsedTime;
1277
+ }
1278
+ controller.$parsers.unshift(function(viewValue) {
1279
+ var date;
1280
+ if (!viewValue) {
1281
+ controller.$setValidity('date', true);
1282
+ return null;
1283
+ }
1284
+ var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);
1285
+ if (!parsedTime || isNaN(parsedTime.getTime())) {
1286
+ controller.$setValidity('date', false);
1287
+ return undefined;
1288
+ }
1289
+ validateAgainstMinMaxTime(parsedTime);
1290
+ if (options.timeType === 'string') {
1291
+ date = dateParser.timezoneOffsetAdjust(parsedTime, options.timezone, true);
1292
+ return formatDate(date, options.modelTimeFormat || options.timeFormat);
1293
+ }
1294
+ date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);
1295
+ if (options.timeType === 'number') {
1296
+ return date.getTime();
1297
+ } else if (options.timeType === 'unix') {
1298
+ return date.getTime() / 1e3;
1299
+ } else if (options.timeType === 'iso') {
1300
+ return date.toISOString();
1301
+ }
1302
+ return new Date(date);
1303
+ });
1304
+ controller.$formatters.push(function(modelValue) {
1305
+ var date;
1306
+ if (angular.isUndefined(modelValue) || modelValue === null) {
1307
+ date = NaN;
1308
+ } else if (angular.isDate(modelValue)) {
1309
+ date = modelValue;
1310
+ } else if (options.timeType === 'string') {
1311
+ date = dateParser.parse(modelValue, null, options.modelTimeFormat);
1312
+ } else if (options.timeType === 'unix') {
1313
+ date = new Date(modelValue * 1e3);
1314
+ } else {
1315
+ date = new Date(modelValue);
1316
+ }
1317
+ controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);
1318
+ return getTimeFormattedString();
1319
+ });
1320
+ controller.$render = function() {
1321
+ element.val(getTimeFormattedString());
1322
+ };
1323
+ function getTimeFormattedString() {
1324
+ return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);
1325
+ }
1326
+ scope.$on('$destroy', function() {
1327
+ if (timepicker) timepicker.destroy();
1328
+ options = null;
1329
+ timepicker = null;
1330
+ });
1331
+ }
1332
+ };
1333
+ } ]);
1334
+ angular.module('mgcrea.ngStrap.tab', []).provider('$tab', function() {
1335
+ var defaults = this.defaults = {
1336
+ animation: 'am-fade',
1337
+ template: 'tab/tab.tpl.html',
1338
+ navClass: 'nav-tabs',
1339
+ activeClass: 'active'
1340
+ };
1341
+ var controller = this.controller = function($scope, $element, $attrs) {
1342
+ var self = this;
1343
+ self.$options = angular.copy(defaults);
1344
+ angular.forEach([ 'animation', 'navClass', 'activeClass' ], function(key) {
1345
+ if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
1346
+ });
1347
+ $scope.$navClass = self.$options.navClass;
1348
+ $scope.$activeClass = self.$options.activeClass;
1349
+ self.$panes = $scope.$panes = [];
1350
+ self.$activePaneChangeListeners = self.$viewChangeListeners = [];
1351
+ self.$push = function(pane) {
1352
+ if (angular.isUndefined(self.$panes.$active)) {
1353
+ $scope.$setActive(pane.name || 0);
1354
+ }
1355
+ self.$panes.push(pane);
1356
+ };
1357
+ self.$remove = function(pane) {
1358
+ var index = self.$panes.indexOf(pane);
1359
+ var active = self.$panes.$active;
1360
+ var activeIndex;
1361
+ if (angular.isString(active)) {
1362
+ activeIndex = self.$panes.map(function(pane) {
1363
+ return pane.name;
1364
+ }).indexOf(active);
1365
+ } else {
1366
+ activeIndex = self.$panes.$active;
1367
+ }
1368
+ self.$panes.splice(index, 1);
1369
+ if (index < activeIndex) {
1370
+ activeIndex--;
1371
+ } else if (index === activeIndex && activeIndex === self.$panes.length) {
1372
+ activeIndex--;
1373
+ }
1374
+ if (activeIndex >= 0 && activeIndex < self.$panes.length) {
1375
+ self.$setActive(self.$panes[activeIndex].name || activeIndex);
1376
+ } else {
1377
+ self.$setActive();
1378
+ }
1379
+ };
1380
+ self.$setActive = $scope.$setActive = function(value) {
1381
+ self.$panes.$active = value;
1382
+ self.$activePaneChangeListeners.forEach(function(fn) {
1383
+ fn();
1384
+ });
1385
+ };
1386
+ self.$isActive = $scope.$isActive = function($pane, $index) {
1387
+ return self.$panes.$active === $pane.name || self.$panes.$active === $index;
1388
+ };
1389
+ };
1390
+ this.$get = function() {
1391
+ var $tab = {};
1392
+ $tab.defaults = defaults;
1393
+ $tab.controller = controller;
1394
+ return $tab;
1395
+ };
1396
+ }).directive('bsTabs', [ '$window', '$animate', '$tab', '$parse', function($window, $animate, $tab, $parse) {
1397
+ var defaults = $tab.defaults;
1398
+ return {
1399
+ require: [ '?ngModel', 'bsTabs' ],
1400
+ transclude: true,
1401
+ scope: true,
1402
+ controller: [ '$scope', '$element', '$attrs', $tab.controller ],
1403
+ templateUrl: function(element, attr) {
1404
+ return attr.template || defaults.template;
1405
+ },
1406
+ link: function postLink(scope, element, attrs, controllers) {
1407
+ var ngModelCtrl = controllers[0];
1408
+ var bsTabsCtrl = controllers[1];
1409
+ if (ngModelCtrl) {
1410
+ bsTabsCtrl.$activePaneChangeListeners.push(function() {
1411
+ ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);
1412
+ });
1413
+ ngModelCtrl.$formatters.push(function(modelValue) {
1414
+ bsTabsCtrl.$setActive(modelValue);
1415
+ return modelValue;
1416
+ });
1417
+ }
1418
+ if (attrs.bsActivePane) {
1419
+ var parsedBsActivePane = $parse(attrs.bsActivePane);
1420
+ bsTabsCtrl.$activePaneChangeListeners.push(function() {
1421
+ parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);
1422
+ });
1423
+ scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {
1424
+ bsTabsCtrl.$setActive(newValue);
1425
+ }, true);
1426
+ }
1427
+ }
1428
+ };
1429
+ } ]).directive('bsPane', [ '$window', '$animate', '$sce', function($window, $animate, $sce) {
1430
+ return {
1431
+ require: [ '^?ngModel', '^bsTabs' ],
1432
+ scope: true,
1433
+ link: function postLink(scope, element, attrs, controllers) {
1434
+ var bsTabsCtrl = controllers[1];
1435
+ element.addClass('tab-pane');
1436
+ attrs.$observe('title', function(newValue, oldValue) {
1437
+ scope.title = $sce.trustAsHtml(newValue);
1438
+ });
1439
+ scope.name = attrs.name;
1440
+ if (bsTabsCtrl.$options.animation) {
1441
+ element.addClass(bsTabsCtrl.$options.animation);
1442
+ }
1443
+ attrs.$observe('disabled', function(newValue, oldValue) {
1444
+ scope.disabled = scope.$eval(newValue);
1445
+ });
1446
+ bsTabsCtrl.$push(scope);
1447
+ scope.$on('$destroy', function() {
1448
+ bsTabsCtrl.$remove(scope);
1449
+ });
1450
+ function render() {
1451
+ var index = bsTabsCtrl.$panes.indexOf(scope);
1452
+ $animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);
1453
+ }
1454
+ bsTabsCtrl.$activePaneChangeListeners.push(function() {
1455
+ render();
1456
+ });
1457
+ render();
1458
+ }
1459
+ };
1460
+ } ]);
1461
+ angular.module('mgcrea.ngStrap.select', [ 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions' ]).provider('$select', function() {
1462
+ var defaults = this.defaults = {
1463
+ animation: 'am-fade',
1464
+ prefixClass: 'select',
1465
+ prefixEvent: '$select',
1466
+ placement: 'bottom-left',
1467
+ templateUrl: 'select/select.tpl.html',
1468
+ trigger: 'focus',
1469
+ container: false,
1470
+ keyboard: true,
1471
+ html: false,
1472
+ delay: 0,
1473
+ multiple: false,
1474
+ allNoneButtons: false,
1475
+ sort: true,
1476
+ caretHtml: '&nbsp;<span class="caret"></span>',
1477
+ placeholder: 'Choose among the following...',
1478
+ allText: 'All',
1479
+ noneText: 'None',
1480
+ maxLength: 3,
1481
+ maxLengthHtml: 'selected',
1482
+ iconCheckmark: 'glyphicon glyphicon-ok'
1483
+ };
1484
+ this.$get = [ '$window', '$document', '$rootScope', '$tooltip', '$timeout', function($window, $document, $rootScope, $tooltip, $timeout) {
1485
+ var isNative = /(ip[ao]d|iphone|android)/gi.test($window.navigator.userAgent);
1486
+ var isTouch = 'createTouch' in $window.document && isNative;
1487
+ function SelectFactory(element, controller, config) {
1488
+ var $select = {};
1489
+ var options = angular.extend({}, defaults, config);
1490
+ $select = $tooltip(element, options);
1491
+ var scope = $select.$scope;
1492
+ scope.$matches = [];
1493
+ if (options.multiple) {
1494
+ scope.$activeIndex = [];
1495
+ } else {
1496
+ scope.$activeIndex = -1;
1497
+ }
1498
+ scope.$isMultiple = options.multiple;
1499
+ scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;
1500
+ scope.$iconCheckmark = options.iconCheckmark;
1501
+ scope.$allText = options.allText;
1502
+ scope.$noneText = options.noneText;
1503
+ scope.$activate = function(index) {
1504
+ scope.$$postDigest(function() {
1505
+ $select.activate(index);
1506
+ });
1507
+ };
1508
+ scope.$select = function(index, evt) {
1509
+ scope.$$postDigest(function() {
1510
+ $select.select(index);
1511
+ });
1512
+ };
1513
+ scope.$isVisible = function() {
1514
+ return $select.$isVisible();
1515
+ };
1516
+ scope.$isActive = function(index) {
1517
+ return $select.$isActive(index);
1518
+ };
1519
+ scope.$selectAll = function() {
1520
+ for (var i = 0; i < scope.$matches.length; i++) {
1521
+ if (!scope.$isActive(i)) {
1522
+ scope.$select(i);
1523
+ }
1524
+ }
1525
+ };
1526
+ scope.$selectNone = function() {
1527
+ for (var i = 0; i < scope.$matches.length; i++) {
1528
+ if (scope.$isActive(i)) {
1529
+ scope.$select(i);
1530
+ }
1531
+ }
1532
+ };
1533
+ $select.update = function(matches) {
1534
+ scope.$matches = matches;
1535
+ $select.$updateActiveIndex();
1536
+ };
1537
+ $select.activate = function(index) {
1538
+ if (options.multiple) {
1539
+ if ($select.$isActive(index)) {
1540
+ scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1);
1541
+ } else {
1542
+ scope.$activeIndex.push(index);
1543
+ }
1544
+ if (options.sort) scope.$activeIndex.sort(function(a, b) {
1545
+ return a - b;
1546
+ });
1547
+ } else {
1548
+ scope.$activeIndex = index;
1549
+ }
1550
+ return scope.$activeIndex;
1551
+ };
1552
+ $select.select = function(index) {
1553
+ var value = scope.$matches[index].value;
1554
+ scope.$apply(function() {
1555
+ $select.activate(index);
1556
+ if (options.multiple) {
1557
+ controller.$setViewValue(scope.$activeIndex.map(function(index) {
1558
+ if (angular.isUndefined(scope.$matches[index])) {
1559
+ return null;
1560
+ }
1561
+ return scope.$matches[index].value;
1562
+ }));
1563
+ } else {
1564
+ controller.$setViewValue(value);
1565
+ $select.hide();
1566
+ }
1567
+ });
1568
+ scope.$emit(options.prefixEvent + '.select', value, index, $select);
1569
+ };
1570
+ $select.$updateActiveIndex = function() {
1571
+ if (options.multiple) {
1572
+ if (angular.isArray(controller.$modelValue)) {
1573
+ scope.$activeIndex = controller.$modelValue.map(function(value) {
1574
+ return $select.$getIndex(value);
1575
+ });
1576
+ } else {
1577
+ scope.$activeIndex = [];
1578
+ }
1579
+ } else {
1580
+ if (angular.isDefined(controller.$modelValue) && scope.$matches.length) {
1581
+ scope.$activeIndex = $select.$getIndex(controller.$modelValue);
1582
+ } else {
1583
+ scope.$activeIndex = -1;
1584
+ }
1585
+ }
1586
+ };
1587
+ $select.$isVisible = function() {
1588
+ if (!options.minLength || !controller) {
1589
+ return scope.$matches.length;
1590
+ }
1591
+ return scope.$matches.length && controller.$viewValue.length >= options.minLength;
1592
+ };
1593
+ $select.$isActive = function(index) {
1594
+ if (options.multiple) {
1595
+ return scope.$activeIndex.indexOf(index) !== -1;
1596
+ }
1597
+ return scope.$activeIndex === index;
1598
+ };
1599
+ $select.$getIndex = function(value) {
1600
+ var index;
1601
+ for (index = scope.$matches.length; index--; ) {
1602
+ if (angular.equals(scope.$matches[index].value, value)) break;
1603
+ }
1604
+ return index;
1605
+ };
1606
+ $select.$onMouseDown = function(evt) {
1607
+ evt.preventDefault();
1608
+ evt.stopPropagation();
1609
+ if (isTouch) {
1610
+ var targetEl = angular.element(evt.target);
1611
+ targetEl.triggerHandler('click');
1612
+ }
1613
+ };
1614
+ $select.$onKeyDown = function(evt) {
1615
+ if (!/(9|13|38|40)/.test(evt.keyCode)) return;
1616
+ if (evt.keyCode !== 9) {
1617
+ evt.preventDefault();
1618
+ evt.stopPropagation();
1619
+ }
1620
+ if (options.multiple && evt.keyCode === 9) {
1621
+ return $select.hide();
1622
+ }
1623
+ if (!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {
1624
+ return $select.select(scope.$activeIndex);
1625
+ }
1626
+ if (!options.multiple) {
1627
+ if (evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; else if (evt.keyCode === 38 && scope.$activeIndex < 0) scope.$activeIndex = scope.$matches.length - 1; else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; else if (angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;
1628
+ scope.$digest();
1629
+ }
1630
+ };
1631
+ $select.$isIE = function() {
1632
+ var ua = $window.navigator.userAgent;
1633
+ return ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge/') > 0;
1634
+ };
1635
+ $select.$selectScrollFix = function(e) {
1636
+ if ($document[0].activeElement.tagName === 'UL') {
1637
+ e.preventDefault();
1638
+ e.stopImmediatePropagation();
1639
+ e.target.focus();
1640
+ }
1641
+ };
1642
+ var _show = $select.show;
1643
+ $select.show = function() {
1644
+ _show();
1645
+ if (options.multiple) {
1646
+ $select.$element.addClass('select-multiple');
1647
+ }
1648
+ $timeout(function() {
1649
+ $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);
1650
+ if (options.keyboard) {
1651
+ element.on('keydown', $select.$onKeyDown);
1652
+ }
1653
+ }, 0, false);
1654
+ };
1655
+ var _hide = $select.hide;
1656
+ $select.hide = function() {
1657
+ if (!options.multiple && angular.isUndefined(controller.$modelValue)) {
1658
+ scope.$activeIndex = -1;
1659
+ }
1660
+ $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);
1661
+ if (options.keyboard) {
1662
+ element.off('keydown', $select.$onKeyDown);
1663
+ }
1664
+ _hide(true);
1665
+ };
1666
+ return $select;
1667
+ }
1668
+ SelectFactory.defaults = defaults;
1669
+ return SelectFactory;
1670
+ } ];
1671
+ }).directive('bsSelect', [ '$window', '$parse', '$q', '$select', '$parseOptions', function($window, $parse, $q, $select, $parseOptions) {
1672
+ var defaults = $select.defaults;
1673
+ return {
1674
+ restrict: 'EAC',
1675
+ require: 'ngModel',
1676
+ link: function postLink(scope, element, attr, controller) {
1677
+ var options = {
1678
+ scope: scope,
1679
+ placeholder: defaults.placeholder
1680
+ };
1681
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'placeholder', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id', 'sort', 'caretHtml', 'prefixClass', 'prefixEvent' ], function(key) {
1682
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
1683
+ });
1684
+ var falseValueRegExp = /^(false|0|)$/i;
1685
+ angular.forEach([ 'html', 'container', 'allNoneButtons', 'sort' ], function(key) {
1686
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) {
1687
+ options[key] = false;
1688
+ }
1689
+ });
1690
+ var dataMultiple = element.attr('data-multiple');
1691
+ if (angular.isDefined(dataMultiple)) {
1692
+ if (falseValueRegExp.test(dataMultiple)) {
1693
+ options.multiple = false;
1694
+ } else {
1695
+ options.multiple = dataMultiple;
1696
+ }
1697
+ }
1698
+ if (element[0].nodeName.toLowerCase() === 'select') {
1699
+ var inputEl = element;
1700
+ inputEl.css('display', 'none');
1701
+ element = angular.element('<button type="button" class="btn btn-default"></button>');
1702
+ inputEl.after(element);
1703
+ }
1704
+ var parsedOptions = $parseOptions(attr.bsOptions);
1705
+ var select = $select(element, controller, options);
1706
+ if (select.$isIE()) {
1707
+ element[0].addEventListener('blur', select.$selectScrollFix);
1708
+ }
1709
+ var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').trim();
1710
+ scope.$watch(watchedOptions, function(newValue, oldValue) {
1711
+ parsedOptions.valuesFn(scope, controller).then(function(values) {
1712
+ select.update(values);
1713
+ controller.$render();
1714
+ });
1715
+ }, true);
1716
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
1717
+ select.$updateActiveIndex();
1718
+ controller.$render();
1719
+ }, true);
1720
+ controller.$render = function() {
1721
+ var selected;
1722
+ var index;
1723
+ if (options.multiple && angular.isArray(controller.$modelValue)) {
1724
+ selected = controller.$modelValue.map(function(value) {
1725
+ index = select.$getIndex(value);
1726
+ return index !== -1 ? select.$scope.$matches[index].label : false;
1727
+ }).filter(angular.isDefined);
1728
+ if (selected.length > (options.maxLength || defaults.maxLength)) {
1729
+ selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);
1730
+ } else {
1731
+ selected = selected.join(', ');
1732
+ }
1733
+ } else {
1734
+ index = select.$getIndex(controller.$modelValue);
1735
+ selected = index !== -1 ? select.$scope.$matches[index].label : false;
1736
+ }
1737
+ element.html((selected || options.placeholder) + (options.caretHtml || defaults.caretHtml));
1738
+ };
1739
+ if (options.multiple) {
1740
+ controller.$isEmpty = function(value) {
1741
+ return !value || value.length === 0;
1742
+ };
1743
+ }
1744
+ scope.$on('$destroy', function() {
1745
+ if (select) select.destroy();
1746
+ options = null;
1747
+ select = null;
1748
+ });
1749
+ }
1750
+ };
1751
+ } ]);
1752
+ angular.module('mgcrea.ngStrap.scrollspy', [ 'mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$scrollspy', function() {
1753
+ var spies = this.$$spies = {};
1754
+ var defaults = this.defaults = {
1755
+ debounce: 150,
1756
+ throttle: 100,
1757
+ offset: 100
1758
+ };
1759
+ this.$get = [ '$window', '$document', '$rootScope', 'dimensions', 'debounce', 'throttle', function($window, $document, $rootScope, dimensions, debounce, throttle) {
1760
+ var windowEl = angular.element($window);
1761
+ var docEl = angular.element($document.prop('documentElement'));
1762
+ var bodyEl = angular.element($window.document.body);
1763
+ function nodeName(element, name) {
1764
+ return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();
1765
+ }
1766
+ function ScrollSpyFactory(config) {
1767
+ var options = angular.extend({}, defaults, config);
1768
+ if (!options.element) options.element = bodyEl;
1769
+ var isWindowSpy = nodeName(options.element, 'body');
1770
+ var scrollEl = isWindowSpy ? windowEl : options.element;
1771
+ var scrollId = isWindowSpy ? 'window' : options.id;
1772
+ if (spies[scrollId]) {
1773
+ spies[scrollId].$$count++;
1774
+ return spies[scrollId];
1775
+ }
1776
+ var $scrollspy = {};
1777
+ var unbindViewContentLoaded;
1778
+ var unbindIncludeContentLoaded;
1779
+ var trackedElements = $scrollspy.$trackedElements = [];
1780
+ var sortedElements = [];
1781
+ var activeTarget;
1782
+ var debouncedCheckPosition;
1783
+ var throttledCheckPosition;
1784
+ var debouncedCheckOffsets;
1785
+ var viewportHeight;
1786
+ var scrollTop;
1787
+ $scrollspy.init = function() {
1788
+ this.$$count = 1;
1789
+ debouncedCheckPosition = debounce(this.checkPosition, options.debounce);
1790
+ throttledCheckPosition = throttle(this.checkPosition, options.throttle);
1791
+ scrollEl.on('click', this.checkPositionWithEventLoop);
1792
+ windowEl.on('resize', debouncedCheckPosition);
1793
+ scrollEl.on('scroll', throttledCheckPosition);
1794
+ debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);
1795
+ unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);
1796
+ unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);
1797
+ debouncedCheckOffsets();
1798
+ if (scrollId) {
1799
+ spies[scrollId] = $scrollspy;
1800
+ }
1801
+ };
1802
+ $scrollspy.destroy = function() {
1803
+ this.$$count--;
1804
+ if (this.$$count > 0) {
1805
+ return;
1806
+ }
1807
+ scrollEl.off('click', this.checkPositionWithEventLoop);
1808
+ windowEl.off('resize', debouncedCheckPosition);
1809
+ scrollEl.off('scroll', throttledCheckPosition);
1810
+ unbindViewContentLoaded();
1811
+ unbindIncludeContentLoaded();
1812
+ if (scrollId) {
1813
+ delete spies[scrollId];
1814
+ }
1815
+ };
1816
+ $scrollspy.checkPosition = function() {
1817
+ if (!sortedElements.length) return;
1818
+ scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;
1819
+ viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));
1820
+ if (scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {
1821
+ return $scrollspy.$activateElement(sortedElements[0]);
1822
+ }
1823
+ for (var i = sortedElements.length; i--; ) {
1824
+ if (angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;
1825
+ if (activeTarget === sortedElements[i].target) continue;
1826
+ if (scrollTop < sortedElements[i].offsetTop) continue;
1827
+ if (sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;
1828
+ return $scrollspy.$activateElement(sortedElements[i]);
1829
+ }
1830
+ };
1831
+ $scrollspy.checkPositionWithEventLoop = function() {
1832
+ setTimeout($scrollspy.checkPosition, 1);
1833
+ };
1834
+ $scrollspy.$activateElement = function(element) {
1835
+ if (activeTarget) {
1836
+ var activeElement = $scrollspy.$getTrackedElement(activeTarget);
1837
+ if (activeElement) {
1838
+ activeElement.source.removeClass('active');
1839
+ if (nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {
1840
+ activeElement.source.parent().parent().removeClass('active');
1841
+ }
1842
+ }
1843
+ }
1844
+ activeTarget = element.target;
1845
+ element.source.addClass('active');
1846
+ if (nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {
1847
+ element.source.parent().parent().addClass('active');
1848
+ }
1849
+ };
1850
+ $scrollspy.$getTrackedElement = function(target) {
1851
+ return trackedElements.filter(function(obj) {
1852
+ return obj.target === target;
1853
+ })[0];
1854
+ };
1855
+ $scrollspy.checkOffsets = function() {
1856
+ angular.forEach(trackedElements, function(trackedElement) {
1857
+ var targetElement = document.querySelector(trackedElement.target);
1858
+ trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;
1859
+ if (options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;
1860
+ });
1861
+ sortedElements = trackedElements.filter(function(el) {
1862
+ return el.offsetTop !== null;
1863
+ }).sort(function(a, b) {
1864
+ return a.offsetTop - b.offsetTop;
1865
+ });
1866
+ debouncedCheckPosition();
1867
+ };
1868
+ $scrollspy.trackElement = function(target, source) {
1869
+ trackedElements.push({
1870
+ target: target,
1871
+ source: source
1872
+ });
1873
+ };
1874
+ $scrollspy.untrackElement = function(target, source) {
1875
+ var toDelete;
1876
+ for (var i = trackedElements.length; i--; ) {
1877
+ if (trackedElements[i].target === target && trackedElements[i].source === source) {
1878
+ toDelete = i;
1879
+ break;
1880
+ }
1881
+ }
1882
+ trackedElements.splice(toDelete, 1);
1883
+ };
1884
+ $scrollspy.activate = function(i) {
1885
+ trackedElements[i].addClass('active');
1886
+ };
1887
+ $scrollspy.init();
1888
+ return $scrollspy;
1889
+ }
1890
+ return ScrollSpyFactory;
1891
+ } ];
1892
+ }).directive('bsScrollspy', [ '$rootScope', 'debounce', 'dimensions', '$scrollspy', function($rootScope, debounce, dimensions, $scrollspy) {
1893
+ return {
1894
+ restrict: 'EAC',
1895
+ link: function postLink(scope, element, attr) {
1896
+ var options = {
1897
+ scope: scope
1898
+ };
1899
+ angular.forEach([ 'offset', 'target' ], function(key) {
1900
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
1901
+ });
1902
+ var scrollspy = $scrollspy(options);
1903
+ scrollspy.trackElement(options.target, element);
1904
+ scope.$on('$destroy', function() {
1905
+ if (scrollspy) {
1906
+ scrollspy.untrackElement(options.target, element);
1907
+ scrollspy.destroy();
1908
+ }
1909
+ options = null;
1910
+ scrollspy = null;
1911
+ });
1912
+ }
1913
+ };
1914
+ } ]).directive('bsScrollspyList', [ '$rootScope', 'debounce', 'dimensions', '$scrollspy', function($rootScope, debounce, dimensions, $scrollspy) {
1915
+ return {
1916
+ restrict: 'A',
1917
+ compile: function postLink(element, attr) {
1918
+ var children = element[0].querySelectorAll('li > a[href]');
1919
+ angular.forEach(children, function(child) {
1920
+ var childEl = angular.element(child);
1921
+ childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));
1922
+ });
1923
+ }
1924
+ };
1925
+ } ]);
1926
+ angular.module('mgcrea.ngStrap.popover', [ 'mgcrea.ngStrap.tooltip' ]).provider('$popover', function() {
1927
+ var defaults = this.defaults = {
1928
+ animation: 'am-fade',
1929
+ customClass: '',
1930
+ container: false,
1931
+ target: false,
1932
+ placement: 'right',
1933
+ templateUrl: 'popover/popover.tpl.html',
1934
+ contentTemplate: false,
1935
+ trigger: 'click',
1936
+ keyboard: true,
1937
+ html: false,
1938
+ title: '',
1939
+ content: '',
1940
+ delay: 0,
1941
+ autoClose: false
1942
+ };
1943
+ this.$get = [ '$tooltip', function($tooltip) {
1944
+ function PopoverFactory(element, config) {
1945
+ var options = angular.extend({}, defaults, config);
1946
+ var $popover = $tooltip(element, options);
1947
+ if (options.content) {
1948
+ $popover.$scope.content = options.content;
1949
+ }
1950
+ return $popover;
1951
+ }
1952
+ return PopoverFactory;
1953
+ } ];
1954
+ }).directive('bsPopover', [ '$window', '$sce', '$popover', function($window, $sce, $popover) {
1955
+ var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
1956
+ return {
1957
+ restrict: 'EAC',
1958
+ scope: true,
1959
+ link: function postLink(scope, element, attr) {
1960
+ var popover;
1961
+ var options = {
1962
+ scope: scope
1963
+ };
1964
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'customClass', 'autoClose', 'id', 'prefixClass', 'prefixEvent' ], function(key) {
1965
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
1966
+ });
1967
+ var falseValueRegExp = /^(false|0|)$/i;
1968
+ angular.forEach([ 'html', 'container', 'autoClose' ], function(key) {
1969
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
1970
+ });
1971
+ var dataTarget = element.attr('data-target');
1972
+ if (angular.isDefined(dataTarget)) {
1973
+ if (falseValueRegExp.test(dataTarget)) {
1974
+ options.target = false;
1975
+ } else {
1976
+ options.target = dataTarget;
1977
+ }
1978
+ }
1979
+ angular.forEach([ 'title', 'content' ], function(key) {
1980
+ if (attr[key]) {
1981
+ attr.$observe(key, function(newValue, oldValue) {
1982
+ scope[key] = $sce.trustAsHtml(newValue);
1983
+ if (angular.isDefined(oldValue)) {
1984
+ requestAnimationFrame(function() {
1985
+ if (popover) popover.$applyPlacement();
1986
+ });
1987
+ }
1988
+ });
1989
+ }
1990
+ });
1991
+ if (attr.bsPopover) {
1992
+ scope.$watch(attr.bsPopover, function(newValue, oldValue) {
1993
+ if (angular.isObject(newValue)) {
1994
+ angular.extend(scope, newValue);
1995
+ } else {
1996
+ scope.content = newValue;
1997
+ }
1998
+ if (angular.isDefined(oldValue)) {
1999
+ requestAnimationFrame(function() {
2000
+ if (popover) popover.$applyPlacement();
2001
+ });
2002
+ }
2003
+ }, true);
2004
+ }
2005
+ if (attr.bsShow) {
2006
+ scope.$watch(attr.bsShow, function(newValue, oldValue) {
2007
+ if (!popover || !angular.isDefined(newValue)) return;
2008
+ if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);
2009
+ if (newValue === true) {
2010
+ popover.show();
2011
+ } else {
2012
+ popover.hide();
2013
+ }
2014
+ });
2015
+ }
2016
+ if (attr.viewport) {
2017
+ scope.$watch(attr.viewport, function(newValue) {
2018
+ if (!popover || !angular.isDefined(newValue)) return;
2019
+ popover.setViewport(newValue);
2020
+ });
2021
+ }
2022
+ popover = $popover(element, options);
2023
+ scope.$on('$destroy', function() {
2024
+ if (popover) popover.destroy();
2025
+ options = null;
2026
+ popover = null;
2027
+ });
2028
+ }
2029
+ };
2030
+ } ]);
2031
+ angular.module('mgcrea.ngStrap.navbar', []).provider('$navbar', function() {
2032
+ var defaults = this.defaults = {
2033
+ activeClass: 'active',
2034
+ routeAttr: 'data-match-route',
2035
+ strict: false
2036
+ };
2037
+ this.$get = function() {
2038
+ return {
2039
+ defaults: defaults
2040
+ };
2041
+ };
2042
+ }).directive('bsNavbar', [ '$window', '$location', '$navbar', function($window, $location, $navbar) {
2043
+ var defaults = $navbar.defaults;
2044
+ return {
2045
+ restrict: 'A',
2046
+ link: function postLink(scope, element, attr, controller) {
2047
+ var options = angular.copy(defaults);
2048
+ angular.forEach(Object.keys(defaults), function(key) {
2049
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
2050
+ });
2051
+ scope.$watch(function() {
2052
+ return $location.path();
2053
+ }, function(newValue, oldValue) {
2054
+ var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');
2055
+ angular.forEach(liElements, function(li) {
2056
+ var liElement = angular.element(li);
2057
+ var pattern = liElement.attr(options.routeAttr).replace('/', '\\/');
2058
+ if (options.strict) {
2059
+ pattern = '^' + pattern + '$';
2060
+ }
2061
+ var regexp = new RegExp(pattern, 'i');
2062
+ if (regexp.test(newValue)) {
2063
+ liElement.addClass(options.activeClass);
2064
+ } else {
2065
+ liElement.removeClass(options.activeClass);
2066
+ }
2067
+ });
2068
+ });
2069
+ }
2070
+ };
2071
+ } ]);
2072
+ angular.module('mgcrea.ngStrap.dropdown', [ 'mgcrea.ngStrap.tooltip' ]).provider('$dropdown', function() {
2073
+ var defaults = this.defaults = {
2074
+ animation: 'am-fade',
2075
+ prefixClass: 'dropdown',
2076
+ prefixEvent: 'dropdown',
2077
+ placement: 'bottom-left',
2078
+ templateUrl: 'dropdown/dropdown.tpl.html',
2079
+ trigger: 'click',
2080
+ container: false,
2081
+ keyboard: true,
2082
+ html: false,
2083
+ delay: 0
2084
+ };
2085
+ this.$get = [ '$window', '$rootScope', '$tooltip', '$timeout', function($window, $rootScope, $tooltip, $timeout) {
2086
+ var bodyEl = angular.element($window.document.body);
2087
+ var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;
2088
+ function DropdownFactory(element, config) {
2089
+ var $dropdown = {};
2090
+ var options = angular.extend({}, defaults, config);
2091
+ $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();
2092
+ $dropdown = $tooltip(element, options);
2093
+ var parentEl = element.parent();
2094
+ $dropdown.$onKeyDown = function(evt) {
2095
+ if (!/(38|40)/.test(evt.keyCode)) return;
2096
+ evt.preventDefault();
2097
+ evt.stopPropagation();
2098
+ var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));
2099
+ if (!items.length) return;
2100
+ var index;
2101
+ angular.forEach(items, function(el, i) {
2102
+ if (matchesSelector && matchesSelector.call(el, ':focus')) index = i;
2103
+ });
2104
+ if (evt.keyCode === 38 && index > 0) index--; else if (evt.keyCode === 40 && index < items.length - 1) index++; else if (angular.isUndefined(index)) index = 0;
2105
+ items.eq(index)[0].focus();
2106
+ };
2107
+ var show = $dropdown.show;
2108
+ $dropdown.show = function() {
2109
+ show();
2110
+ $timeout(function() {
2111
+ if (options.keyboard && $dropdown.$element) $dropdown.$element.on('keydown', $dropdown.$onKeyDown);
2112
+ bodyEl.on('click', onBodyClick);
2113
+ }, 0, false);
2114
+ if (parentEl.hasClass('dropdown')) parentEl.addClass('open');
2115
+ };
2116
+ var hide = $dropdown.hide;
2117
+ $dropdown.hide = function() {
2118
+ if (!$dropdown.$isShown) return;
2119
+ if (options.keyboard && $dropdown.$element) $dropdown.$element.off('keydown', $dropdown.$onKeyDown);
2120
+ bodyEl.off('click', onBodyClick);
2121
+ if (parentEl.hasClass('dropdown')) parentEl.removeClass('open');
2122
+ hide();
2123
+ };
2124
+ var destroy = $dropdown.destroy;
2125
+ $dropdown.destroy = function() {
2126
+ bodyEl.off('click', onBodyClick);
2127
+ destroy();
2128
+ };
2129
+ function onBodyClick(evt) {
2130
+ if (evt.target === element[0]) return;
2131
+ return evt.target !== element[0] && $dropdown.hide();
2132
+ }
2133
+ return $dropdown;
2134
+ }
2135
+ return DropdownFactory;
2136
+ } ];
2137
+ }).directive('bsDropdown', [ '$window', '$sce', '$dropdown', function($window, $sce, $dropdown) {
2138
+ return {
2139
+ restrict: 'EAC',
2140
+ scope: true,
2141
+ compile: function(tElement, tAttrs) {
2142
+ if (!tAttrs.bsDropdown) {
2143
+ var nextSibling = tElement[0].nextSibling;
2144
+ while (nextSibling && nextSibling.nodeType !== 1) {
2145
+ nextSibling = nextSibling.nextSibling;
2146
+ }
2147
+ if (nextSibling && nextSibling.className.split(' ').indexOf('dropdown-menu') >= 0) {
2148
+ tAttrs.template = nextSibling.outerHTML;
2149
+ tAttrs.templateUrl = undefined;
2150
+ nextSibling.parentNode.removeChild(nextSibling);
2151
+ }
2152
+ }
2153
+ return function postLink(scope, element, attr) {
2154
+ var options = {
2155
+ scope: scope
2156
+ };
2157
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'id', 'autoClose' ], function(key) {
2158
+ if (angular.isDefined(tAttrs[key])) options[key] = tAttrs[key];
2159
+ });
2160
+ var falseValueRegExp = /^(false|0|)$/i;
2161
+ angular.forEach([ 'html', 'container' ], function(key) {
2162
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
2163
+ });
2164
+ if (attr.bsDropdown) {
2165
+ scope.$watch(attr.bsDropdown, function(newValue, oldValue) {
2166
+ scope.content = newValue;
2167
+ }, true);
2168
+ }
2169
+ var dropdown = $dropdown(element, options);
2170
+ if (attr.bsShow) {
2171
+ scope.$watch(attr.bsShow, function(newValue, oldValue) {
2172
+ if (!dropdown || !angular.isDefined(newValue)) return;
2173
+ if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);
2174
+ if (newValue === true) {
2175
+ dropdown.show();
2176
+ } else {
2177
+ dropdown.hide();
2178
+ }
2179
+ });
2180
+ }
2181
+ scope.$on('$destroy', function() {
2182
+ if (dropdown) dropdown.destroy();
2183
+ options = null;
2184
+ dropdown = null;
2185
+ });
2186
+ };
2187
+ }
2188
+ };
2189
+ } ]);
2190
+ angular.module('mgcrea.ngStrap.modal', [ 'mgcrea.ngStrap.core', 'mgcrea.ngStrap.helpers.dimensions' ]).provider('$modal', function() {
2191
+ var defaults = this.defaults = {
2192
+ animation: 'am-fade',
2193
+ backdropAnimation: 'am-fade',
2194
+ customClass: '',
2195
+ prefixClass: 'modal',
2196
+ prefixEvent: 'modal',
2197
+ placement: 'top',
2198
+ templateUrl: 'modal/modal.tpl.html',
2199
+ template: '',
2200
+ contentTemplate: false,
2201
+ container: false,
2202
+ element: null,
2203
+ backdrop: true,
2204
+ keyboard: true,
2205
+ html: false,
2206
+ show: true,
2207
+ size: null
2208
+ };
2209
+ this.$get = [ '$window', '$rootScope', '$bsCompiler', '$animate', '$timeout', '$sce', 'dimensions', function($window, $rootScope, $bsCompiler, $animate, $timeout, $sce, dimensions) {
2210
+ var forEach = angular.forEach;
2211
+ var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
2212
+ var bodyElement = angular.element($window.document.body);
2213
+ var backdropCount = 0;
2214
+ var dialogBaseZindex = 1050;
2215
+ var backdropBaseZindex = 1040;
2216
+ var validSizes = {
2217
+ lg: 'modal-lg',
2218
+ sm: 'modal-sm'
2219
+ };
2220
+ function ModalFactory(config) {
2221
+ var $modal = {};
2222
+ var options = $modal.$options = angular.extend({}, defaults, config);
2223
+ var promise = $modal.$promise = $bsCompiler.compile(options);
2224
+ var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();
2225
+ if (!options.element && !options.container) {
2226
+ options.container = 'body';
2227
+ }
2228
+ $modal.$id = options.id || options.element && options.element.attr('id') || '';
2229
+ forEach([ 'title', 'content' ], function(key) {
2230
+ if (options[key]) scope[key] = $sce.trustAsHtml(options[key]);
2231
+ });
2232
+ scope.$hide = function() {
2233
+ scope.$$postDigest(function() {
2234
+ $modal.hide();
2235
+ });
2236
+ };
2237
+ scope.$show = function() {
2238
+ scope.$$postDigest(function() {
2239
+ $modal.show();
2240
+ });
2241
+ };
2242
+ scope.$toggle = function() {
2243
+ scope.$$postDigest(function() {
2244
+ $modal.toggle();
2245
+ });
2246
+ };
2247
+ $modal.$isShown = scope.$isShown = false;
2248
+ var compileData;
2249
+ var modalElement;
2250
+ var modalScope;
2251
+ var backdropElement = angular.element('<div class="' + options.prefixClass + '-backdrop"/>');
2252
+ backdropElement.css({
2253
+ position: 'fixed',
2254
+ top: '0px',
2255
+ left: '0px',
2256
+ bottom: '0px',
2257
+ right: '0px'
2258
+ });
2259
+ promise.then(function(data) {
2260
+ compileData = data;
2261
+ $modal.init();
2262
+ });
2263
+ $modal.init = function() {
2264
+ if (options.show) {
2265
+ scope.$$postDigest(function() {
2266
+ $modal.show();
2267
+ });
2268
+ }
2269
+ };
2270
+ $modal.destroy = function() {
2271
+ destroyModalElement();
2272
+ if (backdropElement) {
2273
+ backdropElement.remove();
2274
+ backdropElement = null;
2275
+ }
2276
+ scope.$destroy();
2277
+ };
2278
+ $modal.show = function() {
2279
+ if ($modal.$isShown) return;
2280
+ var parent;
2281
+ var after;
2282
+ if (angular.isElement(options.container)) {
2283
+ parent = options.container;
2284
+ after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;
2285
+ } else {
2286
+ if (options.container) {
2287
+ parent = findElement(options.container);
2288
+ after = parent[0] && parent[0].lastChild ? angular.element(parent[0].lastChild) : null;
2289
+ } else {
2290
+ parent = null;
2291
+ after = options.element;
2292
+ }
2293
+ }
2294
+ if (modalElement) destroyModalElement();
2295
+ modalScope = $modal.$scope.$new();
2296
+ modalElement = $modal.$element = compileData.link(modalScope, function(clonedElement, scope) {});
2297
+ $modal.$backdrop = backdropElement;
2298
+ if (options.backdrop) {
2299
+ modalElement.css({
2300
+ 'z-index': dialogBaseZindex + backdropCount * 20
2301
+ });
2302
+ backdropElement.css({
2303
+ 'z-index': backdropBaseZindex + backdropCount * 20
2304
+ });
2305
+ backdropCount++;
2306
+ }
2307
+ if (scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {
2308
+ return;
2309
+ }
2310
+ modalElement.css({
2311
+ display: 'block'
2312
+ }).addClass(options.placement);
2313
+ if (options.customClass) {
2314
+ modalElement.addClass(options.customClass);
2315
+ }
2316
+ if (options.size && validSizes[options.size]) {
2317
+ angular.element(findElement('.modal-dialog', modalElement[0])).addClass(validSizes[options.size]);
2318
+ }
2319
+ if (options.animation) {
2320
+ if (options.backdrop) {
2321
+ backdropElement.addClass(options.backdropAnimation);
2322
+ }
2323
+ modalElement.addClass(options.animation);
2324
+ }
2325
+ if (options.backdrop) {
2326
+ $animate.enter(backdropElement, bodyElement, null);
2327
+ }
2328
+ if (angular.version.minor <= 2) {
2329
+ $animate.enter(modalElement, parent, after, enterAnimateCallback);
2330
+ } else {
2331
+ $animate.enter(modalElement, parent, after).then(enterAnimateCallback);
2332
+ }
2333
+ $modal.$isShown = scope.$isShown = true;
2334
+ safeDigest(scope);
2335
+ var el = modalElement[0];
2336
+ requestAnimationFrame(function() {
2337
+ el.focus();
2338
+ });
2339
+ bodyElement.addClass(options.prefixClass + '-open');
2340
+ if (options.animation) {
2341
+ bodyElement.addClass(options.prefixClass + '-with-' + options.animation);
2342
+ }
2343
+ bindBackdropEvents();
2344
+ bindKeyboardEvents();
2345
+ };
2346
+ function enterAnimateCallback() {
2347
+ scope.$emit(options.prefixEvent + '.show', $modal);
2348
+ }
2349
+ $modal.hide = function() {
2350
+ if (!$modal.$isShown) return;
2351
+ if (options.backdrop) {
2352
+ backdropCount--;
2353
+ }
2354
+ if (scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {
2355
+ return;
2356
+ }
2357
+ if (angular.version.minor <= 2) {
2358
+ $animate.leave(modalElement, leaveAnimateCallback);
2359
+ } else {
2360
+ $animate.leave(modalElement).then(leaveAnimateCallback);
2361
+ }
2362
+ if (options.backdrop) {
2363
+ $animate.leave(backdropElement);
2364
+ }
2365
+ $modal.$isShown = scope.$isShown = false;
2366
+ safeDigest(scope);
2367
+ unbindBackdropEvents();
2368
+ unbindKeyboardEvents();
2369
+ };
2370
+ function leaveAnimateCallback() {
2371
+ bodyElement.removeClass(options.prefixClass + '-open');
2372
+ if (options.animation) {
2373
+ bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);
2374
+ }
2375
+ scope.$emit(options.prefixEvent + '.hide', $modal);
2376
+ }
2377
+ $modal.toggle = function() {
2378
+ if ($modal.$isShown) {
2379
+ $modal.hide();
2380
+ } else {
2381
+ $modal.show();
2382
+ }
2383
+ };
2384
+ $modal.focus = function() {
2385
+ modalElement[0].focus();
2386
+ };
2387
+ $modal.$onKeyUp = function(evt) {
2388
+ if (evt.which === 27 && $modal.$isShown) {
2389
+ $modal.hide();
2390
+ evt.stopPropagation();
2391
+ }
2392
+ };
2393
+ function bindBackdropEvents() {
2394
+ if (options.backdrop) {
2395
+ modalElement.on('click', hideOnBackdropClick);
2396
+ backdropElement.on('click', hideOnBackdropClick);
2397
+ backdropElement.on('wheel', preventEventDefault);
2398
+ }
2399
+ }
2400
+ function unbindBackdropEvents() {
2401
+ if (options.backdrop) {
2402
+ modalElement.off('click', hideOnBackdropClick);
2403
+ backdropElement.off('click', hideOnBackdropClick);
2404
+ backdropElement.off('wheel', preventEventDefault);
2405
+ }
2406
+ }
2407
+ function bindKeyboardEvents() {
2408
+ if (options.keyboard) {
2409
+ modalElement.on('keyup', $modal.$onKeyUp);
2410
+ }
2411
+ }
2412
+ function unbindKeyboardEvents() {
2413
+ if (options.keyboard) {
2414
+ modalElement.off('keyup', $modal.$onKeyUp);
2415
+ }
2416
+ }
2417
+ function hideOnBackdropClick(evt) {
2418
+ if (evt.target !== evt.currentTarget) return;
2419
+ if (options.backdrop === 'static') {
2420
+ $modal.focus();
2421
+ } else {
2422
+ $modal.hide();
2423
+ }
2424
+ }
2425
+ function preventEventDefault(evt) {
2426
+ evt.preventDefault();
2427
+ }
2428
+ function destroyModalElement() {
2429
+ if ($modal.$isShown && modalElement !== null) {
2430
+ unbindBackdropEvents();
2431
+ unbindKeyboardEvents();
2432
+ }
2433
+ if (modalScope) {
2434
+ modalScope.$destroy();
2435
+ modalScope = null;
2436
+ }
2437
+ if (modalElement) {
2438
+ modalElement.remove();
2439
+ modalElement = $modal.$element = null;
2440
+ }
2441
+ }
2442
+ return $modal;
2443
+ }
2444
+ function safeDigest(scope) {
2445
+ scope.$$phase || scope.$root && scope.$root.$$phase || scope.$digest();
2446
+ }
2447
+ function findElement(query, element) {
2448
+ return angular.element((element || document).querySelectorAll(query));
2449
+ }
2450
+ return ModalFactory;
2451
+ } ];
2452
+ }).directive('bsModal', [ '$window', '$sce', '$modal', function($window, $sce, $modal) {
2453
+ return {
2454
+ restrict: 'EAC',
2455
+ scope: true,
2456
+ link: function postLink(scope, element, attr, transclusion) {
2457
+ var options = {
2458
+ scope: scope,
2459
+ element: element,
2460
+ show: false
2461
+ };
2462
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'backdropAnimation', 'id', 'prefixEvent', 'prefixClass', 'customClass', 'modalClass', 'size' ], function(key) {
2463
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
2464
+ });
2465
+ if (options.modalClass) {
2466
+ options.customClass = options.modalClass;
2467
+ }
2468
+ var falseValueRegExp = /^(false|0|)$/i;
2469
+ angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) {
2470
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
2471
+ });
2472
+ angular.forEach([ 'title', 'content' ], function(key) {
2473
+ if (attr[key]) {
2474
+ attr.$observe(key, function(newValue, oldValue) {
2475
+ scope[key] = $sce.trustAsHtml(newValue);
2476
+ });
2477
+ }
2478
+ });
2479
+ if (attr.bsModal) {
2480
+ scope.$watch(attr.bsModal, function(newValue, oldValue) {
2481
+ if (angular.isObject(newValue)) {
2482
+ angular.extend(scope, newValue);
2483
+ } else {
2484
+ scope.content = newValue;
2485
+ }
2486
+ }, true);
2487
+ }
2488
+ var modal = $modal(options);
2489
+ element.on(attr.trigger || 'click', modal.toggle);
2490
+ scope.$on('$destroy', function() {
2491
+ if (modal) modal.destroy();
2492
+ options = null;
2493
+ modal = null;
2494
+ });
2495
+ }
2496
+ };
2497
+ } ]);
2498
+ if (angular.version.minor < 3 && angular.version.dot < 14) {
2499
+ angular.module('ng').factory('$$rAF', [ '$window', '$timeout', function($window, $timeout) {
2500
+ var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame;
2501
+ var cancelAnimationFrame = $window.cancelAnimationFrame || $window.webkitCancelAnimationFrame || $window.mozCancelAnimationFrame || $window.webkitCancelRequestAnimationFrame;
2502
+ var rafSupported = !!requestAnimationFrame;
2503
+ var raf = rafSupported ? function(fn) {
2504
+ var id = requestAnimationFrame(fn);
2505
+ return function() {
2506
+ cancelAnimationFrame(id);
2507
+ };
2508
+ } : function(fn) {
2509
+ var timer = $timeout(fn, 16.66, false);
2510
+ return function() {
2511
+ $timeout.cancel(timer);
2512
+ };
2513
+ };
2514
+ raf.supported = rafSupported;
2515
+ return raf;
2516
+ } ]);
2517
+ }
2518
+ angular.module('mgcrea.ngStrap.helpers.parseOptions', []).provider('$parseOptions', function() {
2519
+ var defaults = this.defaults = {
2520
+ regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/
2521
+ };
2522
+ this.$get = [ '$parse', '$q', function($parse, $q) {
2523
+ function ParseOptionsFactory(attr, config) {
2524
+ var $parseOptions = {};
2525
+ var options = angular.extend({}, defaults, config);
2526
+ $parseOptions.$values = [];
2527
+ var match;
2528
+ var displayFn;
2529
+ var valueName;
2530
+ var keyName;
2531
+ var groupByFn;
2532
+ var valueFn;
2533
+ var valuesFn;
2534
+ $parseOptions.init = function() {
2535
+ $parseOptions.$match = match = attr.match(options.regexp);
2536
+ displayFn = $parse(match[2] || match[1]);
2537
+ valueName = match[4] || match[6];
2538
+ keyName = match[5];
2539
+ groupByFn = $parse(match[3] || '');
2540
+ valueFn = $parse(match[2] ? match[1] : valueName);
2541
+ valuesFn = $parse(match[7]);
2542
+ };
2543
+ $parseOptions.valuesFn = function(scope, controller) {
2544
+ return $q.when(valuesFn(scope, controller)).then(function(values) {
2545
+ if (!angular.isArray(values)) {
2546
+ values = [];
2547
+ }
2548
+ $parseOptions.$values = values.length ? parseValues(values, scope) : [];
2549
+ return $parseOptions.$values;
2550
+ });
2551
+ };
2552
+ $parseOptions.displayValue = function(modelValue) {
2553
+ var scope = {};
2554
+ scope[valueName] = modelValue;
2555
+ return displayFn(scope);
2556
+ };
2557
+ function parseValues(values, scope) {
2558
+ return values.map(function(match, index) {
2559
+ var locals = {};
2560
+ var label;
2561
+ var value;
2562
+ locals[valueName] = match;
2563
+ label = displayFn(scope, locals);
2564
+ value = valueFn(scope, locals);
2565
+ return {
2566
+ label: label,
2567
+ value: value,
2568
+ index: index
2569
+ };
2570
+ });
2571
+ }
2572
+ $parseOptions.init();
2573
+ return $parseOptions;
2574
+ }
2575
+ return ParseOptionsFactory;
2576
+ } ];
2577
+ });
2578
+ angular.module('mgcrea.ngStrap.helpers.dimensions', []).factory('dimensions', function() {
2579
+ var fn = {};
2580
+ var nodeName = fn.nodeName = function(element, name) {
2581
+ return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();
2582
+ };
2583
+ fn.css = function(element, prop, extra) {
2584
+ var value;
2585
+ if (element.currentStyle) {
2586
+ value = element.currentStyle[prop];
2587
+ } else if (window.getComputedStyle) {
2588
+ value = window.getComputedStyle(element)[prop];
2589
+ } else {
2590
+ value = element.style[prop];
2591
+ }
2592
+ return extra === true ? parseFloat(value) || 0 : value;
2593
+ };
2594
+ fn.offset = function(element) {
2595
+ var boxRect = element.getBoundingClientRect();
2596
+ var docElement = element.ownerDocument;
2597
+ return {
2598
+ width: boxRect.width || element.offsetWidth,
2599
+ height: boxRect.height || element.offsetHeight,
2600
+ top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),
2601
+ left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)
2602
+ };
2603
+ };
2604
+ fn.setOffset = function(element, options, i) {
2605
+ var curPosition;
2606
+ var curLeft;
2607
+ var curCSSTop;
2608
+ var curTop;
2609
+ var curOffset;
2610
+ var curCSSLeft;
2611
+ var calculatePosition;
2612
+ var position = fn.css(element, 'position');
2613
+ var curElem = angular.element(element);
2614
+ var props = {};
2615
+ if (position === 'static') {
2616
+ element.style.position = 'relative';
2617
+ }
2618
+ curOffset = fn.offset(element);
2619
+ curCSSTop = fn.css(element, 'top');
2620
+ curCSSLeft = fn.css(element, 'left');
2621
+ calculatePosition = (position === 'absolute' || position === 'fixed') && (curCSSTop + curCSSLeft).indexOf('auto') > -1;
2622
+ if (calculatePosition) {
2623
+ curPosition = fn.position(element);
2624
+ curTop = curPosition.top;
2625
+ curLeft = curPosition.left;
2626
+ } else {
2627
+ curTop = parseFloat(curCSSTop) || 0;
2628
+ curLeft = parseFloat(curCSSLeft) || 0;
2629
+ }
2630
+ if (angular.isFunction(options)) {
2631
+ options = options.call(element, i, curOffset);
2632
+ }
2633
+ if (options.top !== null) {
2634
+ props.top = options.top - curOffset.top + curTop;
2635
+ }
2636
+ if (options.left !== null) {
2637
+ props.left = options.left - curOffset.left + curLeft;
2638
+ }
2639
+ if ('using' in options) {
2640
+ options.using.call(curElem, props);
2641
+ } else {
2642
+ curElem.css({
2643
+ top: props.top + 'px',
2644
+ left: props.left + 'px'
2645
+ });
2646
+ }
2647
+ };
2648
+ fn.position = function(element) {
2649
+ var offsetParentRect = {
2650
+ top: 0,
2651
+ left: 0
2652
+ };
2653
+ var offsetParentEl;
2654
+ var offset;
2655
+ if (fn.css(element, 'position') === 'fixed') {
2656
+ offset = element.getBoundingClientRect();
2657
+ } else {
2658
+ offsetParentEl = offsetParentElement(element);
2659
+ offset = fn.offset(element);
2660
+ if (!nodeName(offsetParentEl, 'html')) {
2661
+ offsetParentRect = fn.offset(offsetParentEl);
2662
+ }
2663
+ offsetParentRect.top += fn.css(offsetParentEl, 'borderTopWidth', true);
2664
+ offsetParentRect.left += fn.css(offsetParentEl, 'borderLeftWidth', true);
2665
+ }
2666
+ return {
2667
+ width: element.offsetWidth,
2668
+ height: element.offsetHeight,
2669
+ top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),
2670
+ left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)
2671
+ };
2672
+ };
2673
+ function offsetParentElement(element) {
2674
+ var docElement = element.ownerDocument;
2675
+ var offsetParent = element.offsetParent || docElement;
2676
+ if (nodeName(offsetParent, '#document')) return docElement.documentElement;
2677
+ while (offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {
2678
+ offsetParent = offsetParent.offsetParent;
2679
+ }
2680
+ return offsetParent || docElement.documentElement;
2681
+ }
2682
+ fn.height = function(element, outer) {
2683
+ var value = element.offsetHeight;
2684
+ if (outer) {
2685
+ value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);
2686
+ } else {
2687
+ value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);
2688
+ }
2689
+ return value;
2690
+ };
2691
+ fn.width = function(element, outer) {
2692
+ var value = element.offsetWidth;
2693
+ if (outer) {
2694
+ value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);
2695
+ } else {
2696
+ value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);
2697
+ }
2698
+ return value;
2699
+ };
2700
+ return fn;
2701
+ });
2702
+ angular.module('mgcrea.ngStrap.helpers.debounce', []).factory('debounce', [ '$timeout', function($timeout) {
2703
+ return function(func, wait, immediate) {
2704
+ var timeout = null;
2705
+ return function() {
2706
+ var context = this;
2707
+ var args = arguments;
2708
+ var callNow = immediate && !timeout;
2709
+ if (timeout) {
2710
+ $timeout.cancel(timeout);
2711
+ }
2712
+ timeout = $timeout(function later() {
2713
+ timeout = null;
2714
+ if (!immediate) {
2715
+ func.apply(context, args);
2716
+ }
2717
+ }, wait, false);
2718
+ if (callNow) {
2719
+ func.apply(context, args);
2720
+ }
2721
+ return timeout;
2722
+ };
2723
+ };
2724
+ } ]).factory('throttle', [ '$timeout', function($timeout) {
2725
+ return function(func, wait, options) {
2726
+ var timeout = null;
2727
+ if (!options) options = {};
2728
+ return function() {
2729
+ var context = this;
2730
+ var args = arguments;
2731
+ if (!timeout) {
2732
+ if (options.leading !== false) {
2733
+ func.apply(context, args);
2734
+ }
2735
+ timeout = $timeout(function later() {
2736
+ timeout = null;
2737
+ if (options.trailing !== false) {
2738
+ func.apply(context, args);
2739
+ }
2740
+ }, wait, false);
2741
+ }
2742
+ };
2743
+ };
2744
+ } ]);
2745
+ angular.module('mgcrea.ngStrap.helpers.dateParser', []).provider('$dateParser', [ '$localeProvider', function($localeProvider) {
2746
+ function ParseDate() {
2747
+ this.year = 1970;
2748
+ this.month = 0;
2749
+ this.day = 1;
2750
+ this.hours = 0;
2751
+ this.minutes = 0;
2752
+ this.seconds = 0;
2753
+ this.milliseconds = 0;
2754
+ }
2755
+ ParseDate.prototype.setMilliseconds = function(value) {
2756
+ this.milliseconds = value;
2757
+ };
2758
+ ParseDate.prototype.setSeconds = function(value) {
2759
+ this.seconds = value;
2760
+ };
2761
+ ParseDate.prototype.setMinutes = function(value) {
2762
+ this.minutes = value;
2763
+ };
2764
+ ParseDate.prototype.setHours = function(value) {
2765
+ this.hours = value;
2766
+ };
2767
+ ParseDate.prototype.getHours = function() {
2768
+ return this.hours;
2769
+ };
2770
+ ParseDate.prototype.setDate = function(value) {
2771
+ this.day = value;
2772
+ };
2773
+ ParseDate.prototype.setMonth = function(value) {
2774
+ this.month = value;
2775
+ };
2776
+ ParseDate.prototype.setFullYear = function(value) {
2777
+ this.year = value;
2778
+ };
2779
+ ParseDate.prototype.fromDate = function(value) {
2780
+ this.year = value.getFullYear();
2781
+ this.month = value.getMonth();
2782
+ this.day = value.getDate();
2783
+ this.hours = value.getHours();
2784
+ this.minutes = value.getMinutes();
2785
+ this.seconds = value.getSeconds();
2786
+ this.milliseconds = value.getMilliseconds();
2787
+ return this;
2788
+ };
2789
+ ParseDate.prototype.toDate = function() {
2790
+ return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);
2791
+ };
2792
+ var proto = ParseDate.prototype;
2793
+ function noop() {}
2794
+ function isNumeric(n) {
2795
+ return !isNaN(parseFloat(n)) && isFinite(n);
2796
+ }
2797
+ function indexOfCaseInsensitive(array, value) {
2798
+ var len = array.length;
2799
+ var str = value.toString().toLowerCase();
2800
+ for (var i = 0; i < len; i++) {
2801
+ if (array[i].toLowerCase() === str) {
2802
+ return i;
2803
+ }
2804
+ }
2805
+ return -1;
2806
+ }
2807
+ var defaults = this.defaults = {
2808
+ format: 'shortDate',
2809
+ strict: false
2810
+ };
2811
+ this.$get = [ '$locale', 'dateFilter', function($locale, dateFilter) {
2812
+ var DateParserFactory = function(config) {
2813
+ var options = angular.extend({}, defaults, config);
2814
+ var $dateParser = {};
2815
+ var regExpMap = {
2816
+ sss: '[0-9]{3}',
2817
+ ss: '[0-5][0-9]',
2818
+ s: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]',
2819
+ mm: '[0-5][0-9]',
2820
+ m: options.strict ? '[1-5]?[0-9]' : '[0-9]|[0-5][0-9]',
2821
+ HH: '[01][0-9]|2[0-3]',
2822
+ H: options.strict ? '1?[0-9]|2[0-3]' : '[01]?[0-9]|2[0-3]',
2823
+ hh: '[0][1-9]|[1][012]',
2824
+ h: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]',
2825
+ a: 'AM|PM',
2826
+ EEEE: $locale.DATETIME_FORMATS.DAY.join('|'),
2827
+ EEE: $locale.DATETIME_FORMATS.SHORTDAY.join('|'),
2828
+ dd: '0[1-9]|[12][0-9]|3[01]',
2829
+ d: options.strict ? '[1-9]|[1-2][0-9]|3[01]' : '0?[1-9]|[1-2][0-9]|3[01]',
2830
+ MMMM: $locale.DATETIME_FORMATS.MONTH.join('|'),
2831
+ MMM: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
2832
+ MM: '0[1-9]|1[012]',
2833
+ M: options.strict ? '[1-9]|1[012]' : '0?[1-9]|1[012]',
2834
+ yyyy: '[1]{1}[0-9]{3}|[2]{1}[0-9]{3}',
2835
+ yy: '[0-9]{2}',
2836
+ y: options.strict ? '-?(0|[1-9][0-9]{0,3})' : '-?0*[0-9]{1,4}'
2837
+ };
2838
+ var setFnMap = {
2839
+ sss: proto.setMilliseconds,
2840
+ ss: proto.setSeconds,
2841
+ s: proto.setSeconds,
2842
+ mm: proto.setMinutes,
2843
+ m: proto.setMinutes,
2844
+ HH: proto.setHours,
2845
+ H: proto.setHours,
2846
+ hh: proto.setHours,
2847
+ h: proto.setHours,
2848
+ EEEE: noop,
2849
+ EEE: noop,
2850
+ dd: proto.setDate,
2851
+ d: proto.setDate,
2852
+ a: function(value) {
2853
+ var hours = this.getHours() % 12;
2854
+ return this.setHours(value.match(/pm/i) ? hours + 12 : hours);
2855
+ },
2856
+ MMMM: function(value) {
2857
+ return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.MONTH, value));
2858
+ },
2859
+ MMM: function(value) {
2860
+ return this.setMonth(indexOfCaseInsensitive($locale.DATETIME_FORMATS.SHORTMONTH, value));
2861
+ },
2862
+ MM: function(value) {
2863
+ return this.setMonth(1 * value - 1);
2864
+ },
2865
+ M: function(value) {
2866
+ return this.setMonth(1 * value - 1);
2867
+ },
2868
+ yyyy: proto.setFullYear,
2869
+ yy: function(value) {
2870
+ return this.setFullYear(2e3 + 1 * value);
2871
+ },
2872
+ y: function(value) {
2873
+ return 1 * value <= 50 && value.length === 2 ? this.setFullYear(2e3 + 1 * value) : this.setFullYear(1 * value);
2874
+ }
2875
+ };
2876
+ var regex;
2877
+ var setMap;
2878
+ $dateParser.init = function() {
2879
+ $dateParser.$format = $locale.DATETIME_FORMATS[options.format] || options.format;
2880
+ regex = regExpForFormat($dateParser.$format);
2881
+ setMap = setMapForFormat($dateParser.$format);
2882
+ };
2883
+ $dateParser.isValid = function(date) {
2884
+ if (angular.isDate(date)) return !isNaN(date.getTime());
2885
+ return regex.test(date);
2886
+ };
2887
+ $dateParser.parse = function(value, baseDate, format, timezone) {
2888
+ if (format) format = $locale.DATETIME_FORMATS[format] || format;
2889
+ if (angular.isDate(value)) value = dateFilter(value, format || $dateParser.$format, timezone);
2890
+ var formatRegex = format ? regExpForFormat(format) : regex;
2891
+ var formatSetMap = format ? setMapForFormat(format) : setMap;
2892
+ var matches = formatRegex.exec(value);
2893
+ if (!matches) return false;
2894
+ var date = baseDate && !isNaN(baseDate.getTime()) ? new ParseDate().fromDate(baseDate) : new ParseDate().fromDate(new Date(1970, 0, 1, 0));
2895
+ for (var i = 0; i < matches.length - 1; i++) {
2896
+ if (formatSetMap[i]) formatSetMap[i].call(date, matches[i + 1]);
2897
+ }
2898
+ var newDate = date.toDate();
2899
+ if (parseInt(date.day, 10) !== newDate.getDate()) {
2900
+ return false;
2901
+ }
2902
+ return newDate;
2903
+ };
2904
+ $dateParser.getDateForAttribute = function(key, value) {
2905
+ var date;
2906
+ if (value === 'today') {
2907
+ var today = new Date();
2908
+ date = new Date(today.getFullYear(), today.getMonth(), today.getDate() + (key === 'maxDate' ? 1 : 0), 0, 0, 0, key === 'minDate' ? 0 : -1);
2909
+ } else if (angular.isString(value) && value.match(/^".+"$/)) {
2910
+ date = new Date(value.substr(1, value.length - 2));
2911
+ } else if (isNumeric(value)) {
2912
+ date = new Date(parseInt(value, 10));
2913
+ } else if (angular.isString(value) && value.length === 0) {
2914
+ date = key === 'minDate' ? -Infinity : +Infinity;
2915
+ } else {
2916
+ date = new Date(value);
2917
+ }
2918
+ return date;
2919
+ };
2920
+ $dateParser.getTimeForAttribute = function(key, value) {
2921
+ var time;
2922
+ if (value === 'now') {
2923
+ time = new Date().setFullYear(1970, 0, 1);
2924
+ } else if (angular.isString(value) && value.match(/^".+"$/)) {
2925
+ time = new Date(value.substr(1, value.length - 2)).setFullYear(1970, 0, 1);
2926
+ } else if (isNumeric(value)) {
2927
+ time = new Date(parseInt(value, 10)).setFullYear(1970, 0, 1);
2928
+ } else if (angular.isString(value) && value.length === 0) {
2929
+ time = key === 'minTime' ? -Infinity : +Infinity;
2930
+ } else {
2931
+ time = $dateParser.parse(value, new Date(1970, 0, 1, 0));
2932
+ }
2933
+ return time;
2934
+ };
2935
+ $dateParser.daylightSavingAdjust = function(date) {
2936
+ if (!date) {
2937
+ return null;
2938
+ }
2939
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
2940
+ return date;
2941
+ };
2942
+ $dateParser.timezoneOffsetAdjust = function(date, timezone, undo) {
2943
+ if (!date) {
2944
+ return null;
2945
+ }
2946
+ if (timezone && timezone === 'UTC') {
2947
+ date = new Date(date.getTime());
2948
+ date.setMinutes(date.getMinutes() + (undo ? -1 : 1) * date.getTimezoneOffset());
2949
+ }
2950
+ return date;
2951
+ };
2952
+ function regExpForFormat(format) {
2953
+ var re = buildDateAbstractRegex(format);
2954
+ return buildDateParseRegex(re);
2955
+ }
2956
+ function buildDateAbstractRegex(format) {
2957
+ var escapedFormat = escapeReservedSymbols(format);
2958
+ var escapedLiteralFormat = escapedFormat.replace(/''/g, '\\\'');
2959
+ var literalRegex = /('(?:\\'|.)*?')/;
2960
+ var formatParts = escapedLiteralFormat.split(literalRegex);
2961
+ var dateElements = Object.keys(regExpMap);
2962
+ var dateRegexParts = [];
2963
+ angular.forEach(formatParts, function(part) {
2964
+ if (isFormatStringLiteral(part)) {
2965
+ part = trimLiteralEscapeChars(part);
2966
+ } else {
2967
+ for (var i = 0; i < dateElements.length; i++) {
2968
+ part = part.split(dateElements[i]).join('${' + i + '}');
2969
+ }
2970
+ }
2971
+ dateRegexParts.push(part);
2972
+ });
2973
+ return dateRegexParts.join('');
2974
+ }
2975
+ function escapeReservedSymbols(text) {
2976
+ return text.replace(/\\/g, '[\\\\]').replace(/-/g, '[-]').replace(/\./g, '[.]').replace(/\*/g, '[*]').replace(/\+/g, '[+]').replace(/\?/g, '[?]').replace(/\$/g, '[$]').replace(/\^/g, '[^]').replace(/\//g, '[/]').replace(/\\s/g, '[\\s]');
2977
+ }
2978
+ function isFormatStringLiteral(text) {
2979
+ return /^'.*'$/.test(text);
2980
+ }
2981
+ function trimLiteralEscapeChars(text) {
2982
+ return text.replace(/^'(.*)'$/, '$1');
2983
+ }
2984
+ function buildDateParseRegex(abstractRegex) {
2985
+ var dateElements = Object.keys(regExpMap);
2986
+ var re = abstractRegex;
2987
+ for (var i = 0; i < dateElements.length; i++) {
2988
+ re = re.split('${' + i + '}').join('(' + regExpMap[dateElements[i]] + ')');
2989
+ }
2990
+ return new RegExp('^' + re + '$', [ 'i' ]);
2991
+ }
2992
+ function setMapForFormat(format) {
2993
+ var re = buildDateAbstractRegex(format);
2994
+ return buildDateParseValuesMap(re);
2995
+ }
2996
+ function buildDateParseValuesMap(abstractRegex) {
2997
+ var dateElements = Object.keys(regExpMap);
2998
+ var valuesRegex = new RegExp('\\${(\\d+)}', 'g');
2999
+ var valuesMatch;
3000
+ var keyIndex;
3001
+ var valueKey;
3002
+ var valueFunction;
3003
+ var valuesFunctionMap = [];
3004
+ while ((valuesMatch = valuesRegex.exec(abstractRegex)) !== null) {
3005
+ keyIndex = valuesMatch[1];
3006
+ valueKey = dateElements[keyIndex];
3007
+ valueFunction = setFnMap[valueKey];
3008
+ valuesFunctionMap.push(valueFunction);
3009
+ }
3010
+ return valuesFunctionMap;
3011
+ }
3012
+ $dateParser.init();
3013
+ return $dateParser;
3014
+ };
3015
+ return DateParserFactory;
3016
+ } ];
3017
+ } ]);
3018
+ angular.module('mgcrea.ngStrap.helpers.dateFormatter', []).service('$dateFormatter', [ '$locale', 'dateFilter', function($locale, dateFilter) {
3019
+ this.getDefaultLocale = function() {
3020
+ return $locale.id;
3021
+ };
3022
+ this.getDatetimeFormat = function(format, lang) {
3023
+ return $locale.DATETIME_FORMATS[format] || format;
3024
+ };
3025
+ this.weekdaysShort = function(lang) {
3026
+ return $locale.DATETIME_FORMATS.SHORTDAY;
3027
+ };
3028
+ function splitTimeFormat(format) {
3029
+ return /(h+)([:\.])?(m+)([:\.])?(s*)[ ]?(a?)/i.exec(format).slice(1);
3030
+ }
3031
+ this.hoursFormat = function(timeFormat) {
3032
+ return splitTimeFormat(timeFormat)[0];
3033
+ };
3034
+ this.minutesFormat = function(timeFormat) {
3035
+ return splitTimeFormat(timeFormat)[2];
3036
+ };
3037
+ this.secondsFormat = function(timeFormat) {
3038
+ return splitTimeFormat(timeFormat)[4];
3039
+ };
3040
+ this.timeSeparator = function(timeFormat) {
3041
+ return splitTimeFormat(timeFormat)[1];
3042
+ };
3043
+ this.showSeconds = function(timeFormat) {
3044
+ return !!splitTimeFormat(timeFormat)[4];
3045
+ };
3046
+ this.showAM = function(timeFormat) {
3047
+ return !!splitTimeFormat(timeFormat)[5];
3048
+ };
3049
+ this.formatDate = function(date, format, lang, timezone) {
3050
+ return dateFilter(date, format, timezone);
3051
+ };
3052
+ } ]);
3053
+ angular.module('mgcrea.ngStrap.core', []).service('$bsCompiler', bsCompilerService);
3054
+ function bsCompilerService($q, $http, $injector, $compile, $controller, $templateCache) {
3055
+ this.compile = function(options) {
3056
+ if (options.template && /\.html$/.test(options.template)) {
3057
+ console.warn('Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead.');
3058
+ options.templateUrl = options.template;
3059
+ options.template = '';
3060
+ }
3061
+ var templateUrl = options.templateUrl;
3062
+ var template = options.template || '';
3063
+ var controller = options.controller;
3064
+ var controllerAs = options.controllerAs;
3065
+ var resolve = angular.copy(options.resolve || {});
3066
+ var locals = angular.copy(options.locals || {});
3067
+ var transformTemplate = options.transformTemplate || angular.identity;
3068
+ var bindToController = options.bindToController;
3069
+ angular.forEach(resolve, function(value, key) {
3070
+ if (angular.isString(value)) {
3071
+ resolve[key] = $injector.get(value);
3072
+ } else {
3073
+ resolve[key] = $injector.invoke(value);
3074
+ }
3075
+ });
3076
+ angular.extend(resolve, locals);
3077
+ if (template) {
3078
+ resolve.$template = $q.when(template);
3079
+ } else if (templateUrl) {
3080
+ resolve.$template = fetchTemplate(templateUrl);
3081
+ } else {
3082
+ throw new Error('Missing `template` / `templateUrl` option.');
3083
+ }
3084
+ if (options.titleTemplate) {
3085
+ resolve.$template = $q.all([ resolve.$template, fetchTemplate(options.titleTemplate) ]).then(function(templates) {
3086
+ var templateEl = angular.element(templates[0]);
3087
+ findElement('[ng-bind="title"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]);
3088
+ return templateEl[0].outerHTML;
3089
+ });
3090
+ }
3091
+ if (options.contentTemplate) {
3092
+ resolve.$template = $q.all([ resolve.$template, fetchTemplate(options.contentTemplate) ]).then(function(templates) {
3093
+ var templateEl = angular.element(templates[0]);
3094
+ var contentEl = findElement('[ng-bind="content"]', templateEl[0]).removeAttr('ng-bind').html(templates[1]);
3095
+ if (!options.templateUrl) contentEl.next().remove();
3096
+ return templateEl[0].outerHTML;
3097
+ });
3098
+ }
3099
+ return $q.all(resolve).then(function(locals) {
3100
+ var template = transformTemplate(locals.$template);
3101
+ if (options.html) {
3102
+ template = template.replace(/ng-bind="/gi, 'ng-bind-html="');
3103
+ }
3104
+ var element = angular.element('<div>').html(template.trim()).contents();
3105
+ var linkFn = $compile(element);
3106
+ return {
3107
+ locals: locals,
3108
+ element: element,
3109
+ link: function link(scope) {
3110
+ locals.$scope = scope;
3111
+ if (controller) {
3112
+ var invokeCtrl = $controller(controller, locals, true);
3113
+ if (bindToController) {
3114
+ angular.extend(invokeCtrl.instance, locals);
3115
+ }
3116
+ var ctrl = angular.isObject(invokeCtrl) ? invokeCtrl : invokeCtrl();
3117
+ element.data('$ngControllerController', ctrl);
3118
+ element.children().data('$ngControllerController', ctrl);
3119
+ if (controllerAs) {
3120
+ scope[controllerAs] = ctrl;
3121
+ }
3122
+ }
3123
+ return linkFn.apply(null, arguments);
3124
+ }
3125
+ };
3126
+ });
3127
+ };
3128
+ function findElement(query, element) {
3129
+ return angular.element((element || document).querySelectorAll(query));
3130
+ }
3131
+ var fetchPromises = {};
3132
+ function fetchTemplate(template) {
3133
+ if (fetchPromises[template]) return fetchPromises[template];
3134
+ return fetchPromises[template] = $http.get(template, {
3135
+ cache: $templateCache
3136
+ }).then(function(res) {
3137
+ return res.data;
3138
+ });
3139
+ }
3140
+ }
3141
+ angular.module('mgcrea.ngStrap.datepicker', [ 'mgcrea.ngStrap.helpers.dateParser', 'mgcrea.ngStrap.helpers.dateFormatter', 'mgcrea.ngStrap.tooltip' ]).provider('$datepicker', function() {
3142
+ var defaults = this.defaults = {
3143
+ animation: 'am-fade',
3144
+ prefixClass: 'datepicker',
3145
+ placement: 'bottom-left',
3146
+ templateUrl: 'datepicker/datepicker.tpl.html',
3147
+ trigger: 'focus',
3148
+ container: false,
3149
+ keyboard: true,
3150
+ html: false,
3151
+ delay: 0,
3152
+ useNative: false,
3153
+ dateType: 'date',
3154
+ dateFormat: 'shortDate',
3155
+ timezone: null,
3156
+ modelDateFormat: null,
3157
+ dayFormat: 'dd',
3158
+ monthFormat: 'MMM',
3159
+ yearFormat: 'yyyy',
3160
+ monthTitleFormat: 'MMMM yyyy',
3161
+ yearTitleFormat: 'yyyy',
3162
+ strictFormat: false,
3163
+ autoclose: false,
3164
+ minDate: -Infinity,
3165
+ maxDate: +Infinity,
3166
+ startView: 0,
3167
+ minView: 0,
3168
+ startWeek: 0,
3169
+ daysOfWeekDisabled: '',
3170
+ iconLeft: 'glyphicon glyphicon-chevron-left',
3171
+ iconRight: 'glyphicon glyphicon-chevron-right'
3172
+ };
3173
+ this.$get = [ '$window', '$document', '$rootScope', '$sce', '$dateFormatter', 'datepickerViews', '$tooltip', '$timeout', function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {
3174
+ var isNative = /(ip[ao]d|iphone|android)/gi.test($window.navigator.userAgent);
3175
+ var isTouch = 'createTouch' in $window.document && isNative;
3176
+ if (!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();
3177
+ function DatepickerFactory(element, controller, config) {
3178
+ var $datepicker = $tooltip(element, angular.extend({}, defaults, config));
3179
+ var parentScope = config.scope;
3180
+ var options = $datepicker.$options;
3181
+ var scope = $datepicker.$scope;
3182
+ if (options.startView) options.startView -= options.minView;
3183
+ var pickerViews = datepickerViews($datepicker);
3184
+ $datepicker.$views = pickerViews.views;
3185
+ var viewDate = pickerViews.viewDate;
3186
+ scope.$mode = options.startView;
3187
+ scope.$iconLeft = options.iconLeft;
3188
+ scope.$iconRight = options.iconRight;
3189
+ var $picker = $datepicker.$views[scope.$mode];
3190
+ scope.$select = function(date) {
3191
+ $datepicker.select(date);
3192
+ };
3193
+ scope.$selectPane = function(value) {
3194
+ $datepicker.$selectPane(value);
3195
+ };
3196
+ scope.$toggleMode = function() {
3197
+ $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);
3198
+ };
3199
+ $datepicker.update = function(date) {
3200
+ if (angular.isDate(date) && !isNaN(date.getTime())) {
3201
+ $datepicker.$date = date;
3202
+ $picker.update.call($picker, date);
3203
+ }
3204
+ $datepicker.$build(true);
3205
+ };
3206
+ $datepicker.updateDisabledDates = function(dateRanges) {
3207
+ options.disabledDateRanges = dateRanges;
3208
+ for (var i = 0, l = scope.rows.length; i < l; i++) {
3209
+ angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);
3210
+ }
3211
+ };
3212
+ $datepicker.select = function(date, keep) {
3213
+ if (!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);
3214
+ if (!scope.$mode || keep) {
3215
+ controller.$setViewValue(angular.copy(date));
3216
+ controller.$render();
3217
+ if (options.autoclose && !keep) {
3218
+ $timeout(function() {
3219
+ $datepicker.hide(true);
3220
+ });
3221
+ }
3222
+ } else {
3223
+ angular.extend(viewDate, {
3224
+ year: date.getFullYear(),
3225
+ month: date.getMonth(),
3226
+ date: date.getDate()
3227
+ });
3228
+ $datepicker.setMode(scope.$mode - 1);
3229
+ $datepicker.$build();
3230
+ }
3231
+ };
3232
+ $datepicker.setMode = function(mode) {
3233
+ scope.$mode = mode;
3234
+ $picker = $datepicker.$views[scope.$mode];
3235
+ $datepicker.$build();
3236
+ };
3237
+ $datepicker.$build = function(pristine) {
3238
+ if (pristine === true && $picker.built) return;
3239
+ if (pristine === false && !$picker.built) return;
3240
+ $picker.build.call($picker);
3241
+ };
3242
+ $datepicker.$updateSelected = function() {
3243
+ for (var i = 0, l = scope.rows.length; i < l; i++) {
3244
+ angular.forEach(scope.rows[i], updateSelected);
3245
+ }
3246
+ };
3247
+ $datepicker.$isSelected = function(date) {
3248
+ return $picker.isSelected(date);
3249
+ };
3250
+ $datepicker.$setDisabledEl = function(el) {
3251
+ el.disabled = $picker.isDisabled(el.date);
3252
+ };
3253
+ $datepicker.$selectPane = function(value) {
3254
+ var steps = $picker.steps;
3255
+ var targetDate = new Date(Date.UTC(viewDate.year + (steps.year || 0) * value, viewDate.month + (steps.month || 0) * value, 1));
3256
+ angular.extend(viewDate, {
3257
+ year: targetDate.getUTCFullYear(),
3258
+ month: targetDate.getUTCMonth(),
3259
+ date: targetDate.getUTCDate()
3260
+ });
3261
+ $datepicker.$build();
3262
+ };
3263
+ $datepicker.$onMouseDown = function(evt) {
3264
+ evt.preventDefault();
3265
+ evt.stopPropagation();
3266
+ if (isTouch) {
3267
+ var targetEl = angular.element(evt.target);
3268
+ if (targetEl[0].nodeName.toLowerCase() !== 'button') {
3269
+ targetEl = targetEl.parent();
3270
+ }
3271
+ targetEl.triggerHandler('click');
3272
+ }
3273
+ };
3274
+ $datepicker.$onKeyDown = function(evt) {
3275
+ if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;
3276
+ evt.preventDefault();
3277
+ evt.stopPropagation();
3278
+ if (evt.keyCode === 13) {
3279
+ if (!scope.$mode) {
3280
+ $datepicker.hide(true);
3281
+ } else {
3282
+ scope.$apply(function() {
3283
+ $datepicker.setMode(scope.$mode - 1);
3284
+ });
3285
+ }
3286
+ return;
3287
+ }
3288
+ $picker.onKeyDown(evt);
3289
+ parentScope.$digest();
3290
+ };
3291
+ function updateSelected(el) {
3292
+ el.selected = $datepicker.$isSelected(el.date);
3293
+ }
3294
+ function focusElement() {
3295
+ element[0].focus();
3296
+ }
3297
+ var _init = $datepicker.init;
3298
+ $datepicker.init = function() {
3299
+ if (isNative && options.useNative) {
3300
+ element.prop('type', 'date');
3301
+ element.css('-webkit-appearance', 'textfield');
3302
+ return;
3303
+ } else if (isTouch) {
3304
+ element.prop('type', 'text');
3305
+ element.attr('readonly', 'true');
3306
+ element.on('click', focusElement);
3307
+ }
3308
+ _init();
3309
+ };
3310
+ var _destroy = $datepicker.destroy;
3311
+ $datepicker.destroy = function() {
3312
+ if (isNative && options.useNative) {
3313
+ element.off('click', focusElement);
3314
+ }
3315
+ _destroy();
3316
+ };
3317
+ var _show = $datepicker.show;
3318
+ $datepicker.show = function() {
3319
+ if (!isTouch && element.attr('readonly') || element.attr('disabled')) return;
3320
+ _show();
3321
+ $timeout(function() {
3322
+ if (!$datepicker.$isShown) return;
3323
+ $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
3324
+ if (options.keyboard) {
3325
+ element.on('keydown', $datepicker.$onKeyDown);
3326
+ }
3327
+ }, 0, false);
3328
+ };
3329
+ var _hide = $datepicker.hide;
3330
+ $datepicker.hide = function(blur) {
3331
+ if (!$datepicker.$isShown) return;
3332
+ $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);
3333
+ if (options.keyboard) {
3334
+ element.off('keydown', $datepicker.$onKeyDown);
3335
+ }
3336
+ _hide(blur);
3337
+ };
3338
+ return $datepicker;
3339
+ }
3340
+ DatepickerFactory.defaults = defaults;
3341
+ return DatepickerFactory;
3342
+ } ];
3343
+ }).directive('bsDatepicker', [ '$window', '$parse', '$q', '$dateFormatter', '$dateParser', '$datepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {
3344
+ var isNative = /(ip[ao]d|iphone|android)/gi.test($window.navigator.userAgent);
3345
+ return {
3346
+ restrict: 'EAC',
3347
+ require: 'ngModel',
3348
+ link: function postLink(scope, element, attr, controller) {
3349
+ var options = {
3350
+ scope: scope
3351
+ };
3352
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'container', 'delay', 'trigger', 'html', 'animation', 'autoclose', 'dateType', 'dateFormat', 'timezone', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id', 'prefixClass', 'prefixEvent' ], function(key) {
3353
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
3354
+ });
3355
+ var falseValueRegExp = /^(false|0|)$/i;
3356
+ angular.forEach([ 'html', 'container', 'autoclose', 'useNative' ], function(key) {
3357
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) {
3358
+ options[key] = false;
3359
+ }
3360
+ });
3361
+ var datepicker = $datepicker(element, controller, options);
3362
+ options = datepicker.$options;
3363
+ if (isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';
3364
+ var lang = options.lang;
3365
+ var formatDate = function(date, format) {
3366
+ return $dateFormatter.formatDate(date, format, lang);
3367
+ };
3368
+ var dateParser = $dateParser({
3369
+ format: options.dateFormat,
3370
+ lang: lang,
3371
+ strict: options.strictFormat
3372
+ });
3373
+ if (attr.bsShow) {
3374
+ scope.$watch(attr.bsShow, function(newValue, oldValue) {
3375
+ if (!datepicker || !angular.isDefined(newValue)) return;
3376
+ if (angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);
3377
+ if (newValue === true) {
3378
+ datepicker.show();
3379
+ } else {
3380
+ datepicker.hide();
3381
+ }
3382
+ });
3383
+ }
3384
+ angular.forEach([ 'minDate', 'maxDate' ], function(key) {
3385
+ if (angular.isDefined(attr[key])) {
3386
+ attr.$observe(key, function(newValue) {
3387
+ datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);
3388
+ if (!isNaN(datepicker.$options[key])) datepicker.$build(false);
3389
+ validateAgainstMinMaxDate(controller.$dateValue);
3390
+ });
3391
+ }
3392
+ });
3393
+ if (angular.isDefined(attr.dateFormat)) {
3394
+ attr.$observe('dateFormat', function(newValue) {
3395
+ datepicker.$options.dateFormat = newValue;
3396
+ });
3397
+ }
3398
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
3399
+ datepicker.update(controller.$dateValue);
3400
+ }, true);
3401
+ function normalizeDateRanges(ranges) {
3402
+ if (!ranges || !ranges.length) return null;
3403
+ return ranges;
3404
+ }
3405
+ if (angular.isDefined(attr.disabledDates)) {
3406
+ scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {
3407
+ disabledRanges = normalizeDateRanges(disabledRanges);
3408
+ previousValue = normalizeDateRanges(previousValue);
3409
+ if (disabledRanges) {
3410
+ datepicker.updateDisabledDates(disabledRanges);
3411
+ }
3412
+ });
3413
+ }
3414
+ function validateAgainstMinMaxDate(parsedDate) {
3415
+ if (!angular.isDate(parsedDate)) return;
3416
+ var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;
3417
+ var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;
3418
+ var isValid = isMinValid && isMaxValid;
3419
+ controller.$setValidity('date', isValid);
3420
+ controller.$setValidity('min', isMinValid);
3421
+ controller.$setValidity('max', isMaxValid);
3422
+ if (isValid) controller.$dateValue = parsedDate;
3423
+ }
3424
+ controller.$parsers.unshift(function(viewValue) {
3425
+ var date;
3426
+ if (!viewValue) {
3427
+ controller.$setValidity('date', true);
3428
+ return null;
3429
+ }
3430
+ var parsedDate = dateParser.parse(viewValue, controller.$dateValue);
3431
+ if (!parsedDate || isNaN(parsedDate.getTime())) {
3432
+ controller.$setValidity('date', false);
3433
+ return;
3434
+ }
3435
+ validateAgainstMinMaxDate(parsedDate);
3436
+ if (options.dateType === 'string') {
3437
+ date = dateParser.timezoneOffsetAdjust(parsedDate, options.timezone, true);
3438
+ return formatDate(date, options.modelDateFormat || options.dateFormat);
3439
+ }
3440
+ date = dateParser.timezoneOffsetAdjust(controller.$dateValue, options.timezone, true);
3441
+ if (options.dateType === 'number') {
3442
+ return date.getTime();
3443
+ } else if (options.dateType === 'unix') {
3444
+ return date.getTime() / 1e3;
3445
+ } else if (options.dateType === 'iso') {
3446
+ return date.toISOString();
3447
+ }
3448
+ return new Date(date);
3449
+ });
3450
+ controller.$formatters.push(function(modelValue) {
3451
+ var date;
3452
+ if (angular.isUndefined(modelValue) || modelValue === null) {
3453
+ date = NaN;
3454
+ } else if (angular.isDate(modelValue)) {
3455
+ date = modelValue;
3456
+ } else if (options.dateType === 'string') {
3457
+ date = dateParser.parse(modelValue, null, options.modelDateFormat);
3458
+ } else if (options.dateType === 'unix') {
3459
+ date = new Date(modelValue * 1e3);
3460
+ } else {
3461
+ date = new Date(modelValue);
3462
+ }
3463
+ controller.$dateValue = dateParser.timezoneOffsetAdjust(date, options.timezone);
3464
+ return getDateFormattedString();
3465
+ });
3466
+ controller.$render = function() {
3467
+ element.val(getDateFormattedString());
3468
+ };
3469
+ function getDateFormattedString() {
3470
+ return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);
3471
+ }
3472
+ scope.$on('$destroy', function() {
3473
+ if (datepicker) datepicker.destroy();
3474
+ options = null;
3475
+ datepicker = null;
3476
+ });
3477
+ }
3478
+ };
3479
+ } ]).provider('datepickerViews', function() {
3480
+ function split(arr, size) {
3481
+ var arrays = [];
3482
+ while (arr.length > 0) {
3483
+ arrays.push(arr.splice(0, size));
3484
+ }
3485
+ return arrays;
3486
+ }
3487
+ function mod(n, m) {
3488
+ return (n % m + m) % m;
3489
+ }
3490
+ this.$get = [ '$dateFormatter', '$dateParser', '$sce', function($dateFormatter, $dateParser, $sce) {
3491
+ return function(picker) {
3492
+ var scope = picker.$scope;
3493
+ var options = picker.$options;
3494
+ var lang = options.lang;
3495
+ var formatDate = function(date, format) {
3496
+ return $dateFormatter.formatDate(date, format, lang);
3497
+ };
3498
+ var dateParser = $dateParser({
3499
+ format: options.dateFormat,
3500
+ lang: lang,
3501
+ strict: options.strictFormat
3502
+ });
3503
+ var weekDaysMin = $dateFormatter.weekdaysShort(lang);
3504
+ var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));
3505
+ var weekDaysLabelsHtml = $sce.trustAsHtml('<th class="dow text-center">' + weekDaysLabels.join('</th><th class="dow text-center">') + '</th>');
3506
+ var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());
3507
+ var viewDate = {
3508
+ year: startDate.getFullYear(),
3509
+ month: startDate.getMonth(),
3510
+ date: startDate.getDate()
3511
+ };
3512
+ var views = [ {
3513
+ format: options.dayFormat,
3514
+ split: 7,
3515
+ steps: {
3516
+ month: 1
3517
+ },
3518
+ update: function(date, force) {
3519
+ if (!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {
3520
+ angular.extend(viewDate, {
3521
+ year: picker.$date.getFullYear(),
3522
+ month: picker.$date.getMonth(),
3523
+ date: picker.$date.getDate()
3524
+ });
3525
+ picker.$build();
3526
+ } else if (date.getDate() !== viewDate.date || date.getDate() === 1) {
3527
+ viewDate.date = picker.$date.getDate();
3528
+ picker.$updateSelected();
3529
+ }
3530
+ },
3531
+ build: function() {
3532
+ var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1);
3533
+ var firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();
3534
+ var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5);
3535
+ var firstDateOffset = firstDate.getTimezoneOffset();
3536
+ var today = dateParser.timezoneOffsetAdjust(new Date(), options.timezone).toDateString();
3537
+ if (firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 6e4);
3538
+ var days = [];
3539
+ var day;
3540
+ for (var i = 0; i < 42; i++) {
3541
+ day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));
3542
+ days.push({
3543
+ date: day,
3544
+ isToday: day.toDateString() === today,
3545
+ label: formatDate(day, this.format),
3546
+ selected: picker.$date && this.isSelected(day),
3547
+ muted: day.getMonth() !== viewDate.month,
3548
+ disabled: this.isDisabled(day)
3549
+ });
3550
+ }
3551
+ scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);
3552
+ scope.showLabels = true;
3553
+ scope.labels = weekDaysLabelsHtml;
3554
+ scope.rows = split(days, this.split);
3555
+ this.built = true;
3556
+ },
3557
+ isSelected: function(date) {
3558
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();
3559
+ },
3560
+ isDisabled: function(date) {
3561
+ var time = date.getTime();
3562
+ if (time < options.minDate || time > options.maxDate) return true;
3563
+ if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;
3564
+ if (options.disabledDateRanges) {
3565
+ for (var i = 0; i < options.disabledDateRanges.length; i++) {
3566
+ if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {
3567
+ return true;
3568
+ }
3569
+ }
3570
+ }
3571
+ return false;
3572
+ },
3573
+ onKeyDown: function(evt) {
3574
+ if (!picker.$date) {
3575
+ return;
3576
+ }
3577
+ var actualTime = picker.$date.getTime();
3578
+ var newDate;
3579
+ if (evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5); else if (evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5); else if (evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5); else if (evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);
3580
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
3581
+ }
3582
+ }, {
3583
+ name: 'month',
3584
+ format: options.monthFormat,
3585
+ split: 4,
3586
+ steps: {
3587
+ year: 1
3588
+ },
3589
+ update: function(date, force) {
3590
+ if (!this.built || date.getFullYear() !== viewDate.year) {
3591
+ angular.extend(viewDate, {
3592
+ year: picker.$date.getFullYear(),
3593
+ month: picker.$date.getMonth(),
3594
+ date: picker.$date.getDate()
3595
+ });
3596
+ picker.$build();
3597
+ } else if (date.getMonth() !== viewDate.month) {
3598
+ angular.extend(viewDate, {
3599
+ month: picker.$date.getMonth(),
3600
+ date: picker.$date.getDate()
3601
+ });
3602
+ picker.$updateSelected();
3603
+ }
3604
+ },
3605
+ build: function() {
3606
+ var months = [];
3607
+ var month;
3608
+ for (var i = 0; i < 12; i++) {
3609
+ month = new Date(viewDate.year, i, 1);
3610
+ months.push({
3611
+ date: month,
3612
+ label: formatDate(month, this.format),
3613
+ selected: picker.$isSelected(month),
3614
+ disabled: this.isDisabled(month)
3615
+ });
3616
+ }
3617
+ scope.title = formatDate(month, options.yearTitleFormat);
3618
+ scope.showLabels = false;
3619
+ scope.rows = split(months, this.split);
3620
+ this.built = true;
3621
+ },
3622
+ isSelected: function(date) {
3623
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();
3624
+ },
3625
+ isDisabled: function(date) {
3626
+ var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);
3627
+ return lastDate < options.minDate || date.getTime() > options.maxDate;
3628
+ },
3629
+ onKeyDown: function(evt) {
3630
+ if (!picker.$date) {
3631
+ return;
3632
+ }
3633
+ var actualMonth = picker.$date.getMonth();
3634
+ var newDate = new Date(picker.$date);
3635
+ if (evt.keyCode === 37) newDate.setMonth(actualMonth - 1); else if (evt.keyCode === 38) newDate.setMonth(actualMonth - 4); else if (evt.keyCode === 39) newDate.setMonth(actualMonth + 1); else if (evt.keyCode === 40) newDate.setMonth(actualMonth + 4);
3636
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
3637
+ }
3638
+ }, {
3639
+ name: 'year',
3640
+ format: options.yearFormat,
3641
+ split: 4,
3642
+ steps: {
3643
+ year: 12
3644
+ },
3645
+ update: function(date, force) {
3646
+ if (!this.built || force || parseInt(date.getFullYear() / 20, 10) !== parseInt(viewDate.year / 20, 10)) {
3647
+ angular.extend(viewDate, {
3648
+ year: picker.$date.getFullYear(),
3649
+ month: picker.$date.getMonth(),
3650
+ date: picker.$date.getDate()
3651
+ });
3652
+ picker.$build();
3653
+ } else if (date.getFullYear() !== viewDate.year) {
3654
+ angular.extend(viewDate, {
3655
+ year: picker.$date.getFullYear(),
3656
+ month: picker.$date.getMonth(),
3657
+ date: picker.$date.getDate()
3658
+ });
3659
+ picker.$updateSelected();
3660
+ }
3661
+ },
3662
+ build: function() {
3663
+ var firstYear = viewDate.year - viewDate.year % (this.split * 3);
3664
+ var years = [];
3665
+ var year;
3666
+ for (var i = 0; i < 12; i++) {
3667
+ year = new Date(firstYear + i, 0, 1);
3668
+ years.push({
3669
+ date: year,
3670
+ label: formatDate(year, this.format),
3671
+ selected: picker.$isSelected(year),
3672
+ disabled: this.isDisabled(year)
3673
+ });
3674
+ }
3675
+ scope.title = years[0].label + '-' + years[years.length - 1].label;
3676
+ scope.showLabels = false;
3677
+ scope.rows = split(years, this.split);
3678
+ this.built = true;
3679
+ },
3680
+ isSelected: function(date) {
3681
+ return picker.$date && date.getFullYear() === picker.$date.getFullYear();
3682
+ },
3683
+ isDisabled: function(date) {
3684
+ var lastDate = +new Date(date.getFullYear() + 1, 0, 0);
3685
+ return lastDate < options.minDate || date.getTime() > options.maxDate;
3686
+ },
3687
+ onKeyDown: function(evt) {
3688
+ if (!picker.$date) {
3689
+ return;
3690
+ }
3691
+ var actualYear = picker.$date.getFullYear();
3692
+ var newDate = new Date(picker.$date);
3693
+ if (evt.keyCode === 37) newDate.setYear(actualYear - 1); else if (evt.keyCode === 38) newDate.setYear(actualYear - 4); else if (evt.keyCode === 39) newDate.setYear(actualYear + 1); else if (evt.keyCode === 40) newDate.setYear(actualYear + 4);
3694
+ if (!this.isDisabled(newDate)) picker.select(newDate, true);
3695
+ }
3696
+ } ];
3697
+ return {
3698
+ views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,
3699
+ viewDate: viewDate
3700
+ };
3701
+ };
3702
+ } ];
3703
+ });
3704
+ angular.module('mgcrea.ngStrap.collapse', []).provider('$collapse', function() {
3705
+ var defaults = this.defaults = {
3706
+ animation: 'am-collapse',
3707
+ disallowToggle: false,
3708
+ activeClass: 'in',
3709
+ startCollapsed: false,
3710
+ allowMultiple: false
3711
+ };
3712
+ var controller = this.controller = function($scope, $element, $attrs) {
3713
+ var self = this;
3714
+ self.$options = angular.copy(defaults);
3715
+ angular.forEach([ 'animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple' ], function(key) {
3716
+ if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
3717
+ });
3718
+ var falseValueRegExp = /^(false|0|)$/i;
3719
+ angular.forEach([ 'disallowToggle', 'startCollapsed', 'allowMultiple' ], function(key) {
3720
+ if (angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) {
3721
+ self.$options[key] = false;
3722
+ }
3723
+ });
3724
+ self.$toggles = [];
3725
+ self.$targets = [];
3726
+ self.$viewChangeListeners = [];
3727
+ self.$registerToggle = function(element) {
3728
+ self.$toggles.push(element);
3729
+ };
3730
+ self.$registerTarget = function(element) {
3731
+ self.$targets.push(element);
3732
+ };
3733
+ self.$unregisterToggle = function(element) {
3734
+ var index = self.$toggles.indexOf(element);
3735
+ self.$toggles.splice(index, 1);
3736
+ };
3737
+ self.$unregisterTarget = function(element) {
3738
+ var index = self.$targets.indexOf(element);
3739
+ self.$targets.splice(index, 1);
3740
+ if (self.$options.allowMultiple) {
3741
+ deactivateItem(element);
3742
+ }
3743
+ fixActiveItemIndexes(index);
3744
+ self.$viewChangeListeners.forEach(function(fn) {
3745
+ fn();
3746
+ });
3747
+ };
3748
+ self.$targets.$active = !self.$options.startCollapsed ? [ 0 ] : [];
3749
+ self.$setActive = $scope.$setActive = function(value) {
3750
+ if (angular.isArray(value)) {
3751
+ self.$targets.$active = value;
3752
+ } else if (!self.$options.disallowToggle && isActive(value)) {
3753
+ deactivateItem(value);
3754
+ } else {
3755
+ activateItem(value);
3756
+ }
3757
+ self.$viewChangeListeners.forEach(function(fn) {
3758
+ fn();
3759
+ });
3760
+ };
3761
+ self.$activeIndexes = function() {
3762
+ if (self.$options.allowMultiple) {
3763
+ return self.$targets.$active;
3764
+ }
3765
+ return self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;
3766
+ };
3767
+ function fixActiveItemIndexes(index) {
3768
+ var activeIndexes = self.$targets.$active;
3769
+ for (var i = 0; i < activeIndexes.length; i++) {
3770
+ if (index < activeIndexes[i]) {
3771
+ activeIndexes[i] = activeIndexes[i] - 1;
3772
+ }
3773
+ if (activeIndexes[i] === self.$targets.length) {
3774
+ activeIndexes[i] = self.$targets.length - 1;
3775
+ }
3776
+ }
3777
+ }
3778
+ function isActive(value) {
3779
+ var activeItems = self.$targets.$active;
3780
+ return activeItems.indexOf(value) !== -1;
3781
+ }
3782
+ function deactivateItem(value) {
3783
+ var index = self.$targets.$active.indexOf(value);
3784
+ if (index !== -1) {
3785
+ self.$targets.$active.splice(index, 1);
3786
+ }
3787
+ }
3788
+ function activateItem(value) {
3789
+ if (!self.$options.allowMultiple) {
3790
+ self.$targets.$active.splice(0, 1);
3791
+ }
3792
+ if (self.$targets.$active.indexOf(value) === -1) {
3793
+ self.$targets.$active.push(value);
3794
+ }
3795
+ }
3796
+ };
3797
+ this.$get = function() {
3798
+ var $collapse = {};
3799
+ $collapse.defaults = defaults;
3800
+ $collapse.controller = controller;
3801
+ return $collapse;
3802
+ };
3803
+ }).directive('bsCollapse', [ '$window', '$animate', '$collapse', function($window, $animate, $collapse) {
3804
+ return {
3805
+ require: [ '?ngModel', 'bsCollapse' ],
3806
+ controller: [ '$scope', '$element', '$attrs', $collapse.controller ],
3807
+ link: function postLink(scope, element, attrs, controllers) {
3808
+ var ngModelCtrl = controllers[0];
3809
+ var bsCollapseCtrl = controllers[1];
3810
+ if (ngModelCtrl) {
3811
+ bsCollapseCtrl.$viewChangeListeners.push(function() {
3812
+ ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());
3813
+ });
3814
+ ngModelCtrl.$formatters.push(function(modelValue) {
3815
+ if (angular.isArray(modelValue)) {
3816
+ bsCollapseCtrl.$setActive(modelValue);
3817
+ } else {
3818
+ var activeIndexes = bsCollapseCtrl.$activeIndexes();
3819
+ if (angular.isArray(activeIndexes)) {
3820
+ if (activeIndexes.indexOf(modelValue * 1) === -1) {
3821
+ bsCollapseCtrl.$setActive(modelValue * 1);
3822
+ }
3823
+ } else if (activeIndexes !== modelValue * 1) {
3824
+ bsCollapseCtrl.$setActive(modelValue * 1);
3825
+ }
3826
+ }
3827
+ return modelValue;
3828
+ });
3829
+ }
3830
+ }
3831
+ };
3832
+ } ]).directive('bsCollapseToggle', function() {
3833
+ return {
3834
+ require: [ '^?ngModel', '^bsCollapse' ],
3835
+ link: function postLink(scope, element, attrs, controllers) {
3836
+ var bsCollapseCtrl = controllers[1];
3837
+ element.attr('data-toggle', 'collapse');
3838
+ bsCollapseCtrl.$registerToggle(element);
3839
+ scope.$on('$destroy', function() {
3840
+ bsCollapseCtrl.$unregisterToggle(element);
3841
+ });
3842
+ element.on('click', function() {
3843
+ if (!attrs.disabled) {
3844
+ var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element);
3845
+ bsCollapseCtrl.$setActive(index * 1);
3846
+ scope.$apply();
3847
+ }
3848
+ });
3849
+ }
3850
+ };
3851
+ }).directive('bsCollapseTarget', [ '$animate', function($animate) {
3852
+ return {
3853
+ require: [ '^?ngModel', '^bsCollapse' ],
3854
+ link: function postLink(scope, element, attrs, controllers) {
3855
+ var bsCollapseCtrl = controllers[1];
3856
+ element.addClass('collapse');
3857
+ if (bsCollapseCtrl.$options.animation) {
3858
+ element.addClass(bsCollapseCtrl.$options.animation);
3859
+ }
3860
+ bsCollapseCtrl.$registerTarget(element);
3861
+ scope.$on('$destroy', function() {
3862
+ bsCollapseCtrl.$unregisterTarget(element);
3863
+ });
3864
+ function render() {
3865
+ var index = bsCollapseCtrl.$targets.indexOf(element);
3866
+ var active = bsCollapseCtrl.$activeIndexes();
3867
+ var action = 'removeClass';
3868
+ if (angular.isArray(active)) {
3869
+ if (active.indexOf(index) !== -1) {
3870
+ action = 'addClass';
3871
+ }
3872
+ } else if (index === active) {
3873
+ action = 'addClass';
3874
+ }
3875
+ $animate[action](element, bsCollapseCtrl.$options.activeClass);
3876
+ }
3877
+ bsCollapseCtrl.$viewChangeListeners.push(function() {
3878
+ render();
3879
+ });
3880
+ render();
3881
+ }
3882
+ };
3883
+ } ]);
3884
+ angular.module('mgcrea.ngStrap.button', []).provider('$button', function() {
3885
+ var defaults = this.defaults = {
3886
+ activeClass: 'active',
3887
+ toggleEvent: 'click'
3888
+ };
3889
+ this.$get = function() {
3890
+ return {
3891
+ defaults: defaults
3892
+ };
3893
+ };
3894
+ }).directive('bsCheckboxGroup', function() {
3895
+ return {
3896
+ restrict: 'A',
3897
+ require: 'ngModel',
3898
+ compile: function postLink(element, attr) {
3899
+ element.attr('data-toggle', 'buttons');
3900
+ element.removeAttr('ng-model');
3901
+ var children = element[0].querySelectorAll('input[type="checkbox"]');
3902
+ angular.forEach(children, function(child) {
3903
+ var childEl = angular.element(child);
3904
+ childEl.attr('bs-checkbox', '');
3905
+ childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));
3906
+ });
3907
+ }
3908
+ };
3909
+ }).directive('bsCheckbox', [ '$button', '$$rAF', function($button, $$rAF) {
3910
+ var defaults = $button.defaults;
3911
+ var constantValueRegExp = /^(true|false|\d+)$/;
3912
+ return {
3913
+ restrict: 'A',
3914
+ require: 'ngModel',
3915
+ link: function postLink(scope, element, attr, controller) {
3916
+ var options = defaults;
3917
+ var isInput = element[0].nodeName === 'INPUT';
3918
+ var activeElement = isInput ? element.parent() : element;
3919
+ var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;
3920
+ if (constantValueRegExp.test(attr.trueValue)) {
3921
+ trueValue = scope.$eval(attr.trueValue);
3922
+ }
3923
+ var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;
3924
+ if (constantValueRegExp.test(attr.falseValue)) {
3925
+ falseValue = scope.$eval(attr.falseValue);
3926
+ }
3927
+ var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';
3928
+ if (hasExoticValues) {
3929
+ controller.$parsers.push(function(viewValue) {
3930
+ return viewValue ? trueValue : falseValue;
3931
+ });
3932
+ controller.$formatters.push(function(modelValue) {
3933
+ return angular.equals(modelValue, trueValue);
3934
+ });
3935
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
3936
+ controller.$render();
3937
+ });
3938
+ }
3939
+ controller.$render = function() {
3940
+ var isActive = angular.equals(controller.$modelValue, trueValue);
3941
+ $$rAF(function() {
3942
+ if (isInput) element[0].checked = isActive;
3943
+ activeElement.toggleClass(options.activeClass, isActive);
3944
+ });
3945
+ };
3946
+ element.bind(options.toggleEvent, function() {
3947
+ scope.$apply(function() {
3948
+ if (!isInput) {
3949
+ controller.$setViewValue(!activeElement.hasClass('active'));
3950
+ }
3951
+ if (!hasExoticValues) {
3952
+ controller.$render();
3953
+ }
3954
+ });
3955
+ });
3956
+ }
3957
+ };
3958
+ } ]).directive('bsRadioGroup', function() {
3959
+ return {
3960
+ restrict: 'A',
3961
+ require: 'ngModel',
3962
+ compile: function postLink(element, attr) {
3963
+ element.attr('data-toggle', 'buttons');
3964
+ element.removeAttr('ng-model');
3965
+ var children = element[0].querySelectorAll('input[type="radio"]');
3966
+ angular.forEach(children, function(child) {
3967
+ angular.element(child).attr('bs-radio', '');
3968
+ angular.element(child).attr('ng-model', attr.ngModel);
3969
+ });
3970
+ }
3971
+ };
3972
+ }).directive('bsRadio', [ '$button', '$$rAF', function($button, $$rAF) {
3973
+ var defaults = $button.defaults;
3974
+ var constantValueRegExp = /^(true|false|\d+)$/;
3975
+ return {
3976
+ restrict: 'A',
3977
+ require: 'ngModel',
3978
+ link: function postLink(scope, element, attr, controller) {
3979
+ var options = defaults;
3980
+ var isInput = element[0].nodeName === 'INPUT';
3981
+ var activeElement = isInput ? element.parent() : element;
3982
+ var value;
3983
+ attr.$observe('value', function(v) {
3984
+ if (typeof v !== 'boolean' && constantValueRegExp.test(v)) {
3985
+ value = scope.$eval(v);
3986
+ } else {
3987
+ value = v;
3988
+ }
3989
+ controller.$render();
3990
+ });
3991
+ controller.$render = function() {
3992
+ var isActive = angular.equals(controller.$modelValue, value);
3993
+ $$rAF(function() {
3994
+ if (isInput) element[0].checked = isActive;
3995
+ activeElement.toggleClass(options.activeClass, isActive);
3996
+ });
3997
+ };
3998
+ element.bind(options.toggleEvent, function() {
3999
+ scope.$apply(function() {
4000
+ controller.$setViewValue(value);
4001
+ controller.$render();
4002
+ });
4003
+ });
4004
+ }
4005
+ };
4006
+ } ]);
4007
+ angular.module('mgcrea.ngStrap.alert', [ 'mgcrea.ngStrap.modal' ]).provider('$alert', function() {
4008
+ var defaults = this.defaults = {
4009
+ animation: 'am-fade',
4010
+ prefixClass: 'alert',
4011
+ prefixEvent: 'alert',
4012
+ placement: null,
4013
+ templateUrl: 'alert/alert.tpl.html',
4014
+ container: false,
4015
+ element: null,
4016
+ backdrop: false,
4017
+ keyboard: true,
4018
+ show: true,
4019
+ duration: false,
4020
+ type: false,
4021
+ dismissable: true
4022
+ };
4023
+ this.$get = [ '$modal', '$timeout', function($modal, $timeout) {
4024
+ function AlertFactory(config) {
4025
+ var $alert = {};
4026
+ var options = angular.extend({}, defaults, config);
4027
+ $alert = $modal(options);
4028
+ $alert.$scope.dismissable = !!options.dismissable;
4029
+ if (options.type) {
4030
+ $alert.$scope.type = options.type;
4031
+ }
4032
+ var show = $alert.show;
4033
+ if (options.duration) {
4034
+ $alert.show = function() {
4035
+ show();
4036
+ $timeout(function() {
4037
+ $alert.hide();
4038
+ }, options.duration * 1e3);
4039
+ };
4040
+ }
4041
+ return $alert;
4042
+ }
4043
+ return AlertFactory;
4044
+ } ];
4045
+ }).directive('bsAlert', [ '$window', '$sce', '$alert', function($window, $sce, $alert) {
4046
+ return {
4047
+ restrict: 'EAC',
4048
+ scope: true,
4049
+ link: function postLink(scope, element, attr, transclusion) {
4050
+ var options = {
4051
+ scope: scope,
4052
+ element: element,
4053
+ show: false
4054
+ };
4055
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable' ], function(key) {
4056
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
4057
+ });
4058
+ var falseValueRegExp = /^(false|0|)$/i;
4059
+ angular.forEach([ 'keyboard', 'html', 'container', 'dismissable' ], function(key) {
4060
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
4061
+ });
4062
+ if (!scope.hasOwnProperty('title')) {
4063
+ scope.title = '';
4064
+ }
4065
+ angular.forEach([ 'title', 'content', 'type' ], function(key) {
4066
+ if (attr[key]) {
4067
+ attr.$observe(key, function(newValue, oldValue) {
4068
+ scope[key] = $sce.trustAsHtml(newValue);
4069
+ });
4070
+ }
4071
+ });
4072
+ if (attr.bsAlert) {
4073
+ scope.$watch(attr.bsAlert, function(newValue, oldValue) {
4074
+ if (angular.isObject(newValue)) {
4075
+ angular.extend(scope, newValue);
4076
+ } else {
4077
+ scope.content = newValue;
4078
+ }
4079
+ }, true);
4080
+ }
4081
+ var alert = $alert(options);
4082
+ element.on(attr.trigger || 'click', alert.toggle);
4083
+ scope.$on('$destroy', function() {
4084
+ if (alert) alert.destroy();
4085
+ options = null;
4086
+ alert = null;
4087
+ });
4088
+ }
4089
+ };
4090
+ } ]);
4091
+ angular.module('mgcrea.ngStrap.aside', [ 'mgcrea.ngStrap.modal' ]).provider('$aside', function() {
4092
+ var defaults = this.defaults = {
4093
+ animation: 'am-fade-and-slide-right',
4094
+ prefixClass: 'aside',
4095
+ prefixEvent: 'aside',
4096
+ placement: 'right',
4097
+ templateUrl: 'aside/aside.tpl.html',
4098
+ contentTemplate: false,
4099
+ container: false,
4100
+ element: null,
4101
+ backdrop: true,
4102
+ keyboard: true,
4103
+ html: false,
4104
+ show: true
4105
+ };
4106
+ this.$get = [ '$modal', function($modal) {
4107
+ function AsideFactory(config) {
4108
+ var $aside = {};
4109
+ var options = angular.extend({}, defaults, config);
4110
+ $aside = $modal(options);
4111
+ return $aside;
4112
+ }
4113
+ return AsideFactory;
4114
+ } ];
4115
+ }).directive('bsAside', [ '$window', '$sce', '$aside', function($window, $sce, $aside) {
4116
+ return {
4117
+ restrict: 'EAC',
4118
+ scope: true,
4119
+ link: function postLink(scope, element, attr, transclusion) {
4120
+ var options = {
4121
+ scope: scope,
4122
+ element: element,
4123
+ show: false
4124
+ };
4125
+ angular.forEach([ 'template', 'templateUrl', 'controller', 'controllerAs', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation' ], function(key) {
4126
+ if (angular.isDefined(attr[key])) options[key] = attr[key];
4127
+ });
4128
+ var falseValueRegExp = /^(false|0|)$/i;
4129
+ angular.forEach([ 'backdrop', 'keyboard', 'html', 'container' ], function(key) {
4130
+ if (angular.isDefined(attr[key]) && falseValueRegExp.test(attr[key])) options[key] = false;
4131
+ });
4132
+ angular.forEach([ 'title', 'content' ], function(key) {
4133
+ if (attr[key]) {
4134
+ attr.$observe(key, function(newValue, oldValue) {
4135
+ scope[key] = $sce.trustAsHtml(newValue);
4136
+ });
4137
+ }
4138
+ });
4139
+ if (attr.bsAside) {
4140
+ scope.$watch(attr.bsAside, function(newValue, oldValue) {
4141
+ if (angular.isObject(newValue)) {
4142
+ angular.extend(scope, newValue);
4143
+ } else {
4144
+ scope.content = newValue;
4145
+ }
4146
+ }, true);
4147
+ }
4148
+ var aside = $aside(options);
4149
+ element.on(attr.trigger || 'click', aside.toggle);
4150
+ scope.$on('$destroy', function() {
4151
+ if (aside) aside.destroy();
4152
+ options = null;
4153
+ aside = null;
4154
+ });
4155
+ }
4156
+ };
4157
+ } ]);
4158
+ angular.module('mgcrea.ngStrap.affix', [ 'mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce' ]).provider('$affix', function() {
4159
+ var defaults = this.defaults = {
4160
+ offsetTop: 'auto',
4161
+ inlineStyles: true
4162
+ };
4163
+ this.$get = [ '$window', 'debounce', 'dimensions', function($window, debounce, dimensions) {
4164
+ var bodyEl = angular.element($window.document.body);
4165
+ var windowEl = angular.element($window);
4166
+ function AffixFactory(element, config) {
4167
+ var $affix = {};
4168
+ var options = angular.extend({}, defaults, config);
4169
+ var targetEl = options.target;
4170
+ var reset = 'affix affix-top affix-bottom';
4171
+ var setWidth = false;
4172
+ var initialAffixTop = 0;
4173
+ var initialOffsetTop = 0;
4174
+ var offsetTop = 0;
4175
+ var offsetBottom = 0;
4176
+ var affixed = null;
4177
+ var unpin = null;
4178
+ var parent = element.parent();
4179
+ if (options.offsetParent) {
4180
+ if (options.offsetParent.match(/^\d+$/)) {
4181
+ for (var i = 0; i < options.offsetParent * 1 - 1; i++) {
4182
+ parent = parent.parent();
4183
+ }
4184
+ } else {
4185
+ parent = angular.element(options.offsetParent);
4186
+ }
4187
+ }
4188
+ $affix.init = function() {
4189
+ this.$parseOffsets();
4190
+ initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;
4191
+ setWidth = !element[0].style.width;
4192
+ targetEl.on('scroll', this.checkPosition);
4193
+ targetEl.on('click', this.checkPositionWithEventLoop);
4194
+ windowEl.on('resize', this.$debouncedOnResize);
4195
+ this.checkPosition();
4196
+ this.checkPositionWithEventLoop();
4197
+ };
4198
+ $affix.destroy = function() {
4199
+ targetEl.off('scroll', this.checkPosition);
4200
+ targetEl.off('click', this.checkPositionWithEventLoop);
4201
+ windowEl.off('resize', this.$debouncedOnResize);
4202
+ };
4203
+ $affix.checkPositionWithEventLoop = function() {
4204
+ setTimeout($affix.checkPosition, 1);
4205
+ };
4206
+ $affix.checkPosition = function() {
4207
+ var scrollTop = getScrollTop();
4208
+ var position = dimensions.offset(element[0]);
4209
+ var elementHeight = dimensions.height(element[0]);
4210
+ var affix = getRequiredAffixClass(unpin, position, elementHeight);
4211
+ if (affixed === affix) return;
4212
+ affixed = affix;
4213
+ if (affix === 'top') {
4214
+ unpin = null;
4215
+ if (setWidth) {
4216
+ element.css('width', '');
4217
+ }
4218
+ if (options.inlineStyles) {
4219
+ element.css('position', options.offsetParent ? '' : 'relative');
4220
+ element.css('top', '');
4221
+ }
4222
+ } else if (affix === 'bottom') {
4223
+ if (options.offsetUnpin) {
4224
+ unpin = -(options.offsetUnpin * 1);
4225
+ } else {
4226
+ unpin = position.top - scrollTop;
4227
+ }
4228
+ if (setWidth) {
4229
+ element.css('width', '');
4230
+ }
4231
+ if (options.inlineStyles) {
4232
+ element.css('position', options.offsetParent ? '' : 'relative');
4233
+ element.css('top', options.offsetParent ? '' : bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop + 'px');
4234
+ }
4235
+ } else {
4236
+ unpin = null;
4237
+ if (setWidth) {
4238
+ element.css('width', element[0].offsetWidth + 'px');
4239
+ }
4240
+ if (options.inlineStyles) {
4241
+ element.css('position', 'fixed');
4242
+ element.css('top', initialAffixTop + 'px');
4243
+ }
4244
+ }
4245
+ element.removeClass(reset).addClass('affix' + (affix !== 'middle' ? '-' + affix : ''));
4246
+ };
4247
+ $affix.$onResize = function() {
4248
+ $affix.$parseOffsets();
4249
+ $affix.checkPosition();
4250
+ };
4251
+ $affix.$debouncedOnResize = debounce($affix.$onResize, 50);
4252
+ $affix.$parseOffsets = function() {
4253
+ var initialPosition = element.css('position');
4254
+ if (options.inlineStyles) {
4255
+ element.css('position', options.offsetParent ? '' : 'relative');
4256
+ }
4257
+ if (options.offsetTop) {
4258
+ if (options.offsetTop === 'auto') {
4259
+ options.offsetTop = '+0';
4260
+ }
4261
+ if (options.offsetTop.match(/^[-+]\d+$/)) {
4262
+ initialAffixTop = -options.offsetTop * 1;
4263
+ if (options.offsetParent) {
4264
+ offsetTop = dimensions.offset(parent[0]).top + options.offsetTop * 1;
4265
+ } else {
4266
+ offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + options.offsetTop * 1;
4267
+ }
4268
+ } else {
4269
+ offsetTop = options.offsetTop * 1;
4270
+ }
4271
+ }
4272
+ if (options.offsetBottom) {
4273
+ if (options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) {
4274
+ offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + options.offsetBottom * 1 + 1;
4275
+ } else {
4276
+ offsetBottom = options.offsetBottom * 1;
4277
+ }
4278
+ }
4279
+ if (options.inlineStyles) {
4280
+ element.css('position', initialPosition);
4281
+ }
4282
+ };
4283
+ function getRequiredAffixClass(_unpin, position, elementHeight) {
4284
+ var scrollTop = getScrollTop();
4285
+ var scrollHeight = getScrollHeight();
4286
+ if (scrollTop <= offsetTop) {
4287
+ return 'top';
4288
+ } else if (_unpin !== null && scrollTop + _unpin <= position.top) {
4289
+ return 'middle';
4290
+ } else if (offsetBottom !== null && position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom) {
4291
+ return 'bottom';
4292
+ }
4293
+ return 'middle';
4294
+ }
4295
+ function getScrollTop() {
4296
+ return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;
4297
+ }
4298
+ function getScrollHeight() {
4299
+ return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;
4300
+ }
4301
+ $affix.init();
4302
+ return $affix;
4303
+ }
4304
+ return AffixFactory;
4305
+ } ];
4306
+ }).directive('bsAffix', [ '$affix', '$window', function($affix, $window) {
4307
+ return {
4308
+ restrict: 'EAC',
4309
+ require: '^?bsAffixTarget',
4310
+ link: function postLink(scope, element, attr, affixTarget) {
4311
+ var options = {
4312
+ scope: scope,
4313
+ target: affixTarget ? affixTarget.$element : angular.element($window)
4314
+ };
4315
+ angular.forEach([ 'offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin', 'inlineStyles' ], function(key) {
4316
+ if (angular.isDefined(attr[key])) {
4317
+ var option = attr[key];
4318
+ if (/true/i.test(option)) option = true;
4319
+ if (/false/i.test(option)) option = false;
4320
+ options[key] = option;
4321
+ }
4322
+ });
4323
+ var affix = $affix(element, options);
4324
+ scope.$on('$destroy', function() {
4325
+ if (affix) affix.destroy();
4326
+ options = null;
4327
+ affix = null;
4328
+ });
4329
+ }
4330
+ };
4331
+ } ]).directive('bsAffixTarget', function() {
4332
+ return {
4333
+ controller: [ '$element', function($element) {
4334
+ this.$element = $element;
4335
+ } ]
4336
+ };
4337
+ });
4338
+ angular.module('mgcrea.ngStrap', [ 'mgcrea.ngStrap.modal', 'mgcrea.ngStrap.aside', 'mgcrea.ngStrap.alert', 'mgcrea.ngStrap.button', 'mgcrea.ngStrap.select', 'mgcrea.ngStrap.datepicker', 'mgcrea.ngStrap.timepicker', 'mgcrea.ngStrap.navbar', 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.popover', 'mgcrea.ngStrap.dropdown', 'mgcrea.ngStrap.typeahead', 'mgcrea.ngStrap.scrollspy', 'mgcrea.ngStrap.affix', 'mgcrea.ngStrap.tab', 'mgcrea.ngStrap.collapse' ]);
4339
+ })(window, document);