Skip to content
This repository was archived by the owner on Sep 2, 2020. It is now read-only.

Commit d8781a0

Browse files
committed
feat(affix): refactor component
1 parent 5c590cc commit d8781a0

File tree

8 files changed

+283
-169
lines changed

8 files changed

+283
-169
lines changed

Gruntfile.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,20 @@ module.exports = function(grunt) {
149149
stripBanners: true
150150
},
151151
dist: {
152-
src: ['<%= yo.src %>/<%= pkg.name %>.js'],
153-
dest: '<%= yo.dist %>/<%= pkg.name %>.js'
152+
options: {
153+
// Replace all 'use strict' statements in the code with a single one at the top
154+
banner: '(function(window, document, undefined) {\n\'use strict\';\n',
155+
footer: '\n})(window, document);\n',
156+
process: function(src, filepath) {
157+
return '// Source: ' + filepath + '\n' +
158+
src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1');
159+
}
160+
},
161+
files: {
162+
'<%= yo.dist %>/<%= pkg.name %>.js': [
163+
'<%= yo.src %>/{,*/}*.js'
164+
]
165+
}
154166
}
155167
},
156168
uglify: {

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ The affix behavior enables dynamic pinning of a DOM element during page scrollin
99

1010
+ Or download the [production version][min] or the [development version][max].
1111

12-
[min]: https://raw.github.com/mgcrea/jquery-bootstrap-affix/master/dist/angular-bootstrap-affix.min.js
13-
[max]: https://raw.github.com/mgcrea/jquery-bootstrap-affix/master/dist/angular-bootstrap-affix.js
12+
[min]: https://raw.github.com/mgcrea/angular-bootstrap-affix/master/dist/angular-bootstrap-affix.min.js
13+
[max]: https://raw.github.com/mgcrea/angular-bootstrap-affix/master/dist/angular-bootstrap-affix.js
1414

1515
In your web page:
1616

1717
```html
1818
<script src="bower_components/angular/angular.js"></script>
19-
<script src="bower_components/angular-jquery/dist/angular-jquery.min.js"></script>
19+
<script src="bower_components/angular-jqlite/dist/angular-jqlite.min.js"></script>
2020
<script src="bower_components/angular-bootstrap-affix/dist/angular-bootstrap-affix.min.js"></script>
2121
<script src="scripts/app.js"></script>
2222
```

dist/angular-bootstrap-affix.js

Lines changed: 0 additions & 56 deletions
This file was deleted.

dist/angular-bootstrap-affix.min.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/affix.js

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

src/bootstrap-affix.js

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)