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.modal').run([
|
|
10
|
+
'$templateCache',
|
|
11
|
+
function ($templateCache) {
|
|
12
|
+
$templateCache.put('modal/modal.tpl.html', '<div class="modal" tabindex="-1" role="dialog"><div class="modal-dialog"><div class="modal-content"><div class="modal-header" ng-show="title"><button type="button" class="close" ng-click="$hide()">×</button><h4 class="modal-title" ng-bind="title"></h4></div><div class="modal-body" ng-bind="content"></div><div class="modal-footer"><button type="button" class="btn btn-default" ng-click="$hide()">Close</button></div></div></div></div>');
|
|
13
|
+
}
|
|
14
|
+
]);
|
|
@@ -0,0 +1,55 @@
|
|
|
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.navbar', []).provider('$navbar', function () {
|
|
10
|
+
var defaults = this.defaults = {
|
|
11
|
+
activeClass: 'active',
|
|
12
|
+
routeAttr: 'data-match-route',
|
|
13
|
+
strict: false
|
|
14
|
+
};
|
|
15
|
+
this.$get = function () {
|
|
16
|
+
return { defaults: defaults };
|
|
17
|
+
};
|
|
18
|
+
}).directive('bsNavbar', [
|
|
19
|
+
'$window',
|
|
20
|
+
'$location',
|
|
21
|
+
'$navbar',
|
|
22
|
+
function ($window, $location, $navbar) {
|
|
23
|
+
var defaults = $navbar.defaults;
|
|
24
|
+
return {
|
|
25
|
+
restrict: 'A',
|
|
26
|
+
link: function postLink(scope, element, attr, controller) {
|
|
27
|
+
// Directive options
|
|
28
|
+
var options = angular.copy(defaults);
|
|
29
|
+
angular.forEach(Object.keys(defaults), function (key) {
|
|
30
|
+
if (angular.isDefined(attr[key]))
|
|
31
|
+
options[key] = attr[key];
|
|
32
|
+
});
|
|
33
|
+
// Watch for the $location
|
|
34
|
+
scope.$watch(function () {
|
|
35
|
+
return $location.path();
|
|
36
|
+
}, function (newValue, oldValue) {
|
|
37
|
+
var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');
|
|
38
|
+
angular.forEach(liElements, function (li) {
|
|
39
|
+
var liElement = angular.element(li);
|
|
40
|
+
var pattern = liElement.attr(options.routeAttr).replace('/', '\\/');
|
|
41
|
+
if (options.strict) {
|
|
42
|
+
pattern = '^' + pattern + '$';
|
|
43
|
+
}
|
|
44
|
+
var regexp = new RegExp(pattern, ['i']);
|
|
45
|
+
if (regexp.test(newValue)) {
|
|
46
|
+
liElement.addClass(options.activeClass);
|
|
47
|
+
} else {
|
|
48
|
+
liElement.removeClass(options.activeClass);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
]);
|
|
@@ -0,0 +1,51 @@
|
|
|
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.helpers.parseOptions', []).provider('$parseOptions', function () {
|
|
10
|
+
var defaults = this.defaults = { 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+(.*?))?$/ };
|
|
11
|
+
this.$get = [
|
|
12
|
+
'$parse',
|
|
13
|
+
'$q',
|
|
14
|
+
function ($parse, $q) {
|
|
15
|
+
function ParseOptionsFactory(attr, config) {
|
|
16
|
+
var $parseOptions = {};
|
|
17
|
+
// Common vars
|
|
18
|
+
var options = angular.extend({}, defaults, config);
|
|
19
|
+
$parseOptions.$values = [];
|
|
20
|
+
// Private vars
|
|
21
|
+
var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;
|
|
22
|
+
$parseOptions.init = function () {
|
|
23
|
+
$parseOptions.$match = match = attr.match(options.regexp);
|
|
24
|
+
displayFn = $parse(match[2] || match[1]), valueName = match[4] || match[6], keyName = match[5], groupByFn = $parse(match[3] || ''), valueFn = $parse(match[2] ? match[1] : valueName), valuesFn = $parse(match[7]);
|
|
25
|
+
};
|
|
26
|
+
$parseOptions.valuesFn = function (scope, controller) {
|
|
27
|
+
return $q.when(valuesFn(scope, controller)).then(function (values) {
|
|
28
|
+
$parseOptions.$values = values ? parseValues(values) : {};
|
|
29
|
+
return $parseOptions.$values;
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
// Private functions
|
|
33
|
+
function parseValues(values) {
|
|
34
|
+
return values.map(function (match, index) {
|
|
35
|
+
var locals = {}, label, value;
|
|
36
|
+
locals[valueName] = match;
|
|
37
|
+
label = displayFn(locals);
|
|
38
|
+
value = valueFn(locals) || index;
|
|
39
|
+
return {
|
|
40
|
+
label: label,
|
|
41
|
+
value: value
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
$parseOptions.init();
|
|
46
|
+
return $parseOptions;
|
|
47
|
+
}
|
|
48
|
+
return ParseOptionsFactory;
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
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.popover', ['mgcrea.ngStrap.tooltip']).provider('$popover', function () {
|
|
10
|
+
var defaults = this.defaults = {
|
|
11
|
+
animation: 'am-fade',
|
|
12
|
+
placement: 'right',
|
|
13
|
+
template: 'popover/popover.tpl.html',
|
|
14
|
+
contentTemplate: false,
|
|
15
|
+
trigger: 'click',
|
|
16
|
+
keyboard: true,
|
|
17
|
+
html: false,
|
|
18
|
+
title: '',
|
|
19
|
+
content: '',
|
|
20
|
+
delay: 0,
|
|
21
|
+
container: false
|
|
22
|
+
};
|
|
23
|
+
this.$get = [
|
|
24
|
+
'$tooltip',
|
|
25
|
+
function ($tooltip) {
|
|
26
|
+
function PopoverFactory(element, config) {
|
|
27
|
+
// Common vars
|
|
28
|
+
var options = angular.extend({}, defaults, config);
|
|
29
|
+
var $popover = $tooltip(element, options);
|
|
30
|
+
// Support scope as string options [/*title, */content]
|
|
31
|
+
if (options.content) {
|
|
32
|
+
$popover.$scope.content = options.content;
|
|
33
|
+
}
|
|
34
|
+
return $popover;
|
|
35
|
+
}
|
|
36
|
+
return PopoverFactory;
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
}).directive('bsPopover', [
|
|
40
|
+
'$window',
|
|
41
|
+
'$location',
|
|
42
|
+
'$sce',
|
|
43
|
+
'$popover',
|
|
44
|
+
function ($window, $location, $sce, $popover) {
|
|
45
|
+
var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;
|
|
46
|
+
return {
|
|
47
|
+
restrict: 'EAC',
|
|
48
|
+
scope: true,
|
|
49
|
+
link: function postLink(scope, element, attr) {
|
|
50
|
+
// Directive options
|
|
51
|
+
var options = { scope: scope };
|
|
52
|
+
angular.forEach([
|
|
53
|
+
'template',
|
|
54
|
+
'contentTemplate',
|
|
55
|
+
'placement',
|
|
56
|
+
'container',
|
|
57
|
+
'delay',
|
|
58
|
+
'trigger',
|
|
59
|
+
'keyboard',
|
|
60
|
+
'html',
|
|
61
|
+
'animation'
|
|
62
|
+
], function (key) {
|
|
63
|
+
if (angular.isDefined(attr[key]))
|
|
64
|
+
options[key] = attr[key];
|
|
65
|
+
});
|
|
66
|
+
// Support scope as data-attrs
|
|
67
|
+
angular.forEach([
|
|
68
|
+
'title',
|
|
69
|
+
'content'
|
|
70
|
+
], function (key) {
|
|
71
|
+
attr[key] && attr.$observe(key, function (newValue, oldValue) {
|
|
72
|
+
scope[key] = $sce.trustAsHtml(newValue);
|
|
73
|
+
angular.isDefined(oldValue) && requestAnimationFrame(function () {
|
|
74
|
+
popover && popover.$applyPlacement();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
// Support scope as an object
|
|
79
|
+
attr.bsPopover && scope.$watch(attr.bsPopover, function (newValue, oldValue) {
|
|
80
|
+
if (angular.isObject(newValue)) {
|
|
81
|
+
angular.extend(scope, newValue);
|
|
82
|
+
} else {
|
|
83
|
+
scope.content = newValue;
|
|
84
|
+
}
|
|
85
|
+
angular.isDefined(oldValue) && requestAnimationFrame(function () {
|
|
86
|
+
popover && popover.$applyPlacement();
|
|
87
|
+
});
|
|
88
|
+
}, true);
|
|
89
|
+
// Initialize popover
|
|
90
|
+
var popover = $popover(element, options);
|
|
91
|
+
// Garbage collection
|
|
92
|
+
scope.$on('$destroy', function () {
|
|
93
|
+
popover.destroy();
|
|
94
|
+
options = null;
|
|
95
|
+
popover = null;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
]);
|
|
@@ -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.popover').run([
|
|
10
|
+
'$templateCache',
|
|
11
|
+
function ($templateCache) {
|
|
12
|
+
$templateCache.put('popover/popover.tpl.html', '<div class="popover"><div class="arrow"></div><h3 class="popover-title" ng-bind="title" ng-show="title"></h3><div class="popover-content" ng-bind="content"></div></div>');
|
|
13
|
+
}
|
|
14
|
+
]);
|
|
@@ -0,0 +1,45 @@
|
|
|
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.version.minor < 3 && angular.version.dot < 14 && angular.module('ng').factory('$$rAF', [
|
|
10
|
+
'$window',
|
|
11
|
+
'$timeout',
|
|
12
|
+
function ($window, $timeout) {
|
|
13
|
+
var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame;
|
|
14
|
+
var cancelAnimationFrame = $window.cancelAnimationFrame || $window.webkitCancelAnimationFrame || $window.mozCancelAnimationFrame || $window.webkitCancelRequestAnimationFrame;
|
|
15
|
+
var rafSupported = !!requestAnimationFrame;
|
|
16
|
+
var raf = rafSupported ? function (fn) {
|
|
17
|
+
var id = requestAnimationFrame(fn);
|
|
18
|
+
return function () {
|
|
19
|
+
cancelAnimationFrame(id);
|
|
20
|
+
};
|
|
21
|
+
} : function (fn) {
|
|
22
|
+
var timer = $timeout(fn, 16.66, false);
|
|
23
|
+
// 1000 / 60 = 16.666
|
|
24
|
+
return function () {
|
|
25
|
+
$timeout.cancel(timer);
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
raf.supported = rafSupported;
|
|
29
|
+
return raf;
|
|
30
|
+
}
|
|
31
|
+
]); // .factory('$$animateReflow', function($$rAF, $document) {
|
|
32
|
+
// var bodyEl = $document[0].body;
|
|
33
|
+
// return function(fn) {
|
|
34
|
+
// //the returned function acts as the cancellation function
|
|
35
|
+
// return $$rAF(function() {
|
|
36
|
+
// //the line below will force the browser to perform a repaint
|
|
37
|
+
// //so that all the animated elements within the animation frame
|
|
38
|
+
// //will be properly updated and drawn on screen. This is
|
|
39
|
+
// //required to perform multi-class CSS based animations with
|
|
40
|
+
// //Firefox. DO NOT REMOVE THIS LINE.
|
|
41
|
+
// var a = bodyEl.offsetWidth + 1;
|
|
42
|
+
// fn();
|
|
43
|
+
// });
|
|
44
|
+
// };
|
|
45
|
+
// });
|
|
@@ -0,0 +1,229 @@
|
|
|
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.scrollspy', [
|
|
10
|
+
'mgcrea.ngStrap.helpers.debounce',
|
|
11
|
+
'mgcrea.ngStrap.helpers.dimensions'
|
|
12
|
+
]).provider('$scrollspy', function () {
|
|
13
|
+
// Pool of registered spies
|
|
14
|
+
var spies = this.$$spies = {};
|
|
15
|
+
var defaults = this.defaults = {
|
|
16
|
+
debounce: 150,
|
|
17
|
+
throttle: 100,
|
|
18
|
+
offset: 100
|
|
19
|
+
};
|
|
20
|
+
this.$get = [
|
|
21
|
+
'$window',
|
|
22
|
+
'$document',
|
|
23
|
+
'$rootScope',
|
|
24
|
+
'dimensions',
|
|
25
|
+
'debounce',
|
|
26
|
+
'throttle',
|
|
27
|
+
function ($window, $document, $rootScope, dimensions, debounce, throttle) {
|
|
28
|
+
var windowEl = angular.element($window);
|
|
29
|
+
var docEl = angular.element($document.prop('documentElement'));
|
|
30
|
+
var bodyEl = angular.element($window.document.body);
|
|
31
|
+
// Helper functions
|
|
32
|
+
function nodeName(element, name) {
|
|
33
|
+
return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();
|
|
34
|
+
}
|
|
35
|
+
function ScrollSpyFactory(config) {
|
|
36
|
+
// Common vars
|
|
37
|
+
var options = angular.extend({}, defaults, config);
|
|
38
|
+
if (!options.element)
|
|
39
|
+
options.element = bodyEl;
|
|
40
|
+
var isWindowSpy = nodeName(options.element, 'body');
|
|
41
|
+
var scrollEl = isWindowSpy ? windowEl : options.element;
|
|
42
|
+
var scrollId = isWindowSpy ? 'window' : options.id;
|
|
43
|
+
// Use existing spy
|
|
44
|
+
if (spies[scrollId]) {
|
|
45
|
+
spies[scrollId].$$count++;
|
|
46
|
+
return spies[scrollId];
|
|
47
|
+
}
|
|
48
|
+
var $scrollspy = {};
|
|
49
|
+
// Private vars
|
|
50
|
+
var unbindViewContentLoaded, unbindIncludeContentLoaded;
|
|
51
|
+
var trackedElements = $scrollspy.$trackedElements = [];
|
|
52
|
+
var sortedElements = [];
|
|
53
|
+
var activeTarget;
|
|
54
|
+
var debouncedCheckPosition;
|
|
55
|
+
var throttledCheckPosition;
|
|
56
|
+
var debouncedCheckOffsets;
|
|
57
|
+
var viewportHeight;
|
|
58
|
+
var scrollTop;
|
|
59
|
+
$scrollspy.init = function () {
|
|
60
|
+
// Setup internal ref counter
|
|
61
|
+
this.$$count = 1;
|
|
62
|
+
// Bind events
|
|
63
|
+
debouncedCheckPosition = debounce(this.checkPosition, options.debounce);
|
|
64
|
+
throttledCheckPosition = throttle(this.checkPosition, options.throttle);
|
|
65
|
+
scrollEl.on('click', this.checkPositionWithEventLoop);
|
|
66
|
+
windowEl.on('resize', debouncedCheckPosition);
|
|
67
|
+
scrollEl.on('scroll', throttledCheckPosition);
|
|
68
|
+
debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);
|
|
69
|
+
unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);
|
|
70
|
+
unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);
|
|
71
|
+
debouncedCheckOffsets();
|
|
72
|
+
// Register spy for reuse
|
|
73
|
+
if (scrollId) {
|
|
74
|
+
spies[scrollId] = $scrollspy;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
$scrollspy.destroy = function () {
|
|
78
|
+
// Check internal ref counter
|
|
79
|
+
this.$$count--;
|
|
80
|
+
if (this.$$count > 0) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Unbind events
|
|
84
|
+
scrollEl.off('click', this.checkPositionWithEventLoop);
|
|
85
|
+
windowEl.off('resize', debouncedCheckPosition);
|
|
86
|
+
scrollEl.off('scroll', debouncedCheckPosition);
|
|
87
|
+
unbindViewContentLoaded();
|
|
88
|
+
unbindIncludeContentLoaded();
|
|
89
|
+
if (scrollId) {
|
|
90
|
+
delete spies[scrollId];
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
$scrollspy.checkPosition = function () {
|
|
94
|
+
// Not ready yet
|
|
95
|
+
if (!sortedElements.length)
|
|
96
|
+
return;
|
|
97
|
+
// Calculate the scroll position
|
|
98
|
+
scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;
|
|
99
|
+
// Calculate the viewport height for use by the components
|
|
100
|
+
viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));
|
|
101
|
+
// Activate first element if scroll is smaller
|
|
102
|
+
if (scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {
|
|
103
|
+
return $scrollspy.$activateElement(sortedElements[0]);
|
|
104
|
+
}
|
|
105
|
+
// Activate proper element
|
|
106
|
+
for (var i = sortedElements.length; i--;) {
|
|
107
|
+
if (angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null)
|
|
108
|
+
continue;
|
|
109
|
+
if (activeTarget === sortedElements[i].target)
|
|
110
|
+
continue;
|
|
111
|
+
if (scrollTop < sortedElements[i].offsetTop)
|
|
112
|
+
continue;
|
|
113
|
+
if (sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop)
|
|
114
|
+
continue;
|
|
115
|
+
return $scrollspy.$activateElement(sortedElements[i]);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
$scrollspy.checkPositionWithEventLoop = function () {
|
|
119
|
+
setTimeout(this.checkPosition, 1);
|
|
120
|
+
};
|
|
121
|
+
// Protected methods
|
|
122
|
+
$scrollspy.$activateElement = function (element) {
|
|
123
|
+
if (activeTarget) {
|
|
124
|
+
var activeElement = $scrollspy.$getTrackedElement(activeTarget);
|
|
125
|
+
if (activeElement) {
|
|
126
|
+
activeElement.source.removeClass('active');
|
|
127
|
+
if (nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {
|
|
128
|
+
activeElement.source.parent().parent().removeClass('active');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
activeTarget = element.target;
|
|
133
|
+
element.source.addClass('active');
|
|
134
|
+
if (nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {
|
|
135
|
+
element.source.parent().parent().addClass('active');
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
$scrollspy.$getTrackedElement = function (target) {
|
|
139
|
+
return trackedElements.filter(function (obj) {
|
|
140
|
+
return obj.target === target;
|
|
141
|
+
})[0];
|
|
142
|
+
};
|
|
143
|
+
// Track offsets behavior
|
|
144
|
+
$scrollspy.checkOffsets = function () {
|
|
145
|
+
angular.forEach(trackedElements, function (trackedElement) {
|
|
146
|
+
var targetElement = document.querySelector(trackedElement.target);
|
|
147
|
+
trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;
|
|
148
|
+
if (options.offset && trackedElement.offsetTop !== null)
|
|
149
|
+
trackedElement.offsetTop -= options.offset * 1;
|
|
150
|
+
});
|
|
151
|
+
sortedElements = trackedElements.filter(function (el) {
|
|
152
|
+
return el.offsetTop !== null;
|
|
153
|
+
}).sort(function (a, b) {
|
|
154
|
+
return a.offsetTop - b.offsetTop;
|
|
155
|
+
});
|
|
156
|
+
debouncedCheckPosition();
|
|
157
|
+
};
|
|
158
|
+
$scrollspy.trackElement = function (target, source) {
|
|
159
|
+
trackedElements.push({
|
|
160
|
+
target: target,
|
|
161
|
+
source: source
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
$scrollspy.untrackElement = function (target, source) {
|
|
165
|
+
var toDelete;
|
|
166
|
+
for (var i = trackedElements.length; i--;) {
|
|
167
|
+
if (trackedElements[i].target === target && trackedElements[i].source === source) {
|
|
168
|
+
toDelete = i;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
trackedElements = trackedElements.splice(toDelete, 1);
|
|
173
|
+
};
|
|
174
|
+
$scrollspy.activate = function (i) {
|
|
175
|
+
trackedElements[i].addClass('active');
|
|
176
|
+
};
|
|
177
|
+
// Initialize plugin
|
|
178
|
+
$scrollspy.init();
|
|
179
|
+
return $scrollspy;
|
|
180
|
+
}
|
|
181
|
+
return ScrollSpyFactory;
|
|
182
|
+
}
|
|
183
|
+
];
|
|
184
|
+
}).directive('bsScrollspy', [
|
|
185
|
+
'$rootScope',
|
|
186
|
+
'debounce',
|
|
187
|
+
'dimensions',
|
|
188
|
+
'$scrollspy',
|
|
189
|
+
function ($rootScope, debounce, dimensions, $scrollspy) {
|
|
190
|
+
return {
|
|
191
|
+
restrict: 'EAC',
|
|
192
|
+
link: function postLink(scope, element, attr) {
|
|
193
|
+
var options = { scope: scope };
|
|
194
|
+
angular.forEach([
|
|
195
|
+
'offset',
|
|
196
|
+
'target'
|
|
197
|
+
], function (key) {
|
|
198
|
+
if (angular.isDefined(attr[key]))
|
|
199
|
+
options[key] = attr[key];
|
|
200
|
+
});
|
|
201
|
+
var scrollspy = $scrollspy(options);
|
|
202
|
+
scrollspy.trackElement(options.target, element);
|
|
203
|
+
scope.$on('$destroy', function () {
|
|
204
|
+
scrollspy.untrackElement(options.target, element);
|
|
205
|
+
scrollspy.destroy();
|
|
206
|
+
options = null;
|
|
207
|
+
scrollspy = null;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
]).directive('bsScrollspyList', [
|
|
213
|
+
'$rootScope',
|
|
214
|
+
'debounce',
|
|
215
|
+
'dimensions',
|
|
216
|
+
'$scrollspy',
|
|
217
|
+
function ($rootScope, debounce, dimensions, $scrollspy) {
|
|
218
|
+
return {
|
|
219
|
+
restrict: 'A',
|
|
220
|
+
compile: function postLink(element, attr) {
|
|
221
|
+
var children = element[0].querySelectorAll('li > a[href]');
|
|
222
|
+
angular.forEach(children, function (child) {
|
|
223
|
+
var childEl = angular.element(child);
|
|
224
|
+
childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
]);
|