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