Razique Mahroua
2019-11-28 1759c24ad2d2b35ec5c756e3dd3a60185fe944b7
commit | author | age
1759c2 1 /**
RM 2  * angular-strap
3  * @version v2.0.3 - 2014-05-30
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.affix', [
10   'mgcrea.ngStrap.helpers.dimensions',
11   'mgcrea.ngStrap.helpers.debounce'
12 ]).provider('$affix', function () {
13   var defaults = this.defaults = { offsetTop: 'auto' };
14   this.$get = [
15     '$window',
16     'debounce',
17     'dimensions',
18     function ($window, debounce, dimensions) {
19       var bodyEl = angular.element($window.document.body);
20       var windowEl = angular.element($window);
21       function AffixFactory(element, config) {
22         var $affix = {};
23         // Common vars
24         var options = angular.extend({}, defaults, config);
25         var targetEl = options.target;
26         // Initial private vars
27         var reset = 'affix affix-top affix-bottom', initialAffixTop = 0, initialOffsetTop = 0, offsetTop = 0, offsetBottom = 0, affixed = null, unpin = null;
28         var parent = element.parent();
29         // Options: custom parent
30         if (options.offsetParent) {
31           if (options.offsetParent.match(/^\d+$/)) {
32             for (var i = 0; i < options.offsetParent * 1 - 1; i++) {
33               parent = parent.parent();
34             }
35           } else {
36             parent = angular.element(options.offsetParent);
37           }
38         }
39         $affix.init = function () {
40           $affix.$parseOffsets();
41           initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;
42           // Bind events
43           targetEl.on('scroll', $affix.checkPosition);
44           targetEl.on('click', $affix.checkPositionWithEventLoop);
45           windowEl.on('resize', $affix.$debouncedOnResize);
46           // Both of these checkPosition() calls are necessary for the case where
47           // the user hits refresh after scrolling to the bottom of the page.
48           $affix.checkPosition();
49           $affix.checkPositionWithEventLoop();
50         };
51         $affix.destroy = function () {
52           // Unbind events
53           targetEl.off('scroll', $affix.checkPosition);
54           targetEl.off('click', $affix.checkPositionWithEventLoop);
55           windowEl.off('resize', $affix.$debouncedOnResize);
56         };
57         $affix.checkPositionWithEventLoop = function () {
58           setTimeout($affix.checkPosition, 1);
59         };
60         $affix.checkPosition = function () {
61           // if (!this.$element.is(':visible')) return
62           var scrollTop = getScrollTop();
63           var position = dimensions.offset(element[0]);
64           var elementHeight = dimensions.height(element[0]);
65           // Get required affix class according to position
66           var affix = getRequiredAffixClass(unpin, position, elementHeight);
67           // Did affix status changed this last check?
68           if (affixed === affix)
69             return;
70           affixed = affix;
71           // Add proper affix class
72           element.removeClass(reset).addClass('affix' + (affix !== 'middle' ? '-' + affix : ''));
73           if (affix === 'top') {
74             unpin = null;
75             element.css('position', options.offsetParent ? '' : 'relative');
76             element.css('top', '');
77           } else if (affix === 'bottom') {
78             if (options.offsetUnpin) {
79               unpin = -(options.offsetUnpin * 1);
80             } else {
81               // Calculate unpin threshold when affixed to bottom.
82               // Hopefully the browser scrolls pixel by pixel.
83               unpin = position.top - scrollTop;
84             }
85             element.css('position', options.offsetParent ? '' : 'relative');
86             element.css('top', options.offsetParent ? '' : bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop + 'px');
87           } else {
88             // affix === 'middle'
89             unpin = null;
90             element.css('position', 'fixed');
91             element.css('top', initialAffixTop + 'px');
92           }
93         };
94         $affix.$onResize = function () {
95           $affix.$parseOffsets();
96           $affix.checkPosition();
97         };
98         $affix.$debouncedOnResize = debounce($affix.$onResize, 50);
99         $affix.$parseOffsets = function () {
100           // Reset position to calculate correct offsetTop
101           element.css('position', options.offsetParent ? '' : 'relative');
102           if (options.offsetTop) {
103             if (options.offsetTop === 'auto') {
104               options.offsetTop = '+0';
105             }
106             if (options.offsetTop.match(/^[-+]\d+$/)) {
107               initialAffixTop = -options.offsetTop * 1;
108               if (options.offsetParent) {
109                 offsetTop = dimensions.offset(parent[0]).top + options.offsetTop * 1;
110               } else {
111                 offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + options.offsetTop * 1;
112               }
113             } else {
114               offsetTop = options.offsetTop * 1;
115             }
116           }
117           if (options.offsetBottom) {
118             if (options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) {
119               // add 1 pixel due to rounding problems...
120               offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + options.offsetBottom * 1 + 1;
121             } else {
122               offsetBottom = options.offsetBottom * 1;
123             }
124           }
125         };
126         // Private methods
127         function getRequiredAffixClass(unpin, position, elementHeight) {
128           var scrollTop = getScrollTop();
129           var scrollHeight = getScrollHeight();
130           if (scrollTop <= offsetTop) {
131             return 'top';
132           } else if (unpin !== null && scrollTop + unpin <= position.top) {
133             return 'middle';
134           } else if (offsetBottom !== null && position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom) {
135             return 'bottom';
136           } else {
137             return 'middle';
138           }
139         }
140         function getScrollTop() {
141           return targetEl[0] === $window ? $window.pageYOffset : targetEl[0] === $window;
142         }
143         function getScrollHeight() {
144           return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;
145         }
146         $affix.init();
147         return $affix;
148       }
149       return AffixFactory;
150     }
151   ];
152 }).directive('bsAffix', [
153   '$affix',
154   '$window',
155   function ($affix, $window) {
156     return {
157       restrict: 'EAC',
158       require: '^?bsAffixTarget',
159       link: function postLink(scope, element, attr, affixTarget) {
160         var options = {
161             scope: scope,
162             offsetTop: 'auto',
163             target: affixTarget ? affixTarget.$element : angular.element($window)
164           };
165         angular.forEach([
166           'offsetTop',
167           'offsetBottom',
168           'offsetParent',
169           'offsetUnpin'
170         ], function (key) {
171           if (angular.isDefined(attr[key]))
172             options[key] = attr[key];
173         });
174         var affix = $affix(element, options);
175         scope.$on('$destroy', function () {
176           options = null;
177           affix = null;
178         });
179       }
180     };
181   }
182 ]).directive('bsAffixTarget', function () {
183   return {
184     controller: [
185       '$element',
186       function ($element) {
187         this.$element = $element;
188       }
189     ]
190   };
191 });