rails-angularstrap 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +89 -0
  3. data/Rakefile +2 -0
  4. data/lib/rails/angularstrap.rb +8 -0
  5. data/lib/rails/angularstrap/version.rb +5 -0
  6. data/vendor/assets/javascripts/angular-strap/LICENSE.md +21 -0
  7. data/vendor/assets/javascripts/angular-strap/README.md +112 -0
  8. data/vendor/assets/javascripts/angular-strap/angular-strap.nuspec +23 -0
  9. data/vendor/assets/javascripts/angular-strap/bower.json +53 -0
  10. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.js +5014 -0
  11. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.min.js +11 -0
  12. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.min.js.map +1 -0
  13. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.tpl.js +89 -0
  14. data/vendor/assets/javascripts/angular-strap/dist/angular-strap.tpl.min.js +8 -0
  15. data/vendor/assets/javascripts/angular-strap/dist/modules/affix.js +249 -0
  16. data/vendor/assets/javascripts/angular-strap/dist/modules/affix.min.js +9 -0
  17. data/vendor/assets/javascripts/angular-strap/dist/modules/affix.min.js.map +1 -0
  18. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.js +120 -0
  19. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.min.js +9 -0
  20. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.min.js.map +1 -0
  21. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.tpl.js +14 -0
  22. data/vendor/assets/javascripts/angular-strap/dist/modules/alert.tpl.min.js +8 -0
  23. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.js +96 -0
  24. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.min.js +9 -0
  25. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.min.js.map +1 -0
  26. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.tpl.js +14 -0
  27. data/vendor/assets/javascripts/angular-strap/dist/modules/aside.tpl.min.js +8 -0
  28. data/vendor/assets/javascripts/angular-strap/dist/modules/button.js +177 -0
  29. data/vendor/assets/javascripts/angular-strap/dist/modules/button.min.js +9 -0
  30. data/vendor/assets/javascripts/angular-strap/dist/modules/button.min.js.map +1 -0
  31. data/vendor/assets/javascripts/angular-strap/dist/modules/collapse.js +273 -0
  32. data/vendor/assets/javascripts/angular-strap/dist/modules/collapse.min.js +9 -0
  33. data/vendor/assets/javascripts/angular-strap/dist/modules/collapse.min.js.map +1 -0
  34. data/vendor/assets/javascripts/angular-strap/dist/modules/date-formatter.js +61 -0
  35. data/vendor/assets/javascripts/angular-strap/dist/modules/date-formatter.min.js +9 -0
  36. data/vendor/assets/javascripts/angular-strap/dist/modules/date-formatter.min.js.map +1 -0
  37. data/vendor/assets/javascripts/angular-strap/dist/modules/date-parser.js +273 -0
  38. data/vendor/assets/javascripts/angular-strap/dist/modules/date-parser.min.js +9 -0
  39. data/vendor/assets/javascripts/angular-strap/dist/modules/date-parser.min.js.map +1 -0
  40. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.js +640 -0
  41. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.min.js +9 -0
  42. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.min.js.map +1 -0
  43. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.tpl.js +14 -0
  44. data/vendor/assets/javascripts/angular-strap/dist/modules/datepicker.tpl.min.js +8 -0
  45. data/vendor/assets/javascripts/angular-strap/dist/modules/debounce.js +62 -0
  46. data/vendor/assets/javascripts/angular-strap/dist/modules/debounce.min.js +9 -0
  47. data/vendor/assets/javascripts/angular-strap/dist/modules/debounce.min.js.map +1 -0
  48. data/vendor/assets/javascripts/angular-strap/dist/modules/dimensions.js +156 -0
  49. data/vendor/assets/javascripts/angular-strap/dist/modules/dimensions.min.js +9 -0
  50. data/vendor/assets/javascripts/angular-strap/dist/modules/dimensions.min.js.map +1 -0
  51. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.js +149 -0
  52. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.min.js +9 -0
  53. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.min.js.map +1 -0
  54. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.tpl.js +14 -0
  55. data/vendor/assets/javascripts/angular-strap/dist/modules/dropdown.tpl.min.js +8 -0
  56. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.js +349 -0
  57. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.min.js +9 -0
  58. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.min.js.map +1 -0
  59. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.tpl.js +14 -0
  60. data/vendor/assets/javascripts/angular-strap/dist/modules/modal.tpl.min.js +8 -0
  61. data/vendor/assets/javascripts/angular-strap/dist/modules/navbar.js +72 -0
  62. data/vendor/assets/javascripts/angular-strap/dist/modules/navbar.min.js +9 -0
  63. data/vendor/assets/javascripts/angular-strap/dist/modules/navbar.min.js.map +1 -0
  64. data/vendor/assets/javascripts/angular-strap/dist/modules/parse-options.js +76 -0
  65. data/vendor/assets/javascripts/angular-strap/dist/modules/parse-options.min.js +9 -0
  66. data/vendor/assets/javascripts/angular-strap/dist/modules/parse-options.min.js.map +1 -0
  67. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.js +112 -0
  68. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.min.js +9 -0
  69. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.min.js.map +1 -0
  70. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.tpl.js +14 -0
  71. data/vendor/assets/javascripts/angular-strap/dist/modules/popover.tpl.min.js +8 -0
  72. data/vendor/assets/javascripts/angular-strap/dist/modules/raf.js +61 -0
  73. data/vendor/assets/javascripts/angular-strap/dist/modules/raf.min.js +9 -0
  74. data/vendor/assets/javascripts/angular-strap/dist/modules/raf.min.js.map +1 -0
  75. data/vendor/assets/javascripts/angular-strap/dist/modules/scrollspy.js +261 -0
  76. data/vendor/assets/javascripts/angular-strap/dist/modules/scrollspy.min.js +9 -0
  77. data/vendor/assets/javascripts/angular-strap/dist/modules/scrollspy.min.js.map +1 -0
  78. data/vendor/assets/javascripts/angular-strap/dist/modules/select.js +325 -0
  79. data/vendor/assets/javascripts/angular-strap/dist/modules/select.min.js +9 -0
  80. data/vendor/assets/javascripts/angular-strap/dist/modules/select.min.js.map +1 -0
  81. data/vendor/assets/javascripts/angular-strap/dist/modules/select.tpl.js +14 -0
  82. data/vendor/assets/javascripts/angular-strap/dist/modules/select.tpl.min.js +8 -0
  83. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.js +186 -0
  84. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.min.js +9 -0
  85. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.min.js.map +1 -0
  86. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.tpl.js +14 -0
  87. data/vendor/assets/javascripts/angular-strap/dist/modules/tab.tpl.min.js +8 -0
  88. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.js +485 -0
  89. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.min.js +9 -0
  90. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.min.js.map +1 -0
  91. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.tpl.js +14 -0
  92. data/vendor/assets/javascripts/angular-strap/dist/modules/timepicker.tpl.min.js +8 -0
  93. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.js +690 -0
  94. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.min.js +9 -0
  95. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.min.js.map +1 -0
  96. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.tpl.js +14 -0
  97. data/vendor/assets/javascripts/angular-strap/dist/modules/tooltip.tpl.min.js +8 -0
  98. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.js +266 -0
  99. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.min.js +9 -0
  100. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.min.js.map +1 -0
  101. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.tpl.js +14 -0
  102. data/vendor/assets/javascripts/angular-strap/dist/modules/typeahead.tpl.min.js +8 -0
  103. data/vendor/assets/javascripts/angular-strap/gulpfile.js +489 -0
  104. data/vendor/assets/javascripts/angular-strap/package.json +73 -0
  105. data/vendor/assets/javascripts/angular-strap/src/affix/affix.js +258 -0
  106. data/vendor/assets/javascripts/angular-strap/src/alert/alert.js +113 -0
  107. data/vendor/assets/javascripts/angular-strap/src/alert/alert.tpl.html +4 -0
  108. data/vendor/assets/javascripts/angular-strap/src/aside/aside.js +89 -0
  109. data/vendor/assets/javascripts/angular-strap/src/aside/aside.tpl.html +14 -0
  110. data/vendor/assets/javascripts/angular-strap/src/button/button.js +174 -0
  111. data/vendor/assets/javascripts/angular-strap/src/collapse/collapse.js +266 -0
  112. data/vendor/assets/javascripts/angular-strap/src/datepicker/datepicker.js +633 -0
  113. data/vendor/assets/javascripts/angular-strap/src/datepicker/datepicker.tpl.html +33 -0
  114. data/vendor/assets/javascripts/angular-strap/src/dropdown/dropdown.js +143 -0
  115. data/vendor/assets/javascripts/angular-strap/src/dropdown/dropdown.tpl.html +6 -0
  116. data/vendor/assets/javascripts/angular-strap/src/helpers/date-formatter.js +54 -0
  117. data/vendor/assets/javascripts/angular-strap/src/helpers/date-parser.js +266 -0
  118. data/vendor/assets/javascripts/angular-strap/src/helpers/debounce.js +55 -0
  119. data/vendor/assets/javascripts/angular-strap/src/helpers/dimensions.js +212 -0
  120. data/vendor/assets/javascripts/angular-strap/src/helpers/parse-options.js +69 -0
  121. data/vendor/assets/javascripts/angular-strap/src/helpers/raf.js +54 -0
  122. data/vendor/assets/javascripts/angular-strap/src/modal/modal.js +348 -0
  123. data/vendor/assets/javascripts/angular-strap/src/modal/modal.tpl.html +14 -0
  124. data/vendor/assets/javascripts/angular-strap/src/module.js +19 -0
  125. data/vendor/assets/javascripts/angular-strap/src/navbar/navbar.js +65 -0
  126. data/vendor/assets/javascripts/angular-strap/src/popover/popover.js +111 -0
  127. data/vendor/assets/javascripts/angular-strap/src/popover/popover.tpl.html +5 -0
  128. data/vendor/assets/javascripts/angular-strap/src/scrollspy/scrollspy.js +254 -0
  129. data/vendor/assets/javascripts/angular-strap/src/select/select.js +321 -0
  130. data/vendor/assets/javascripts/angular-strap/src/select/select.tpl.html +14 -0
  131. data/vendor/assets/javascripts/angular-strap/src/tab/tab.js +183 -0
  132. data/vendor/assets/javascripts/angular-strap/src/tab/tab.tpl.html +7 -0
  133. data/vendor/assets/javascripts/angular-strap/src/timepicker/timepicker.js +493 -0
  134. data/vendor/assets/javascripts/angular-strap/src/timepicker/timepicker.tpl.html +62 -0
  135. data/vendor/assets/javascripts/angular-strap/src/tooltip/tooltip.js +806 -0
  136. data/vendor/assets/javascripts/angular-strap/src/tooltip/tooltip.tpl.html +4 -0
  137. data/vendor/assets/javascripts/angular-strap/src/typeahead/typeahead.js +262 -0
  138. data/vendor/assets/javascripts/angular-strap/src/typeahead/typeahead.tpl.html +5 -0
  139. data/vendor/assets/javascripts/angular/README.md +64 -0
  140. data/vendor/assets/javascripts/angular/angular-csp.css +13 -0
  141. data/vendor/assets/javascripts/angular/angular.js +26181 -0
  142. data/vendor/assets/javascripts/angular/angular.min.js +250 -0
  143. data/vendor/assets/javascripts/angular/angular.min.js.gzip +0 -0
  144. data/vendor/assets/javascripts/angular/angular.min.js.map +8 -0
  145. data/vendor/assets/javascripts/angular/bower.json +8 -0
  146. data/vendor/assets/javascripts/angular/index.js +2 -0
  147. data/vendor/assets/javascripts/angular/package.json +25 -0
  148. metadata +237 -0
