1
+ /**
2
+ * angular-strap
3
+ * @version v2.0.0-beta.1 - 2014-01-07
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' , [ 'mgcrea.ngStrap.jqlite.dimensions' ] ) . provider ( '$affix' , function ( ) {
10
+ var defaults = this . defaults = { offsetTop : 'auto' } ;
11
+ this . $get = [
12
+ '$window' ,
13
+ 'dimensions' ,
14
+ function ( $window , dimensions ) {
15
+ var windowEl = angular . element ( $window ) ;
16
+ var bodyEl = angular . element ( $window . document . body ) ;
17
+ function AffixFactory ( element , config ) {
18
+ var $affix = { } ;
19
+ var options = angular . extend ( { } , defaults , config ) ;
20
+ var reset = 'affix affix-top affix-bottom' , initialAffixTop = 0 , initialOffsetTop = 0 , affixed = null , unpin = null ;
21
+ var parent = element . parent ( ) ;
22
+ if ( options . offsetParent ) {
23
+ if ( options . offsetParent . match ( / ^ \d + $ / ) ) {
24
+ for ( var i = 0 ; i < options . offsetParent * 1 - 1 ; i ++ ) {
25
+ parent = parent . parent ( ) ;
26
+ }
27
+ } else {
28
+ parent = angular . element ( options . offsetParent ) ;
29
+ }
30
+ }
31
+ var offsetTop = 0 ;
32
+ if ( options . offsetTop ) {
33
+ if ( options . offsetTop === 'auto' ) {
34
+ options . offsetTop = '+0' ;
35
+ }
36
+ if ( options . offsetTop . match ( / ^ [ - + ] \d + $ / ) ) {
37
+ initialAffixTop -= options . offsetTop * 1 ;
38
+ if ( options . offsetParent ) {
39
+ offsetTop = dimensions . offset ( parent [ 0 ] ) . top + options . offsetTop * 1 ;
40
+ } else {
41
+ offsetTop = dimensions . offset ( element [ 0 ] ) . top - dimensions . css ( element [ 0 ] , 'marginTop' , true ) + options . offsetTop * 1 ;
42
+ }
43
+ } else {
44
+ offsetTop = options . offsetTop * 1 ;
45
+ }
46
+ }
47
+ var offsetBottom = 0 ;
48
+ if ( options . offsetBottom ) {
49
+ if ( options . offsetParent && options . offsetBottom . match ( / ^ [ - + ] \d + $ / ) ) {
50
+ offsetBottom = $window . document . body . scrollHeight - ( dimensions . offset ( parent [ 0 ] ) . top + dimensions . height ( parent [ 0 ] ) ) + options . offsetBottom * 1 + 1 ;
51
+ } else {
52
+ offsetBottom = options . offsetBottom * 1 ;
53
+ }
54
+ }
55
+ $affix . init = function ( ) {
56
+ initialOffsetTop = dimensions . offset ( element [ 0 ] ) . top + initialAffixTop ;
57
+ windowEl . on ( 'scroll' , this . checkPosition ) ;
58
+ windowEl . on ( 'click' , this . checkPositionWithEventLoop ) ;
59
+ this . checkPosition ( ) ;
60
+ this . checkPositionWithEventLoop ( ) ;
61
+ } ;
62
+ $affix . destroy = function ( ) {
63
+ windowEl . off ( 'scroll' , this . checkPosition ) ;
64
+ windowEl . off ( 'click' , this . checkPositionWithEventLoop ) ;
65
+ } ;
66
+ $affix . checkPositionWithEventLoop = function ( ) {
67
+ setTimeout ( this . checkPosition , 1 ) ;
68
+ } ;
69
+ $affix . checkPosition = function ( ) {
70
+ var scrollTop = $window . pageYOffset ;
71
+ var position = dimensions . offset ( element [ 0 ] ) ;
72
+ var elementHeight = dimensions . height ( element [ 0 ] ) ;
73
+ var affix = getRequiredAffixClass ( unpin , position , elementHeight ) ;
74
+ if ( affixed === affix )
75
+ return ;
76
+ affixed = affix ;
77
+ element . removeClass ( reset ) . addClass ( 'affix' + ( affix !== 'middle' ? '-' + affix : '' ) ) ;
78
+ if ( affix === 'top' ) {
79
+ unpin = null ;
80
+ element . css ( 'position' , options . offsetParent ? '' : 'relative' ) ;
81
+ element . css ( 'top' , '' ) ;
82
+ } else if ( affix === 'bottom' ) {
83
+ if ( options . offsetUnpin ) {
84
+ unpin = - ( options . offsetUnpin * 1 ) ;
85
+ } else {
86
+ unpin = position . top - scrollTop ;
87
+ }
88
+ element . css ( 'position' , options . offsetParent ? '' : 'relative' ) ;
89
+ element . css ( 'top' , options . offsetParent ? '' : bodyEl [ 0 ] . offsetHeight - offsetBottom - elementHeight - initialOffsetTop + 'px' ) ;
90
+ } else {
91
+ unpin = null ;
92
+ element . css ( 'position' , 'fixed' ) ;
93
+ element . css ( 'top' , initialAffixTop + 'px' ) ;
94
+ }
95
+ } ;
96
+ function getRequiredAffixClass ( unpin , position , elementHeight ) {
97
+ var scrollTop = $window . pageYOffset ;
98
+ var scrollHeight = $window . document . body . scrollHeight ;
99
+ if ( scrollTop <= offsetTop ) {
100
+ return 'top' ;
101
+ } else if ( unpin !== null && scrollTop + unpin <= position . top ) {
102
+ return 'middle' ;
103
+ } else if ( offsetBottom !== null && position . top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom ) {
104
+ return 'bottom' ;
105
+ } else {
106
+ return 'middle' ;
107
+ }
108
+ }
109
+ $affix . init ( ) ;
110
+ return $affix ;
111
+ }
112
+ return AffixFactory ;
113
+ }
114
+ ] ;
115
+ } ) . directive ( 'bsAffix' , [
116
+ '$affix' ,
117
+ 'dimensions' ,
118
+ function ( $affix , dimensions ) {
119
+ return {
120
+ restrict : 'EAC' ,
121
+ link : function postLink ( scope , element , attr ) {
122
+ var options = {
123
+ scope : scope ,
124
+ offsetTop : 'auto'
125
+ } ;
126
+ angular . forEach ( [
127
+ 'offsetTop' ,
128
+ 'offsetBottom' ,
129
+ 'offsetParent' ,
130
+ 'offsetUnpin'
131
+ ] , function ( key ) {
132
+ if ( angular . isDefined ( attr [ key ] ) )
133
+ options [ key ] = attr [ key ] ;
134
+ } ) ;
135
+ var affix = $affix ( element , options ) ;
136
+ scope . $on ( '$destroy' , function ( ) {
137
+ options = null ;
138
+ affix = null ;
139
+ } ) ;
140
+ }
141
+ } ;
142
+ }
143
+ ] ) ;
0 commit comments