angular-strap-rails 2.0.1
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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +1 -0
- data/angular-strap-rails.gemspec +15 -0
- data/lib/angular-strap-rails.rb +8 -0
- data/lib/angular-strap-rails/version.rb +5 -0
- data/vendor/.DS_Store +0 -0
- data/vendor/assets/.DS_Store +0 -0
- data/vendor/assets/javascripts/.DS_Store +0 -0
- data/vendor/assets/javascripts/angular-strap.coffee +0 -0
- data/vendor/assets/javascripts/angular-strap/.DS_Store +0 -0
- data/vendor/assets/javascripts/angular-strap/datepicker.coffee +11 -0
- data/vendor/assets/javascripts/angular-strap/modal.coffee +9 -0
- data/vendor/assets/javascripts/dist/angular-strap.js +3682 -0
- data/vendor/assets/javascripts/dist/angular-strap.tpl.js +100 -0
- data/vendor/assets/javascripts/dist/modules/affix.js +191 -0
- data/vendor/assets/javascripts/dist/modules/alert.js +114 -0
- data/vendor/assets/javascripts/dist/modules/alert.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/aside.js +96 -0
- data/vendor/assets/javascripts/dist/modules/aside.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/button.js +141 -0
- data/vendor/assets/javascripts/dist/modules/date-parser.js +150 -0
- data/vendor/assets/javascripts/dist/modules/datepicker.js +583 -0
- data/vendor/assets/javascripts/dist/modules/datepicker.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/debounce.js +60 -0
- data/vendor/assets/javascripts/dist/modules/dimensions.js +142 -0
- data/vendor/assets/javascripts/dist/modules/dropdown.js +124 -0
- data/vendor/assets/javascripts/dist/modules/dropdown.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/modal.js +282 -0
- data/vendor/assets/javascripts/dist/modules/modal.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/navbar.js +55 -0
- data/vendor/assets/javascripts/dist/modules/parse-options.js +51 -0
- data/vendor/assets/javascripts/dist/modules/popover.js +100 -0
- data/vendor/assets/javascripts/dist/modules/popover.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/raf.js +45 -0
- data/vendor/assets/javascripts/dist/modules/scrollspy.js +229 -0
- data/vendor/assets/javascripts/dist/modules/select.js +281 -0
- data/vendor/assets/javascripts/dist/modules/select.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/tab.js +69 -0
- data/vendor/assets/javascripts/dist/modules/tab.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/timepicker.js +430 -0
- data/vendor/assets/javascripts/dist/modules/timepicker.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/tooltip.js +405 -0
- data/vendor/assets/javascripts/dist/modules/tooltip.tpl.js +14 -0
- data/vendor/assets/javascripts/dist/modules/typeahead.js +225 -0
- data/vendor/assets/javascripts/dist/modules/typeahead.tpl.js +14 -0
- data/vendor/assets/stylesheets/angular-strap.css +564 -0
- metadata +94 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.0.1 - 2014-04-10
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
angular.module('mgcrea.ngStrap.timepicker').run([
|
|
10
|
+
'$templateCache',
|
|
11
|
+
function ($templateCache) {
|
|
12
|
+
$templateCache.put('timepicker/timepicker.tpl.html', '<div class="dropdown-menu timepicker" style="min-width: 0px;width: auto"><table height="100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$moveIndex(-1, 0)"><i class="glyphicon glyphicon-chevron-up"></i></button></th><th> </th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$moveIndex(-1, 1)"><i class="glyphicon glyphicon-chevron-up"></i></button></th></tr></thead><tbody><tr ng-repeat="(i, row) in rows"><td class="text-center"><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"><span ng-class="{\'text-muted\': row[0].muted}" ng-bind="row[0].label"></span></button></td><td><span ng-bind="i == midIndex ? \':\' : \' \'"></span></td><td class="text-center"><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"><span ng-class="{\'text-muted\': row[1].muted}" ng-bind="row[1].label"></span></button></td><td ng-if="showAM"> </td><td ng-if="showAM"><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> <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></td></tr></tbody><tfoot><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$moveIndex(1, 0)"><i class="glyphicon glyphicon-chevron-down"></i></button></th><th> </th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$moveIndex(1, 1)"><i class="glyphicon glyphicon-chevron-down"></i></button></th></tr></tfoot></table></div>');
|
|
13
|
+
}
|
|
14
|
+
]);
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.0.1 - 2014-04-10
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']).provider('$tooltip', function () {
|
|
10
|
+
var defaults = this.defaults = {
|
|
11
|
+
animation: 'am-fade',
|
|
12
|
+
prefixClass: 'tooltip',
|
|
13
|
+
prefixEvent: 'tooltip',
|
|
14
|
+
container: false,
|
|
15
|
+
placement: 'top',
|
|
16
|
+
template: 'tooltip/tooltip.tpl.html',
|
|
17
|
+
contentTemplate: false,
|
|
18
|
+
trigger: 'hover focus',
|
|
19
|
+
keyboard: false,
|
|
20
|
+
html: false,
|
|
21
|
+
show: false,
|
|
22
|
+
title: '',
|
|
23
|
+
type: '',
|
|
24
|
+
delay: 0
|
|
25
|
+
};
|
|
26
|
+
this.$get = [
|
|
27
|
+
'$window',
|
|
28
|
+
'$rootScope',
|
|
29
|
+
'$compile',
|
|
30
|
+
'$q',
|
|
31
|
+
'$templateCache',
|
|
32
|
+
'$http',
|
|
33
|
+
'$animate',
|
|
34
|
+
'$timeout',
|
|
35
|
+
'dimensions',
|
|
36
|
+
'$$rAF',
|
|
37
|
+
function ($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, dimensions, $$rAF) {
|
|
38
|
+
var trim = String.prototype.trim;
|
|
39
|
+
var isTouch = 'createTouch' in $window.document;
|
|
40
|
+
var htmlReplaceRegExp = /ng-bind="/gi;
|
|
41
|
+
function TooltipFactory(element, config) {
|
|
42
|
+
var $tooltip = {};
|
|
43
|
+
// Common vars
|
|
44
|
+
var options = $tooltip.$options = angular.extend({}, defaults, config);
|
|
45
|
+
$tooltip.$promise = fetchTemplate(options.template);
|
|
46
|
+
var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();
|
|
47
|
+
if (options.delay && angular.isString(options.delay)) {
|
|
48
|
+
options.delay = parseFloat(options.delay);
|
|
49
|
+
}
|
|
50
|
+
// Support scope as string options
|
|
51
|
+
if (options.title) {
|
|
52
|
+
$tooltip.$scope.title = options.title;
|
|
53
|
+
}
|
|
54
|
+
// Provide scope helpers
|
|
55
|
+
scope.$hide = function () {
|
|
56
|
+
scope.$$postDigest(function () {
|
|
57
|
+
$tooltip.hide();
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
scope.$show = function () {
|
|
61
|
+
scope.$$postDigest(function () {
|
|
62
|
+
$tooltip.show();
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
scope.$toggle = function () {
|
|
66
|
+
scope.$$postDigest(function () {
|
|
67
|
+
$tooltip.toggle();
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
$tooltip.$isShown = scope.$isShown = false;
|
|
71
|
+
// Private vars
|
|
72
|
+
var timeout, hoverState;
|
|
73
|
+
// Support contentTemplate option
|
|
74
|
+
if (options.contentTemplate) {
|
|
75
|
+
$tooltip.$promise = $tooltip.$promise.then(function (template) {
|
|
76
|
+
var templateEl = angular.element(template);
|
|
77
|
+
return fetchTemplate(options.contentTemplate).then(function (contentTemplate) {
|
|
78
|
+
var contentEl = findElement('[ng-bind="content"]', templateEl[0]);
|
|
79
|
+
if (!contentEl.length)
|
|
80
|
+
contentEl = findElement('[ng-bind="title"]', templateEl[0]);
|
|
81
|
+
contentEl.removeAttr('ng-bind').html(contentTemplate);
|
|
82
|
+
return templateEl[0].outerHTML;
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// Fetch, compile then initialize tooltip
|
|
87
|
+
var tipLinker, tipElement, tipTemplate, tipContainer;
|
|
88
|
+
$tooltip.$promise.then(function (template) {
|
|
89
|
+
if (angular.isObject(template))
|
|
90
|
+
template = template.data;
|
|
91
|
+
if (options.html)
|
|
92
|
+
template = template.replace(htmlReplaceRegExp, 'ng-bind-html="');
|
|
93
|
+
template = trim.apply(template);
|
|
94
|
+
tipTemplate = template;
|
|
95
|
+
tipLinker = $compile(template);
|
|
96
|
+
$tooltip.init();
|
|
97
|
+
});
|
|
98
|
+
$tooltip.init = function () {
|
|
99
|
+
// Options: delay
|
|
100
|
+
if (options.delay && angular.isNumber(options.delay)) {
|
|
101
|
+
options.delay = {
|
|
102
|
+
show: options.delay,
|
|
103
|
+
hide: options.delay
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Replace trigger on touch devices ?
|
|
107
|
+
// if(isTouch && options.trigger === defaults.trigger) {
|
|
108
|
+
// options.trigger.replace(/hover/g, 'click');
|
|
109
|
+
// }
|
|
110
|
+
// Options : container
|
|
111
|
+
if (options.container === 'self') {
|
|
112
|
+
tipContainer = element;
|
|
113
|
+
} else if (options.container) {
|
|
114
|
+
tipContainer = findElement(options.container);
|
|
115
|
+
}
|
|
116
|
+
// Options: trigger
|
|
117
|
+
var triggers = options.trigger.split(' ');
|
|
118
|
+
angular.forEach(triggers, function (trigger) {
|
|
119
|
+
if (trigger === 'click') {
|
|
120
|
+
element.on('click', $tooltip.toggle);
|
|
121
|
+
} else if (trigger !== 'manual') {
|
|
122
|
+
element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
|
|
123
|
+
element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
|
|
124
|
+
trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// Options: show
|
|
128
|
+
if (options.show) {
|
|
129
|
+
scope.$$postDigest(function () {
|
|
130
|
+
options.trigger === 'focus' ? element[0].focus() : $tooltip.show();
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
$tooltip.destroy = function () {
|
|
135
|
+
// Unbind events
|
|
136
|
+
var triggers = options.trigger.split(' ');
|
|
137
|
+
for (var i = triggers.length; i--;) {
|
|
138
|
+
var trigger = triggers[i];
|
|
139
|
+
if (trigger === 'click') {
|
|
140
|
+
element.off('click', $tooltip.toggle);
|
|
141
|
+
} else if (trigger !== 'manual') {
|
|
142
|
+
element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);
|
|
143
|
+
element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);
|
|
144
|
+
trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Remove element
|
|
148
|
+
if (tipElement) {
|
|
149
|
+
tipElement.remove();
|
|
150
|
+
tipElement = null;
|
|
151
|
+
}
|
|
152
|
+
// Destroy scope
|
|
153
|
+
scope.$destroy();
|
|
154
|
+
};
|
|
155
|
+
$tooltip.enter = function () {
|
|
156
|
+
clearTimeout(timeout);
|
|
157
|
+
hoverState = 'in';
|
|
158
|
+
if (!options.delay || !options.delay.show) {
|
|
159
|
+
return $tooltip.show();
|
|
160
|
+
}
|
|
161
|
+
timeout = setTimeout(function () {
|
|
162
|
+
if (hoverState === 'in')
|
|
163
|
+
$tooltip.show();
|
|
164
|
+
}, options.delay.show);
|
|
165
|
+
};
|
|
166
|
+
$tooltip.show = function () {
|
|
167
|
+
scope.$emit(options.prefixEvent + '.show.before', $tooltip);
|
|
168
|
+
var parent = options.container ? tipContainer : null;
|
|
169
|
+
var after = options.container ? null : element;
|
|
170
|
+
// Hide any existing tipElement
|
|
171
|
+
if (tipElement)
|
|
172
|
+
tipElement.remove();
|
|
173
|
+
// Fetch a cloned element linked from template
|
|
174
|
+
tipElement = $tooltip.$element = tipLinker(scope, function (clonedElement, scope) {
|
|
175
|
+
});
|
|
176
|
+
// Set the initial positioning.
|
|
177
|
+
tipElement.css({
|
|
178
|
+
top: '0px',
|
|
179
|
+
left: '0px',
|
|
180
|
+
display: 'block'
|
|
181
|
+
}).addClass(options.placement);
|
|
182
|
+
// Options: animation
|
|
183
|
+
if (options.animation)
|
|
184
|
+
tipElement.addClass(options.animation);
|
|
185
|
+
// Options: type
|
|
186
|
+
if (options.type)
|
|
187
|
+
tipElement.addClass(options.prefixClass + '-' + options.type);
|
|
188
|
+
$animate.enter(tipElement, parent, after, function () {
|
|
189
|
+
scope.$emit(options.prefixEvent + '.show', $tooltip);
|
|
190
|
+
});
|
|
191
|
+
$tooltip.$isShown = scope.$isShown = true;
|
|
192
|
+
scope.$$phase || scope.$root.$$phase || scope.$digest();
|
|
193
|
+
$$rAF($tooltip.$applyPlacement);
|
|
194
|
+
// var a = bodyEl.offsetWidth + 1; ?
|
|
195
|
+
// Bind events
|
|
196
|
+
if (options.keyboard) {
|
|
197
|
+
if (options.trigger !== 'focus') {
|
|
198
|
+
$tooltip.focus();
|
|
199
|
+
tipElement.on('keyup', $tooltip.$onKeyUp);
|
|
200
|
+
} else {
|
|
201
|
+
element.on('keyup', $tooltip.$onFocusKeyUp);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
$tooltip.leave = function () {
|
|
206
|
+
clearTimeout(timeout);
|
|
207
|
+
hoverState = 'out';
|
|
208
|
+
if (!options.delay || !options.delay.hide) {
|
|
209
|
+
return $tooltip.hide();
|
|
210
|
+
}
|
|
211
|
+
timeout = setTimeout(function () {
|
|
212
|
+
if (hoverState === 'out') {
|
|
213
|
+
$tooltip.hide();
|
|
214
|
+
}
|
|
215
|
+
}, options.delay.hide);
|
|
216
|
+
};
|
|
217
|
+
$tooltip.hide = function (blur) {
|
|
218
|
+
if (!$tooltip.$isShown)
|
|
219
|
+
return;
|
|
220
|
+
scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
|
|
221
|
+
$animate.leave(tipElement, function () {
|
|
222
|
+
scope.$emit(options.prefixEvent + '.hide', $tooltip);
|
|
223
|
+
});
|
|
224
|
+
$tooltip.$isShown = scope.$isShown = false;
|
|
225
|
+
scope.$$phase || scope.$root.$$phase || scope.$digest();
|
|
226
|
+
// Unbind events
|
|
227
|
+
if (options.keyboard && tipElement !== null) {
|
|
228
|
+
tipElement.off('keyup', $tooltip.$onKeyUp);
|
|
229
|
+
}
|
|
230
|
+
// Allow to blur the input when hidden, like when pressing enter key
|
|
231
|
+
if (blur && options.trigger === 'focus') {
|
|
232
|
+
return element[0].blur();
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
$tooltip.toggle = function () {
|
|
236
|
+
$tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();
|
|
237
|
+
};
|
|
238
|
+
$tooltip.focus = function () {
|
|
239
|
+
tipElement[0].focus();
|
|
240
|
+
};
|
|
241
|
+
// Protected methods
|
|
242
|
+
$tooltip.$applyPlacement = function () {
|
|
243
|
+
if (!tipElement)
|
|
244
|
+
return;
|
|
245
|
+
// Get the position of the tooltip element.
|
|
246
|
+
var elementPosition = getPosition();
|
|
247
|
+
// Get the height and width of the tooltip so we can center it.
|
|
248
|
+
var tipWidth = tipElement.prop('offsetWidth'), tipHeight = tipElement.prop('offsetHeight');
|
|
249
|
+
// Get the tooltip's top and left coordinates to center it with this directive.
|
|
250
|
+
var tipPosition = getCalculatedOffset(options.placement, elementPosition, tipWidth, tipHeight);
|
|
251
|
+
// Now set the calculated positioning.
|
|
252
|
+
tipPosition.top += 'px';
|
|
253
|
+
tipPosition.left += 'px';
|
|
254
|
+
tipElement.css(tipPosition);
|
|
255
|
+
};
|
|
256
|
+
$tooltip.$onKeyUp = function (evt) {
|
|
257
|
+
evt.which === 27 && $tooltip.hide();
|
|
258
|
+
};
|
|
259
|
+
$tooltip.$onFocusKeyUp = function (evt) {
|
|
260
|
+
evt.which === 27 && element[0].blur();
|
|
261
|
+
};
|
|
262
|
+
$tooltip.$onFocusElementMouseDown = function (evt) {
|
|
263
|
+
evt.preventDefault();
|
|
264
|
+
evt.stopPropagation();
|
|
265
|
+
// Some browsers do not auto-focus buttons (eg. Safari)
|
|
266
|
+
$tooltip.$isShown ? element[0].blur() : element[0].focus();
|
|
267
|
+
};
|
|
268
|
+
// Private methods
|
|
269
|
+
function getPosition() {
|
|
270
|
+
if (options.container === 'body') {
|
|
271
|
+
return dimensions.offset(element[0]);
|
|
272
|
+
} else {
|
|
273
|
+
return dimensions.position(element[0]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function getCalculatedOffset(placement, position, actualWidth, actualHeight) {
|
|
277
|
+
var offset;
|
|
278
|
+
var split = placement.split('-');
|
|
279
|
+
switch (split[0]) {
|
|
280
|
+
case 'right':
|
|
281
|
+
offset = {
|
|
282
|
+
top: position.top + position.height / 2 - actualHeight / 2,
|
|
283
|
+
left: position.left + position.width
|
|
284
|
+
};
|
|
285
|
+
break;
|
|
286
|
+
case 'bottom':
|
|
287
|
+
offset = {
|
|
288
|
+
top: position.top + position.height,
|
|
289
|
+
left: position.left + position.width / 2 - actualWidth / 2
|
|
290
|
+
};
|
|
291
|
+
break;
|
|
292
|
+
case 'left':
|
|
293
|
+
offset = {
|
|
294
|
+
top: position.top + position.height / 2 - actualHeight / 2,
|
|
295
|
+
left: position.left - actualWidth
|
|
296
|
+
};
|
|
297
|
+
break;
|
|
298
|
+
default:
|
|
299
|
+
offset = {
|
|
300
|
+
top: position.top - actualHeight,
|
|
301
|
+
left: position.left + position.width / 2 - actualWidth / 2
|
|
302
|
+
};
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
if (!split[1]) {
|
|
306
|
+
return offset;
|
|
307
|
+
}
|
|
308
|
+
// Add support for corners @todo css
|
|
309
|
+
if (split[0] === 'top' || split[0] === 'bottom') {
|
|
310
|
+
switch (split[1]) {
|
|
311
|
+
case 'left':
|
|
312
|
+
offset.left = position.left;
|
|
313
|
+
break;
|
|
314
|
+
case 'right':
|
|
315
|
+
offset.left = position.left + position.width - actualWidth;
|
|
316
|
+
}
|
|
317
|
+
} else if (split[0] === 'left' || split[0] === 'right') {
|
|
318
|
+
switch (split[1]) {
|
|
319
|
+
case 'top':
|
|
320
|
+
offset.top = position.top - actualHeight;
|
|
321
|
+
break;
|
|
322
|
+
case 'bottom':
|
|
323
|
+
offset.top = position.top + position.height;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return offset;
|
|
327
|
+
}
|
|
328
|
+
return $tooltip;
|
|
329
|
+
}
|
|
330
|
+
// Helper functions
|
|
331
|
+
function findElement(query, element) {
|
|
332
|
+
return angular.element((element || document).querySelectorAll(query));
|
|
333
|
+
}
|
|
334
|
+
function fetchTemplate(template) {
|
|
335
|
+
return $q.when($templateCache.get(template) || $http.get(template)).then(function (res) {
|
|
336
|
+
if (angular.isObject(res)) {
|
|
337
|
+
$templateCache.put(template, res.data);
|
|
338
|
+
return res.data;
|
|
339
|
+
}
|
|
340
|
+
return res;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return TooltipFactory;
|
|
344
|
+
}
|
|
345
|
+
];
|
|
346
|
+
}).directive('bsTooltip', [
|
|
347
|
+
'$window',
|
|
348
|
+
'$location',
|
|
349
|
+
'$sce',
|
|
350
|
+
'$tooltip',
|
|
351
|
+
'$$rAF',
|
|
352
|
+
function ($window, $location, $sce, $tooltip, $$rAF) {
|
|
353
|
+
return {
|
|
354
|
+
restrict: 'EAC',
|
|
355
|
+
scope: true,
|
|
356
|
+
link: function postLink(scope, element, attr, transclusion) {
|
|
357
|
+
// Directive options
|
|
358
|
+
var options = { scope: scope };
|
|
359
|
+
angular.forEach([
|
|
360
|
+
'template',
|
|
361
|
+
'contentTemplate',
|
|
362
|
+
'placement',
|
|
363
|
+
'container',
|
|
364
|
+
'delay',
|
|
365
|
+
'trigger',
|
|
366
|
+
'keyboard',
|
|
367
|
+
'html',
|
|
368
|
+
'animation',
|
|
369
|
+
'type'
|
|
370
|
+
], function (key) {
|
|
371
|
+
if (angular.isDefined(attr[key]))
|
|
372
|
+
options[key] = attr[key];
|
|
373
|
+
});
|
|
374
|
+
// Observe scope attributes for change
|
|
375
|
+
angular.forEach(['title'], function (key) {
|
|
376
|
+
attr[key] && attr.$observe(key, function (newValue, oldValue) {
|
|
377
|
+
scope[key] = $sce.trustAsHtml(newValue);
|
|
378
|
+
angular.isDefined(oldValue) && $$rAF(function () {
|
|
379
|
+
tooltip && tooltip.$applyPlacement();
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
// Support scope as an object
|
|
384
|
+
attr.bsTooltip && scope.$watch(attr.bsTooltip, function (newValue, oldValue) {
|
|
385
|
+
if (angular.isObject(newValue)) {
|
|
386
|
+
angular.extend(scope, newValue);
|
|
387
|
+
} else {
|
|
388
|
+
scope.title = newValue;
|
|
389
|
+
}
|
|
390
|
+
angular.isDefined(oldValue) && $$rAF(function () {
|
|
391
|
+
tooltip && tooltip.$applyPlacement();
|
|
392
|
+
});
|
|
393
|
+
}, true);
|
|
394
|
+
// Initialize popover
|
|
395
|
+
var tooltip = $tooltip(element, options);
|
|
396
|
+
// Garbage collection
|
|
397
|
+
scope.$on('$destroy', function () {
|
|
398
|
+
tooltip.destroy();
|
|
399
|
+
options = null;
|
|
400
|
+
tooltip = null;
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
]);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.0.1 - 2014-04-10
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
angular.module('mgcrea.ngStrap.tooltip').run([
|
|
10
|
+
'$templateCache',
|
|
11
|
+
function ($templateCache) {
|
|
12
|
+
$templateCache.put('tooltip/tooltip.tpl.html', '<div class="tooltip in" ng-show="title"><div class="tooltip-arrow"></div><div class="tooltip-inner" ng-bind="title"></div></div>');
|
|
13
|
+
}
|
|
14
|
+
]);
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* angular-strap
|
|
3
|
+
* @version v2.0.1 - 2014-04-10
|
|
4
|
+
* @link http://mgcrea.github.io/angular-strap
|
|
5
|
+
* @author Olivier Louvignes (olivier@mg-crea.com)
|
|
6
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
angular.module('mgcrea.ngStrap.typeahead', [
|
|
10
|
+
'mgcrea.ngStrap.tooltip',
|
|
11
|
+
'mgcrea.ngStrap.helpers.parseOptions'
|
|
12
|
+
]).provider('$typeahead', function () {
|
|
13
|
+
var defaults = this.defaults = {
|
|
14
|
+
animation: 'am-fade',
|
|
15
|
+
prefixClass: 'typeahead',
|
|
16
|
+
placement: 'bottom-left',
|
|
17
|
+
template: 'typeahead/typeahead.tpl.html',
|
|
18
|
+
trigger: 'focus',
|
|
19
|
+
container: false,
|
|
20
|
+
keyboard: true,
|
|
21
|
+
html: false,
|
|
22
|
+
delay: 0,
|
|
23
|
+
minLength: 1,
|
|
24
|
+
filter: 'filter',
|
|
25
|
+
limit: 6
|
|
26
|
+
};
|
|
27
|
+
this.$get = [
|
|
28
|
+
'$window',
|
|
29
|
+
'$rootScope',
|
|
30
|
+
'$tooltip',
|
|
31
|
+
function ($window, $rootScope, $tooltip) {
|
|
32
|
+
var bodyEl = angular.element($window.document.body);
|
|
33
|
+
function TypeaheadFactory(element, config) {
|
|
34
|
+
var $typeahead = {};
|
|
35
|
+
// Common vars
|
|
36
|
+
var options = angular.extend({}, defaults, config);
|
|
37
|
+
var controller = options.controller;
|
|
38
|
+
$typeahead = $tooltip(element, options);
|
|
39
|
+
var parentScope = config.scope;
|
|
40
|
+
var scope = $typeahead.$scope;
|
|
41
|
+
scope.$resetMatches = function () {
|
|
42
|
+
scope.$matches = [];
|
|
43
|
+
scope.$activeIndex = 0;
|
|
44
|
+
};
|
|
45
|
+
scope.$resetMatches();
|
|
46
|
+
scope.$activate = function (index) {
|
|
47
|
+
scope.$$postDigest(function () {
|
|
48
|
+
$typeahead.activate(index);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
scope.$select = function (index, evt) {
|
|
52
|
+
scope.$$postDigest(function () {
|
|
53
|
+
$typeahead.select(index);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
scope.$isVisible = function () {
|
|
57
|
+
return $typeahead.$isVisible();
|
|
58
|
+
};
|
|
59
|
+
// Public methods
|
|
60
|
+
$typeahead.update = function (matches) {
|
|
61
|
+
scope.$matches = matches;
|
|
62
|
+
if (scope.$activeIndex >= matches.length) {
|
|
63
|
+
scope.$activeIndex = 0;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
$typeahead.activate = function (index) {
|
|
67
|
+
scope.$activeIndex = index;
|
|
68
|
+
};
|
|
69
|
+
$typeahead.select = function (index) {
|
|
70
|
+
var value = scope.$matches[index].value;
|
|
71
|
+
if (controller) {
|
|
72
|
+
controller.$setViewValue(value);
|
|
73
|
+
controller.$render();
|
|
74
|
+
if (parentScope)
|
|
75
|
+
parentScope.$digest();
|
|
76
|
+
}
|
|
77
|
+
scope.$resetMatches();
|
|
78
|
+
// Emit event
|
|
79
|
+
scope.$emit('$typeahead.select', value, index);
|
|
80
|
+
};
|
|
81
|
+
// Protected methods
|
|
82
|
+
$typeahead.$isVisible = function () {
|
|
83
|
+
if (!options.minLength || !controller) {
|
|
84
|
+
return !!scope.$matches.length;
|
|
85
|
+
}
|
|
86
|
+
// minLength support
|
|
87
|
+
return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;
|
|
88
|
+
};
|
|
89
|
+
$typeahead.$getIndex = function (value) {
|
|
90
|
+
var l = scope.$matches.length, i = l;
|
|
91
|
+
if (!l)
|
|
92
|
+
return;
|
|
93
|
+
for (i = l; i--;) {
|
|
94
|
+
if (scope.$matches[i].value === value)
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
if (i < 0)
|
|
98
|
+
return;
|
|
99
|
+
return i;
|
|
100
|
+
};
|
|
101
|
+
$typeahead.$onMouseDown = function (evt) {
|
|
102
|
+
// Prevent blur on mousedown
|
|
103
|
+
evt.preventDefault();
|
|
104
|
+
evt.stopPropagation();
|
|
105
|
+
};
|
|
106
|
+
$typeahead.$onKeyDown = function (evt) {
|
|
107
|
+
if (!/(38|40|13)/.test(evt.keyCode))
|
|
108
|
+
return;
|
|
109
|
+
evt.preventDefault();
|
|
110
|
+
evt.stopPropagation();
|
|
111
|
+
// Select with enter
|
|
112
|
+
if (evt.keyCode === 13 && scope.$matches.length) {
|
|
113
|
+
return $typeahead.select(scope.$activeIndex);
|
|
114
|
+
}
|
|
115
|
+
// Navigate with keyboard
|
|
116
|
+
if (evt.keyCode === 38 && scope.$activeIndex > 0)
|
|
117
|
+
scope.$activeIndex--;
|
|
118
|
+
else if (evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1)
|
|
119
|
+
scope.$activeIndex++;
|
|
120
|
+
else if (angular.isUndefined(scope.$activeIndex))
|
|
121
|
+
scope.$activeIndex = 0;
|
|
122
|
+
scope.$digest();
|
|
123
|
+
};
|
|
124
|
+
// Overrides
|
|
125
|
+
var show = $typeahead.show;
|
|
126
|
+
$typeahead.show = function () {
|
|
127
|
+
show();
|
|
128
|
+
setTimeout(function () {
|
|
129
|
+
$typeahead.$element.on('mousedown', $typeahead.$onMouseDown);
|
|
130
|
+
if (options.keyboard) {
|
|
131
|
+
element.on('keydown', $typeahead.$onKeyDown);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
var hide = $typeahead.hide;
|
|
136
|
+
$typeahead.hide = function () {
|
|
137
|
+
$typeahead.$element.off('mousedown', $typeahead.$onMouseDown);
|
|
138
|
+
if (options.keyboard) {
|
|
139
|
+
element.off('keydown', $typeahead.$onKeyDown);
|
|
140
|
+
}
|
|
141
|
+
hide();
|
|
142
|
+
};
|
|
143
|
+
return $typeahead;
|
|
144
|
+
}
|
|
145
|
+
TypeaheadFactory.defaults = defaults;
|
|
146
|
+
return TypeaheadFactory;
|
|
147
|
+
}
|
|
148
|
+
];
|
|
149
|
+
}).directive('bsTypeahead', [
|
|
150
|
+
'$window',
|
|
151
|
+
'$parse',
|
|
152
|
+
'$q',
|
|
153
|
+
'$typeahead',
|
|
154
|
+
'$parseOptions',
|
|
155
|
+
function ($window, $parse, $q, $typeahead, $parseOptions) {
|
|
156
|
+
var defaults = $typeahead.defaults;
|
|
157
|
+
return {
|
|
158
|
+
restrict: 'EAC',
|
|
159
|
+
require: 'ngModel',
|
|
160
|
+
link: function postLink(scope, element, attr, controller) {
|
|
161
|
+
// Directive options
|
|
162
|
+
var options = {
|
|
163
|
+
scope: scope,
|
|
164
|
+
controller: controller
|
|
165
|
+
};
|
|
166
|
+
angular.forEach([
|
|
167
|
+
'placement',
|
|
168
|
+
'container',
|
|
169
|
+
'delay',
|
|
170
|
+
'trigger',
|
|
171
|
+
'keyboard',
|
|
172
|
+
'html',
|
|
173
|
+
'animation',
|
|
174
|
+
'template',
|
|
175
|
+
'filter',
|
|
176
|
+
'limit',
|
|
177
|
+
'minLength'
|
|
178
|
+
], function (key) {
|
|
179
|
+
if (angular.isDefined(attr[key]))
|
|
180
|
+
options[key] = attr[key];
|
|
181
|
+
});
|
|
182
|
+
// Build proper ngOptions
|
|
183
|
+
var filter = options.filter || defaults.filter;
|
|
184
|
+
var limit = options.limit || defaults.limit;
|
|
185
|
+
var ngOptions = attr.ngOptions;
|
|
186
|
+
if (filter)
|
|
187
|
+
ngOptions += ' | ' + filter + ':$viewValue';
|
|
188
|
+
if (limit)
|
|
189
|
+
ngOptions += ' | limitTo:' + limit;
|
|
190
|
+
var parsedOptions = $parseOptions(ngOptions);
|
|
191
|
+
// Initialize typeahead
|
|
192
|
+
var typeahead = $typeahead(element, options);
|
|
193
|
+
// if(!dump) var dump = console.error.bind(console);
|
|
194
|
+
// Watch model for changes
|
|
195
|
+
scope.$watch(attr.ngModel, function (newValue, oldValue) {
|
|
196
|
+
scope.$modelValue = newValue;
|
|
197
|
+
//Set model value on the scope to custom templates can use it.
|
|
198
|
+
parsedOptions.valuesFn(scope, controller).then(function (values) {
|
|
199
|
+
if (values.length > limit)
|
|
200
|
+
values = values.slice(0, limit);
|
|
201
|
+
// if(matches.length === 1 && matches[0].value === newValue) return;
|
|
202
|
+
typeahead.update(values);
|
|
203
|
+
// Queue a new rendering that will leverage collection loading
|
|
204
|
+
controller.$render();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
// Model rendering in view
|
|
208
|
+
controller.$render = function () {
|
|
209
|
+
// console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);
|
|
210
|
+
if (controller.$isEmpty(controller.$viewValue))
|
|
211
|
+
return element.val('');
|
|
212
|
+
var index = typeahead.$getIndex(controller.$modelValue);
|
|
213
|
+
var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;
|
|
214
|
+
element.val(selected.replace(/<(?:.|\n)*?>/gm, '').trim());
|
|
215
|
+
};
|
|
216
|
+
// Garbage collection
|
|
217
|
+
scope.$on('$destroy', function () {
|
|
218
|
+
typeahead.destroy();
|
|
219
|
+
options = null;
|
|
220
|
+
typeahead = null;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
]);
|