@@ -0,0 +1,62 @@
1
+ <div class="dropdown-menu timepicker" style="min-width: 0px;width: auto;">
2
+ <table height="100%">
3
+ <thead>
4
+ <tr class="text-center">
5
+ <th>
6
+ <button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 0)">
7
+ <i class="{{ $iconUp }}"></i>
8
+ </button>
9
+ </th>
10
+ <th>
11
+ &nbsp;
12
+ </th>
13
+ <th>
14
+ <button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 1)">
15
+ <i class="{{ $iconUp }}"></i>
16
+ </button>
17
+ </th>
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ <tr ng-repeat="(i, row) in rows">
22
+ <td class="text-center">
23
+ <button tabindex="-1" style="width: 100%" type="button" class="btn btn-default" ng-class="{'btn-primary': row[0].selected}" ng-click="$select(row[0].date, 0)" ng-disabled="row[0].disabled">
24
+ <span ng-class="{'text-muted': row[0].muted}" ng-bind="row[0].label"></span>
25
+ </button>
26
+ </td>
27
+ <td>
28
+ <span ng-bind="i == midIndex ? timeSeparator : ' '"></span>
29
+ </td>
30
+ <td class="text-center">
31
+ <button tabindex="-1" ng-if="row[1].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{'btn-primary': row[1].selected}" ng-click="$select(row[1].date, 1)" ng-disabled="row[1].disabled">
32
+ <span ng-class="{'text-muted': row[1].muted}" ng-bind="row[1].label"></span>
33
+ </button>
34
+ </td>
35
+ <td ng-if="showAM">
36
+ &nbsp;
37
+ </td>
38
+ <td ng-if="showAM">
39
+ <button tabindex="-1" ng-show="i == midIndex - !isAM * 1" style="width: 100%" type="button" ng-class="{'btn-primary': !!isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">AM</button>
40
+ <button tabindex="-1" ng-show="i == midIndex + 1 - !isAM * 1" style="width: 100%" type="button" ng-class="{'btn-primary': !isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">PM</button>
41
+ </td>
42
+ </tr>
43
+ </tbody>
44
+ <tfoot>
45
+ <tr class="text-center">
46
+ <th>
47
+ <button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 0)">
48
+ <i class="{{ $iconDown }}"></i>
49
+ </button>
50
+ </th>
51
+ <th>
52
+ &nbsp;
53
+ </th>
54
+ <th>
55
+ <button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 1)">
56
+ <i class="{{ $iconDown }}"></i>
57
+ </button>
58
+ </th>
59
+ </tr>
60
+ </tfoot>
61
+ </table>
62
+ </div>
@@ -0,0 +1,806 @@
1
+ 'use strict';
2
+
3
+ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])
4
+
5
+ .provider('$tooltip', function() {
6
+
7
+ var defaults = this.defaults = {
8
+ animation: 'am-fade',
9
+ customClass: '',
10
+ prefixClass: 'tooltip',
11
+ prefixEvent: 'tooltip',
12
+ container: false,
13
+ target: false,
14
+ placement: 'top',
15
+ template: 'tooltip/tooltip.tpl.html',
16
+ contentTemplate: false,
17
+ trigger: 'hover focus',
18
+ keyboard: false,
19
+ html: false,
20
+ show: false,
21
+ title: '',
22
+ type: '',
23
+ delay: 0,
24
+ autoClose: false,
25
+ bsEnabled: true,
26
+ viewport: {
27
+ selector: 'body',
28
+ padding: 0
29
+ }
30
+ };
31
+
32
+ this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {
33
+
34
+ var trim = String.prototype.trim;
35
+ var isTouch = 'createTouch' in $window.document;
36
+ var htmlReplaceRegExp = /ng-bind="/ig;
37
+ var $body = angular.element($window.document);
38
+
39
+ function TooltipFactory(element, config) {
40
+
41
+ var $tooltip = {};
42
+
43
+ // Common vars
44
+ var nodeName = element[0].nodeName.toLowerCase();
45
+ var options = $tooltip.$options = angular.extend({}, defaults, config);
46
+ $tooltip.$promise = fetchTemplate(options.template);
47
+ var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
48
+ if(options.delay && angular.isString(options.delay)) {
49
+ var split = options.delay.split(',').map(parseFloat);
50
+ options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];
51
+ }
52
+
53
+ // store $id to identify the triggering element in events
54
+ // give priority to options.id, otherwise, try to use
55
+ // element id if defined
56
+ $tooltip.$id = options.id || element.attr('id') || '';
57
+
58
+ // Support scope as string options
59
+ if(options.title) {
60
+ scope.title = $sce.trustAsHtml(options.title);
61
+ }
62
+
63
+ // Provide scope helpers
64
+ scope.$setEnabled = function(isEnabled) {
65
+ scope.$$postDigest(function() {
66
+ $tooltip.setEnabled(isEnabled);
67
+ });
68
+ };
69
+ scope.$hide = function() {
70
+ scope.$$postDigest(function() {
71
+ $tooltip.hide();
72
+ });
73
+ };
74
+ scope.$show = function() {
75
+ scope.$$postDigest(function() {
76
+ $tooltip.show();
77
+ });
78
+ };
79
+ scope.$toggle = function() {
80
+ scope.$$postDigest(function() {
81
+ $tooltip.toggle();
82
+ });
83
+ };
84
+ // Publish isShown as a protected var on scope
85
+ $tooltip.$isShown = scope.$isShown = false;
86
+
87
+ // Private vars
88
+ var timeout, hoverState;
89
+
90
+ // Support contentTemplate option
91
+ if(options.contentTemplate) {
92
+ $tooltip.$promise = $tooltip.$promise.then(function(template) {
93
+ var templateEl = angular.element(template);
94
+ return fetchTemplate(options.contentTemplate)
95
+ .then(function(contentTemplate) {
96
+ var contentEl = findElement('[ng-bind="content"]', templateEl[0]);
97
+ if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]);
98
+ contentEl.removeAttr('ng-bind').html(contentTemplate);
99
+ return templateEl[0].outerHTML;
100
+ });
101
+ });
102
+ }
103
+
104
+ // Fetch, compile then initialize tooltip
105
+ var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;
106
+ $tooltip.$promise.then(function(template) {
107
+ if(angular.isObject(template)) template = template.data;
108
+ if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
109
+ template = trim.apply(template);
110
+ tipTemplate = template;
111
+ tipLinker = $compile(template);
112
+ $tooltip.init();
113
+ });
114
+
115
+ $tooltip.init = function() {
116
+
117
+ // Options: delay
118
+ if (options.delay && angular.isNumber(options.delay)) {
119
+ options.delay = {
120
+ show: options.delay,
121
+ hide: options.delay
122
+ };
123
+ }
124
+
125
+ // Replace trigger on touch devices ?
126
+ // if(isTouch && options.trigger === defaults.trigger) {
127
+ // options.trigger.replace(/hover/g, 'click');
128
+ // }
129
+
130
+ // Options : container
131
+ if(options.container === 'self') {
132
+ tipContainer = element;
133
+ } else if(angular.isElement(options.container)) {
134
+ tipContainer = options.container;
135
+ } else if(options.container) {
136
+ tipContainer = findElement(options.container);
137
+ }
138
+
139
+ // Options: trigger
140
+ bindTriggerEvents();
141
+
142
+ // Options: target
143
+ if(options.target) {
144
+ options.target = angular.isElement(options.target) ? options.target : findElement(options.target);
145
+ }
146
+
147
+ // Options: show
148
+ if(options.show) {
149
+ scope.$$postDigest(function() {
150
+ options.trigger === 'focus' ? element[0].focus() : $tooltip.show();
151
+ });
152
+ }
153
+
154
+ };
155
+
156
+ $tooltip.destroy = function() {
157
+
158
+ // Unbind events
159
+ unbindTriggerEvents();
160
+
161
+ // Remove element
162
+ destroyTipElement();
163
+
164
+ // Destroy scope
165
+ scope.$destroy();
166
+
167
+ };
168
+
169
+ $tooltip.enter = function() {
170
+
171
+ clearTimeout(timeout);
172
+ hoverState = 'in';
173
+ if (!options.delay || !options.delay.show) {
174
+ return $tooltip.show();
175
+ }
176
+
177
+ timeout = setTimeout(function() {
178
+ if (hoverState ==='in') $tooltip.show();
179
+ }, options.delay.show);
180
+
181
+ };
182
+
183
+ $tooltip.show = function() {
184
+ if (!options.bsEnabled || $tooltip.$isShown) return;
185
+
186
+ scope.$emit(options.prefixEvent + '.show.before', $tooltip);
187
+ var parent, after;
188
+ if (options.container) {
189
+ parent = tipContainer;
190
+ if (tipContainer[0].lastChild) {
191
+ after = angular.element(tipContainer[0].lastChild);
192
+ } else {
193
+ after = null;
194
+ }
195
+ } else {
196
+ parent = null;
197
+ after = element;
198
+ }
199
+
200
+
201
+ // Hide any existing tipElement
202
+ if(tipElement) destroyTipElement();
203
+ // Fetch a cloned element linked from template
204
+ tipScope = $tooltip.$scope.$new();
205
+ tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});
206
+
207
+ // Set the initial positioning. Make the tooltip invisible
208
+ // so IE doesn't try to focus on it off screen.
209
+ tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});
210
+
211
+ // Options: animation
212
+ if(options.animation) tipElement.addClass(options.animation);
213
+ // Options: type
214
+ if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);
215
+ // Options: custom classes
216
+ if(options.customClass) tipElement.addClass(options.customClass);
217
+
218
+ // Append the element, without any animations. If we append
219
+ // using $animate.enter, some of the animations cause the placement
220
+ // to be off due to the transforms.
221
+ after ? after.after(tipElement) : parent.prepend(tipElement);
222
+
223
+ $tooltip.$isShown = scope.$isShown = true;
224
+ safeDigest(scope);
225
+
226
+ // Now, apply placement
227
+ $tooltip.$applyPlacement();
228
+
229
+ // Once placed, animate it.
230
+ // Support v1.3+ $animate
231
+ // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
232
+ var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);
233
+ if(promise && promise.then) promise.then(enterAnimateCallback);
234
+ safeDigest(scope);
235
+
236
+ $$rAF(function () {
237
+ // Once the tooltip is placed and the animation starts, make the tooltip visible
238
+ if(tipElement) tipElement.css({visibility: 'visible'});
239
+ });
240
+
241
+ // Bind events
242
+ if(options.keyboard) {
243
+ if(options.trigger !== 'focus') {
244
+ $tooltip.focus();
245
+ }
246
+ bindKeyboardEvents();
247
+ }
248
+
249
+ if(options.autoClose) {
250
+ bindAutoCloseEvents();
251
+ }
252
+
253
+ };
254
+
255
+ function enterAnimateCallback() {
256
+ scope.$emit(options.prefixEvent + '.show', $tooltip);
257
+ }
258
+
259
+ $tooltip.leave = function() {
260
+
261
+ clearTimeout(timeout);
262
+ hoverState = 'out';
263
+ if (!options.delay || !options.delay.hide) {
264
+ return $tooltip.hide();
265
+ }
266
+ timeout = setTimeout(function () {
267
+ if (hoverState === 'out') {
268
+ $tooltip.hide();
269
+ }
270
+ }, options.delay.hide);
271
+
272
+ };
273
+
274
+ var _blur;
275
+ var _tipToHide;
276
+ $tooltip.hide = function(blur) {
277
+
278
+ if(!$tooltip.$isShown) return;
279
+ scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
280
+
281
+ // store blur value for leaveAnimateCallback to use
282
+ _blur = blur;
283
+
284
+ // store current tipElement reference to use
285
+ // in leaveAnimateCallback
286
+ _tipToHide = tipElement;
287
+
288
+ // Support v1.3+ $animate
289
+ // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
290
+ var promise = $animate.leave(tipElement, leaveAnimateCallback);
291
+ if(promise && promise.then) promise.then(leaveAnimateCallback);
292
+
293
+ $tooltip.$isShown = scope.$isShown = false;
294
+ safeDigest(scope);
295
+
296
+ // Unbind events
297
+ if(options.keyboard && tipElement !== null) {
298
+ unbindKeyboardEvents();
299
+ }
300
+
301
+ if(options.autoClose && tipElement !== null) {
302
+ unbindAutoCloseEvents();
303
+ }
304
+ };
305
+
306
+ function leaveAnimateCallback() {
307
+ scope.$emit(options.prefixEvent + '.hide', $tooltip);
308
+
309
+ // check if current tipElement still references
310
+ // the same element when hide was called
311
+ if (tipElement === _tipToHide) {
312
+ // Allow to blur the input when hidden, like when pressing enter key
313
+ if(_blur && options.trigger === 'focus') {
314
+ return element[0].blur();
315
+ }
316
+
317
+ // clean up child scopes
318
+ destroyTipElement();
319
+ }
320
+ }
321
+
322
+ $tooltip.toggle = function() {
323
+ $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();
324
+ };
325
+
326
+ $tooltip.focus = function() {
327
+ tipElement[0].focus();
328
+ };
329
+
330
+ $tooltip.setEnabled = function(isEnabled) {
331
+ options.bsEnabled = isEnabled;
332
+ };
333
+
334
+ $tooltip.setViewport = function(viewport) {
335
+ options.viewport = viewport;
336
+ };
337
+
338
+ // Protected methods
339
+
340
+ $tooltip.$applyPlacement = function() {
341
+ if(!tipElement) return;
342
+
343
+ // Determine if we're doing an auto or normal placement
344
+ var placement = options.placement,
345
+ autoToken = /\s?auto?\s?/i,
346
+ autoPlace = autoToken.test(placement);
347
+
348
+ if (autoPlace) {
349
+ placement = placement.replace(autoToken, '') || defaults.placement;
350
+ }
351
+
352
+ // Need to add the position class before we get
353
+ // the offsets
354
+ tipElement.addClass(options.placement);
355
+
356
+ // Get the position of the target element
357
+ // and the height and width of the tooltip so we can center it.
358
+ var elementPosition = getPosition(),
359
+ tipWidth = tipElement.prop('offsetWidth'),
360
+ tipHeight = tipElement.prop('offsetHeight');
361
+
362
+ // If we're auto placing, we need to check the positioning
363
+ if (autoPlace) {
364
+ var originalPlacement = placement;
365
+ var container = options.container ? findElement(options.container) : element.parent();
366
+ var containerPosition = getPosition(container);
367
+
368
+ // Determine if the vertical placement
369
+ if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {
370
+ placement = originalPlacement.replace('bottom', 'top');
371
+ } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {
372
+ placement = originalPlacement.replace('top', 'bottom');
373
+ }
374
+
375
+ // Determine the horizontal placement
376
+ // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right
377
+ // and flow in the opposite direction of their placement.
378
+ if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&
379
+ elementPosition.right + tipWidth > containerPosition.width) {
380
+
381
+ placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');
382
+ } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&
383
+ elementPosition.left - tipWidth < containerPosition.left) {
384
+
385
+ placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');
386
+ }
387
+
388
+ tipElement.removeClass(originalPlacement).addClass(placement);
389
+ }
390
+
391
+ // Get the tooltip's top and left coordinates to center it with this directive.
392
+ var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);
393
+ applyPlacement(tipPosition, placement);
394
+ };
395
+
396
+ $tooltip.$onKeyUp = function(evt) {
397
+ if (evt.which === 27 && $tooltip.$isShown) {
398
+ $tooltip.hide();
399
+ evt.stopPropagation();
400
+ }
401
+ };
402
+
403
+ $tooltip.$onFocusKeyUp = function(evt) {
404
+ if (evt.which === 27) {
405
+ element[0].blur();
406
+ evt.stopPropagation();
407
+ }
408
+ };
409
+
410
+ $tooltip.$onFocusElementMouseDown = function(evt) {
411
+ evt.preventDefault();
412
+ evt.stopPropagation();
413
+ // Some browsers do not auto-focus buttons (eg. Safari)
414
+ $tooltip.$isShown ? element[0].blur() : element[0].focus();
415
+ };
416
+
417
+ // bind/unbind events
418
+ function bindTriggerEvents() {
419
+ var triggers = options.trigger.split(' ');
420
+ angular.forEach(triggers, function(trigger) {
421
+ if(trigger === 'click') {
422
+ element.on('click', $tooltip.toggle);
423
+ } else if(trigger !== 'manual') {
424
+ element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
425
+ element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
426
+ nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
427
+ }
428
+ });
429
+ }
430
+
431
+ function unbindTriggerEvents() {
432
+ var triggers = options.trigger.split(' ');
433
+ for (var i = triggers.length; i--;) {
434
+ var trigger = triggers[i];
435
+ if(trigger === 'click') {
436
+ element.off('click', $tooltip.toggle);
437
+ } else if(trigger !== 'manual') {
438
+ element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
439
+ element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
440
+ nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
441
+ }
442
+ }
443
+ }
444
+
445
+ function bindKeyboardEvents() {
446
+ if(options.trigger !== 'focus') {
447
+ tipElement.on('keyup', $tooltip.$onKeyUp);
448
+ } else {
449
+ element.on('keyup', $tooltip.$onFocusKeyUp);
450
+ }
451
+ }
452
+
453
+ function unbindKeyboardEvents() {
454
+ if(options.trigger !== 'focus') {
455
+ tipElement.off('keyup', $tooltip.$onKeyUp);
456
+ } else {
457
+ element.off('keyup', $tooltip.$onFocusKeyUp);
458
+ }
459
+ }
460
+
461
+ var _autoCloseEventsBinded = false;
462
+ function bindAutoCloseEvents() {
463
+ // use timeout to hookup the events to prevent
464
+ // event bubbling from being processed imediately.
465
+ $timeout(function() {
466
+ // Stop propagation when clicking inside tooltip
467
+ tipElement.on('click', stopEventPropagation);
468
+
469
+ // Hide when clicking outside tooltip
470
+ $body.on('click', $tooltip.hide);
471
+
472
+ _autoCloseEventsBinded = true;
473
+ }, 0, false);
474
+ }
475
+
476
+ function unbindAutoCloseEvents() {
477
+ if (_autoCloseEventsBinded) {
478
+ tipElement.off('click', stopEventPropagation);
479
+ $body.off('click', $tooltip.hide);
480
+ _autoCloseEventsBinded = false;
481
+ }
482
+ }
483
+
484
+ function stopEventPropagation(event) {
485
+ event.stopPropagation();
486
+ }
487
+
488
+ // Private methods
489
+
490
+ function getPosition($element) {
491
+ $element = $element || (options.target || element);
492
+
493
+ var el = $element[0],
494
+ isBody = el.tagName === 'BODY';
495
+
496
+ var elRect = el.getBoundingClientRect();
497
+ var rect = {};
498
+
499
+ // IE8 has issues with angular.extend and using elRect directly.
500
+ // By coping the values of elRect into a new object, we can continue to use extend
501
+ for (var p in elRect) {
502
+ if (elRect.hasOwnProperty(p)) {
503
+ rect[p] = elRect[p];
504
+ }
505
+ }
506
+
507
+ if (rect.width === null) {
508
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
509
+ rect = angular.extend({}, rect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });
510
+ }
511
+ var elOffset = isBody ? { top: 0, left: 0 } : dimensions.offset(el),
512
+ scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.prop('scrollTop') || 0 },
513
+ outerDims = isBody ? { width: document.documentElement.clientWidth, height: $window.innerHeight } : null;
514
+
515
+ return angular.extend({}, rect, scroll, outerDims, elOffset);
516
+ }
517
+
518
+ function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
519
+ var offset;
520
+ var split = placement.split('-');
521
+
522
+ switch (split[0]) {
523
+ case 'right':
524
+ offset = {
525
+ top: position.top + position.height / 2 - actualHeight / 2,
526
+ left: position.left + position.width
527
+ };
528
+ break;
529
+ case 'bottom':
530
+ offset = {
531
+ top: position.top + position.height,
532
+ left: position.left + position.width / 2 - actualWidth / 2
533
+ };
534
+ break;
535
+ case 'left':
536
+ offset = {
537
+ top: position.top + position.height / 2 - actualHeight / 2,
538
+ left: position.left - actualWidth
539
+ };
540
+ break;
541
+ default:
542
+ offset = {
543
+ top: position.top - actualHeight,
544
+ left: position.left + position.width / 2 - actualWidth / 2
545
+ };
546
+ break;
547
+ }
548
+
549
+ if(!split[1]) {
550
+ return offset;
551
+ }
552
+
553
+ // Add support for corners @todo css
554
+ if(split[0] === 'top' || split[0] === 'bottom') {
555
+ switch (split[1]) {
556
+ case 'left':
557
+ offset.left = position.left;
558
+ break;
559
+ case 'right':
560
+ offset.left = position.left + position.width - actualWidth;
561
+ }
562
+ } else if(split[0] === 'left' || split[0] === 'right') {
563
+ switch (split[1]) {
564
+ case 'top':
565
+ offset.top = position.top - actualHeight;
566
+ break;
567
+ case 'bottom':
568
+ offset.top = position.top + position.height;
569
+ }
570
+ }
571
+
572
+ return offset;
573
+ }
574
+
575
+ function applyPlacement(offset, placement) {
576
+ var tip = tipElement[0],
577
+ width = tip.offsetWidth,
578
+ height = tip.offsetHeight;
579
+
580
+ // manually read margins because getBoundingClientRect includes difference
581
+ var marginTop = parseInt(dimensions.css(tip, 'margin-top'), 10),
582
+ marginLeft = parseInt(dimensions.css(tip, 'margin-left'), 10);
583
+
584
+ // we must check for NaN for ie 8/9
585
+ if (isNaN(marginTop)) marginTop = 0;
586
+ if (isNaN(marginLeft)) marginLeft = 0;
587
+
588
+ offset.top = offset.top + marginTop;
589
+ offset.left = offset.left + marginLeft;
590
+
591
+ // dimensions setOffset doesn't round pixel values
592
+ // so we use setOffset directly with our own function
593
+ dimensions.setOffset(tip, angular.extend({
594
+ using: function (props) {
595
+ tipElement.css({
596
+ top: Math.round(props.top) + 'px',
597
+ left: Math.round(props.left) + 'px'
598
+ });
599
+ }
600
+ }, offset), 0);
601
+
602
+ // check to see if placing tip in new offset caused the tip to resize itself
603
+ var actualWidth = tip.offsetWidth,
604
+ actualHeight = tip.offsetHeight;
605
+
606
+ if (placement === 'top' && actualHeight !== height) {
607
+ offset.top = offset.top + height - actualHeight;
608
+ }
609
+
610
+ // If it's an exotic placement, exit now instead of
611
+ // applying a delta and changing the arrow
612
+ if (/top-left|top-right|bottom-left|bottom-right/.test(placement)) return;
613
+
614
+ var delta = getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);
615
+
616
+ if (delta.left) {
617
+ offset.left += delta.left;
618
+ } else {
619
+ offset.top += delta.top;
620
+ }
621
+
622
+ dimensions.setOffset(tip, offset);
623
+
624
+ if (/top|right|bottom|left/.test(placement)) {
625
+ var isVertical = /top|bottom/.test(placement),
626
+ arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight,
627
+ arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight';
628
+
629
+ replaceArrow(arrowDelta, tip[arrowOffsetPosition], isVertical);
630
+ }
631
+ }
632
+
633
+ function getViewportAdjustedDelta(placement, position, actualWidth, actualHeight) {
634
+ var delta = { top: 0, left: 0 },
635
+ $viewport = options.viewport && findElement(options.viewport.selector || options.viewport);
636
+
637
+ if (!$viewport) {
638
+ return delta;
639
+ }
640
+
641
+ var viewportPadding = options.viewport && options.viewport.padding || 0,
642
+ viewportDimensions = getPosition($viewport);
643
+
644
+ if (/right|left/.test(placement)) {
645
+ var topEdgeOffset = position.top - viewportPadding - viewportDimensions.scroll,
646
+ bottomEdgeOffset = position.top + viewportPadding - viewportDimensions.scroll + actualHeight;
647
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
648
+ delta.top = viewportDimensions.top - topEdgeOffset;
649
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
650
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;
651
+ }
652
+ } else {
653
+ var leftEdgeOffset = position.left - viewportPadding,
654
+ rightEdgeOffset = position.left + viewportPadding + actualWidth;
655
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
656
+ delta.left = viewportDimensions.left - leftEdgeOffset;
657
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
658
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;
659
+ }
660
+ }
661
+
662
+ return delta;
663
+ }
664
+
665
+ function replaceArrow(delta, dimension, isHorizontal) {
666
+ var $arrow = findElement('.tooltip-arrow, .arrow', tipElement[0]);
667
+
668
+ $arrow.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
669
+ .css(isHorizontal ? 'top' : 'left', '');
670
+ }
671
+
672
+ function destroyTipElement() {
673
+ // Cancel pending callbacks
674
+ clearTimeout(timeout);
675
+
676
+ if($tooltip.$isShown && tipElement !== null) {
677
+ if(options.autoClose) {
678
+ unbindAutoCloseEvents();
679
+ }
680
+
681
+ if(options.keyboard) {
682
+ unbindKeyboardEvents();
683
+ }
684
+ }
685
+
686
+ if(tipScope) {
687
+ tipScope.$destroy();
688
+ tipScope = null;
689
+ }
690
+
691
+ if(tipElement) {
692
+ tipElement.remove();
693
+ tipElement = $tooltip.$element = null;
694
+ }
695
+ }
696
+
697
+ return $tooltip;
698
+
699
+ }
700
+
701
+ // Helper functions
702
+
703
+ function safeDigest(scope) {
704
+ scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
705
+ }
706
+
707
+ function findElement(query, element) {
708
+ return angular.element((element || document).querySelectorAll(query));
709
+ }
710
+
711
+ var fetchPromises = {};
712
+ function fetchTemplate(template) {
713
+ if(fetchPromises[template]) return fetchPromises[template];
714
+ return (fetchPromises[template] = $http.get(template, {cache: $templateCache}).then(function(res) {
715
+ return res.data;
716
+ }));
717
+ }
718
+
719
+ return TooltipFactory;
720
+
721
+ };
722
+
723
+ })
724
+
725
+ .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {
726
+
727
+ return {
728
+ restrict: 'EAC',
729
+ scope: true,
730
+ link: function postLink(scope, element, attr, transclusion) {
731
+
732
+ // Directive options
733
+ var options = {scope: scope};
734
+ angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {
735
+ if(angular.isDefined(attr[key])) options[key] = attr[key];
736
+ });
737
+
738
+ // should not parse target attribute, only data-target
739
+ if(element.attr('data-target')) {
740
+ options.target = element.attr('data-target');
741
+ }
742
+
743
+ // overwrite inherited title value when no value specified
744
+ // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11
745
+ if (!scope.hasOwnProperty('title')){
746
+ scope.title = '';
747
+ }
748
+
749
+ // Observe scope attributes for change
750
+ attr.$observe('title', function(newValue) {
751
+ if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {
752
+ var oldValue = scope.title;
753
+ scope.title = $sce.trustAsHtml(newValue);
754
+ angular.isDefined(oldValue) && $$rAF(function() {
755
+ tooltip && tooltip.$applyPlacement();
756
+ });
757
+ }
758
+ });
759
+
760
+ // Support scope as an object
761
+ attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {
762
+ if(angular.isObject(newValue)) {
763
+ angular.extend(scope, newValue);
764
+ } else {
765
+ scope.title = newValue;
766
+ }
767
+ angular.isDefined(oldValue) && $$rAF(function() {
768
+ tooltip && tooltip.$applyPlacement();
769
+ });
770
+ }, true);
771
+
772
+ // Visibility binding support
773
+ attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {
774
+ if(!tooltip || !angular.isDefined(newValue)) return;
775
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);
776
+ newValue === true ? tooltip.show() : tooltip.hide();
777
+ });
778
+
779
+ // Enabled binding support
780
+ attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {
781
+ // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);
782
+ if(!tooltip || !angular.isDefined(newValue)) return;
783
+ if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);
784
+ newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);
785
+ });
786
+
787
+ // Viewport support
788
+ attr.viewport && scope.$watch(attr.viewport, function (newValue) {
789
+ if(!tooltip || !angular.isDefined(newValue)) return;
790
+ tooltip.setViewport(newValue);
791
+ });
792
+
793
+ // Initialize popover
794
+ var tooltip = $tooltip(element, options);
795
+
796
+ // Garbage collection
797
+ scope.$on('$destroy', function() {
798
+ if(tooltip) tooltip.destroy();
799
+ options = null;
800
+ tooltip = null;
801
+ });
802
+
803
+ }
804
+ };
805
+
806
+ });