| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- ;(function( win, $ ) {
- function featureTest( property, value, noPrefixes ) {
- // Thanks Modernizr! https://github.com/phistuck/Modernizr/commit/3fb7217f5f8274e2f11fe6cfeda7cfaf9948a1f5
- var prop = property + ':',
- el = document.createElement( 'test' ),
- mStyle = el.style;
- if( !noPrefixes ) {
- mStyle.cssText = prop + [ '-webkit-', '-moz-', '-ms-', '-o-', '' ].join( value + ';' + prop ) + value + ';';
- } else {
- mStyle.cssText = prop + value;
- }
- return mStyle[ property ].indexOf( value ) !== -1;
- }
- function getPx( unit ) {
- return parseInt( unit, 10 ) || 0;
- }
- var uniqueIdCounter = 0;
- var S = {
- classes: {
- plugin: 'fixedsticky',
- active: 'fixedsticky-on',
- inactive: 'fixedsticky-off',
- clone: 'fixedsticky-dummy',
- withoutFixedFixed: 'fixedsticky-withoutfixedfixed'
- },
- keys: {
- offset: 'fixedStickyOffset',
- position: 'fixedStickyPosition',
- id: 'fixedStickyId'
- },
- tests: {
- sticky: featureTest( 'position', 'sticky' ),
- fixed: featureTest( 'position', 'fixed', true )
- },
- // Thanks jQuery!
- getScrollTop: function() {
- var prop = 'pageYOffset',
- method = 'scrollTop';
- return win ? (prop in win) ? win[ prop ] :
- win.document.documentElement[ method ] :
- win.document.body[ method ];
- },
- bypass: function() {
- // Check native sticky, check fixed and if fixed-fixed is also included on the page and is supported
- return ( S.tests.sticky && !S.optOut ) ||
- !S.tests.fixed ||
- win.FixedFixed && !$( win.document.documentElement ).hasClass( 'fixed-supported' );
- },
- update: function( el ) {
- if( !el.offsetWidth ) { return; }
- var $el = $( el ),
- height = $el.outerHeight(),
- initialOffset = $el.data( S.keys.offset ),
- scroll = S.getScrollTop(),
- isAlreadyOn = $el.is( '.' + S.classes.active ),
- toggle = function( turnOn ) {
- $el[ turnOn ? 'addClass' : 'removeClass' ]( S.classes.active )
- [ !turnOn ? 'addClass' : 'removeClass' ]( S.classes.inactive );
- },
- viewportHeight = $( window ).height(),
- position = $el.data( S.keys.position ),
- skipSettingToFixed,
- elTop,
- elBottom,
- $parent = $el.parent(),
- parentOffset = $parent.offset().top,
- parentHeight = $parent.outerHeight();
- if( initialOffset === undefined ) {
- initialOffset = $el.offset().top;
- $el.data( S.keys.offset, initialOffset );
- $el.after( $( '<div>' ).addClass( S.classes.clone ).height( height ) );
- } else {
- $el.next( '.' + S.classes.clone ).height( height );
- }
- if( !position ) {
- // Some browsers require fixed/absolute to report accurate top/left values.
- skipSettingToFixed = $el.css( 'top' ) !== 'auto' || $el.css( 'bottom' ) !== 'auto';
- if( !skipSettingToFixed ) {
- $el.css( 'position', 'fixed' );
- }
- position = {
- top: $el.css( 'top' ) !== 'auto',
- bottom: $el.css( 'bottom' ) !== 'auto'
- };
- if( !skipSettingToFixed ) {
- $el.css( 'position', '' );
- }
- $el.data( S.keys.position, position );
- }
- function isFixedToTop() {
- var offsetTop = scroll + elTop;
- // Initial Offset Top
- return initialOffset < offsetTop &&
- // Container Bottom
- offsetTop + height <= parentOffset + parentHeight;
- }
- function isFixedToBottom() {
- // Initial Offset Top + Height
- return initialOffset + ( height || 0 ) > scroll + viewportHeight - elBottom &&
- // Container Top
- scroll + viewportHeight - elBottom >= parentOffset + ( height || 0 );
- }
- elTop = getPx( $el.css( 'top' ) );
- elBottom = getPx( $el.css( 'bottom' ) );
- if( position.top && isFixedToTop() || position.bottom && isFixedToBottom() ) {
- if( !isAlreadyOn ) {
- toggle( true );
- }
- } else {
- if( isAlreadyOn ) {
- toggle( false );
- }
- }
- },
- destroy: function( el ) {
- var $el = $( el );
- if (S.bypass()) {
- return $el;
- }
- return $el.each(function() {
- var $this = $( this );
- var id = $this.data( S.keys.id );
- $( win ).unbind( '.fixedsticky' + id );
- $this
- .removeData( [ S.keys.offset, S.keys.position, S.keys.id ] )
- .removeClass( S.classes.active )
- .removeClass( S.classes.inactive )
- .next( '.' + S.classes.clone ).remove();
- });
- },
- init: function( el ) {
- var $el = $( el );
- if( S.bypass() ) {
- return $el;
- }
- return $el.each(function() {
- var _this = this;
- var id = uniqueIdCounter++;
- $( this ).data( S.keys.id, id );
- $( win ).bind( 'scroll.fixedsticky' + id, function() {
- S.update( _this );
- }).trigger( 'scroll.fixedsticky' + id );
- $( win ).bind( 'resize.fixedsticky' + id , function() {
- if( $el.is( '.' + S.classes.active ) ) {
- S.update( _this );
- }
- });
- });
- }
- };
- win.FixedSticky = S;
- // Plugin
- $.fn.fixedsticky = function( method ) {
- if ( typeof S[ method ] === 'function') {
- return S[ method ].call( S, this);
- } else if ( typeof method === 'object' || ! method ) {
- return S.init.call( S, this );
- } else {
- throw new Error( 'Method `' + method + '` does not exist on jQuery.fixedsticky' );
- }
- };
- // Add fallback when fixed-fixed is not available.
- if( !win.FixedFixed ) {
- $( win.document.documentElement ).addClass( S.classes.withoutFixedFixed );
- }
- })( window, jQuery );
|