1;(function( win, $ ) { 2 3 function featureTest( property, value, noPrefixes ) { 4 5 if (window.forceFixedStickyNoNative && value == 'sticky') return false; 6 7 // Thanks Modernizr! https://github.com/phistuck/Modernizr/commit/3fb7217f5f8274e2f11fe6cfeda7cfaf9948a1f5 8 var prop = property + ':', 9 el = document.createElement( 'test' ), 10 mStyle = el.style; 11 12 if( !noPrefixes ) { 13 mStyle.cssText = prop + [ '-webkit-', '-moz-', '-ms-', '-o-', '' ].join( value + ';' + prop ) + value + ';'; 14 } else { 15 mStyle.cssText = prop + value; 16 } 17 return mStyle[ property ].indexOf( value ) !== -1; 18 } 19 20 function getPx( unit ) { 21 return parseInt( unit, 10 ) || 0; 22 } 23 24 var uniqueIdCounter = 0; 25 26 var S = { 27 classes: { 28 plugin: 'fixedsticky', 29 active: 'fixedsticky-on', 30 inactive: 'fixedsticky-off', 31 clone: 'fixedsticky-dummy', 32 withoutFixedFixed: 'fixedsticky-withoutfixedfixed' 33 }, 34 keys: { 35 offset: 'fixedStickyOffset', 36 position: 'fixedStickyPosition', 37 id: 'fixedStickyId' 38 }, 39 tests: { 40 sticky: featureTest( 'position', 'sticky' ), 41 fixed: featureTest( 'position', 'fixed', true ) 42 }, 43 // Thanks jQuery! 44 getScrollTop: function() { 45 var prop = 'pageYOffset', 46 method = 'scrollTop'; 47 return win ? (prop in win) ? win[ prop ] : 48 win.document.documentElement[ method ] : 49 win.document.body[ method ]; 50 }, 51 bypass: function() { 52 // Check native sticky, check fixed and if fixed-fixed is also included on the page and is supported 53 return ( S.tests.sticky && !S.optOut ) || 54 !S.tests.fixed || 55 win.FixedFixed && !$( win.document.documentElement ).hasClass( 'fixed-supported' ); 56 }, 57 update: function( el ) { 58 if( !el.offsetWidth ) { return; } 59 60 var $el = $( el ), 61 height = $el.outerHeight(), 62 initialOffset = $el.data( S.keys.offset ), 63 scroll = S.getScrollTop(), 64 isAlreadyOn = $el.is( '.' + S.classes.active ), 65 toggle = function( turnOn ) { 66 $el[ turnOn ? 'addClass' : 'removeClass' ]( S.classes.active ) 67 [ !turnOn ? 'addClass' : 'removeClass' ]( S.classes.inactive ); 68 }, 69 viewportHeight = $( window ).height(), 70 position = $el.data( S.keys.position ), 71 skipSettingToFixed, 72 elTop, 73 elBottom, 74 $parent = $el.parent(), 75 parentOffset = $parent.offset().top, 76 parentHeight = $parent.outerHeight(); 77 78 if( initialOffset === undefined ) { 79 initialOffset = $el.offset().top; 80 $el.data( S.keys.offset, initialOffset ); 81 $el.after( $( '<div>' ).addClass( S.classes.clone ).height( height ) ); 82 } 83 84 if( !position ) { 85 // Some browsers require fixed/absolute to report accurate top/left values. 86 skipSettingToFixed = $el.css( 'top' ) !== 'auto' || $el.css( 'bottom' ) !== 'auto'; 87 88 if( !skipSettingToFixed ) { 89 $el.css( 'position', 'fixed' ); 90 } 91 92 position = { 93 top: $el.css( 'top' ) !== 'auto', 94 bottom: $el.css( 'bottom' ) !== 'auto' 95 }; 96 97 if( !skipSettingToFixed ) { 98 $el.css( 'position', '' ); 99 } 100 101 $el.data( S.keys.position, position ); 102 } 103 104 function isFixedToTop() { 105 var offsetTop = scroll + elTop; 106 107 // Initial Offset Top 108 return initialOffset < offsetTop && 109 // Container Bottom 110 offsetTop + height <= parentOffset + parentHeight; 111 } 112 113 function isFixedToBottom() { 114 // Initial Offset Top + Height 115 return initialOffset + ( height || 0 ) > scroll + viewportHeight - elBottom && 116 // Container Top 117 scroll + viewportHeight - elBottom >= parentOffset + ( height || 0 ); 118 } 119 120 elTop = getPx( $el.css( 'top' ) ); 121 elBottom = getPx( $el.css( 'bottom' ) ); 122 123 if( position.top && isFixedToTop() || position.bottom && isFixedToBottom() ) { 124 if( !isAlreadyOn ) { 125 toggle( true ); 126 } 127 } else { 128 if( isAlreadyOn ) { 129 toggle( false ); 130 } 131 } 132 }, 133 destroy: function( el ) { 134 var $el = $( el ); 135 if (S.bypass()) { 136 return; 137 } 138 139 return $el.each(function() { 140 var $this = $( this ); 141 var id = $this.data( S.keys.id ); 142 $( win ).unbind( '.fixedsticky' + id ); 143 144 $this 145 .removeData( [ S.keys.offset, S.keys.position, S.keys.id ] ) 146 .removeClass( S.classes.active ) 147 .removeClass( S.classes.inactive ) 148 .next( '.' + S.classes.clone ).remove(); 149 }); 150 }, 151 init: function( el ) { 152 var $el = $( el ); 153 154 if( S.bypass() ) { 155 return; 156 } 157 158 return $el.each(function() { 159 var _this = this; 160 var id = uniqueIdCounter++;
161 $( this ).data( S.keys.id, id ); 162 163 $( win ).bind( 'scroll.fixedsticky' + id, function() { 164 S.update( _this ); 165 }).trigger( 'scroll.fixedsticky' + id ); 166 167 $( win ).bind( 'resize.fixedsticky' + id , function() { 168 if( $el.is( '.' + S.classes.active ) ) { 169 S.update( _this ); 170 } 171 }); 172 }); 173 } 174 }; 175 176 win.FixedSticky = S; 177 178 // Plugin 179 $.fn.fixedsticky = function( method ) { 180 if ( typeof S[ method ] === 'function') { 181 return S[ method ].call( S, this); 182 } else if ( typeof method === 'object' || ! method ) { 183 return S.init.call( S, this ); 184 } else { 185 throw new Error( 'Method `' + method + '` does not exist on jQuery.fixedsticky' ); 186 } 187 }; 188 189 // Add fallback when fixed-fixed is not available. 190 if( !win.FixedFixed ) { 191 $( win.document.documentElement ).addClass( S.classes.withoutFixedFixed ); 192 } 193 194})( window, jQuery );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.