| @@ 16697-17645 (lines=949) @@ | ||
| 16694 | * |
|
| 16695 | */ |
|
| 16696 | ||
| 16697 | ;(function ($, window, document, undefined) { |
|
| 16698 | ||
| 16699 | "use strict"; |
|
| 16700 | ||
| 16701 | window = (typeof window != 'undefined' && window.Math == Math) |
|
| 16702 | ? window |
|
| 16703 | : (typeof self != 'undefined' && self.Math == Math) |
|
| 16704 | ? self |
|
| 16705 | : Function('return this')() |
|
| 16706 | ; |
|
| 16707 | ||
| 16708 | $.fn.sticky = function(parameters) { |
|
| 16709 | var |
|
| 16710 | $allModules = $(this), |
|
| 16711 | moduleSelector = $allModules.selector || '', |
|
| 16712 | ||
| 16713 | time = new Date().getTime(), |
|
| 16714 | performance = [], |
|
| 16715 | ||
| 16716 | query = arguments[0], |
|
| 16717 | methodInvoked = (typeof query == 'string'), |
|
| 16718 | queryArguments = [].slice.call(arguments, 1), |
|
| 16719 | returnedValue |
|
| 16720 | ; |
|
| 16721 | ||
| 16722 | $allModules |
|
| 16723 | .each(function() { |
|
| 16724 | var |
|
| 16725 | settings = ( $.isPlainObject(parameters) ) |
|
| 16726 | ? $.extend(true, {}, $.fn.sticky.settings, parameters) |
|
| 16727 | : $.extend({}, $.fn.sticky.settings), |
|
| 16728 | ||
| 16729 | className = settings.className, |
|
| 16730 | namespace = settings.namespace, |
|
| 16731 | error = settings.error, |
|
| 16732 | ||
| 16733 | eventNamespace = '.' + namespace, |
|
| 16734 | moduleNamespace = 'module-' + namespace, |
|
| 16735 | ||
| 16736 | $module = $(this), |
|
| 16737 | $window = $(window), |
|
| 16738 | $scroll = $(settings.scrollContext), |
|
| 16739 | $container, |
|
| 16740 | $context, |
|
| 16741 | ||
| 16742 | selector = $module.selector || '', |
|
| 16743 | instance = $module.data(moduleNamespace), |
|
| 16744 | ||
| 16745 | requestAnimationFrame = window.requestAnimationFrame |
|
| 16746 | || window.mozRequestAnimationFrame |
|
| 16747 | || window.webkitRequestAnimationFrame |
|
| 16748 | || window.msRequestAnimationFrame |
|
| 16749 | || function(callback) { setTimeout(callback, 0); }, |
|
| 16750 | ||
| 16751 | element = this, |
|
| 16752 | ||
| 16753 | documentObserver, |
|
| 16754 | observer, |
|
| 16755 | module |
|
| 16756 | ; |
|
| 16757 | ||
| 16758 | module = { |
|
| 16759 | ||
| 16760 | initialize: function() { |
|
| 16761 | ||
| 16762 | module.determineContainer(); |
|
| 16763 | module.determineContext(); |
|
| 16764 | module.verbose('Initializing sticky', settings, $container); |
|
| 16765 | ||
| 16766 | module.save.positions(); |
|
| 16767 | module.checkErrors(); |
|
| 16768 | module.bind.events(); |
|
| 16769 | ||
| 16770 | if(settings.observeChanges) { |
|
| 16771 | module.observeChanges(); |
|
| 16772 | } |
|
| 16773 | module.instantiate(); |
|
| 16774 | }, |
|
| 16775 | ||
| 16776 | instantiate: function() { |
|
| 16777 | module.verbose('Storing instance of module', module); |
|
| 16778 | instance = module; |
|
| 16779 | $module |
|
| 16780 | .data(moduleNamespace, module) |
|
| 16781 | ; |
|
| 16782 | }, |
|
| 16783 | ||
| 16784 | destroy: function() { |
|
| 16785 | module.verbose('Destroying previous instance'); |
|
| 16786 | module.reset(); |
|
| 16787 | if(documentObserver) { |
|
| 16788 | documentObserver.disconnect(); |
|
| 16789 | } |
|
| 16790 | if(observer) { |
|
| 16791 | observer.disconnect(); |
|
| 16792 | } |
|
| 16793 | $window |
|
| 16794 | .off('load' + eventNamespace, module.event.load) |
|
| 16795 | .off('resize' + eventNamespace, module.event.resize) |
|
| 16796 | ; |
|
| 16797 | $scroll |
|
| 16798 | .off('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 16799 | ; |
|
| 16800 | $module.removeData(moduleNamespace); |
|
| 16801 | }, |
|
| 16802 | ||
| 16803 | observeChanges: function() { |
|
| 16804 | if('MutationObserver' in window) { |
|
| 16805 | documentObserver = new MutationObserver(module.event.documentChanged); |
|
| 16806 | observer = new MutationObserver(module.event.changed); |
|
| 16807 | documentObserver.observe(document, { |
|
| 16808 | childList : true, |
|
| 16809 | subtree : true |
|
| 16810 | }); |
|
| 16811 | observer.observe(element, { |
|
| 16812 | childList : true, |
|
| 16813 | subtree : true |
|
| 16814 | }); |
|
| 16815 | observer.observe($context[0], { |
|
| 16816 | childList : true, |
|
| 16817 | subtree : true |
|
| 16818 | }); |
|
| 16819 | module.debug('Setting up mutation observer', observer); |
|
| 16820 | } |
|
| 16821 | }, |
|
| 16822 | ||
| 16823 | determineContainer: function() { |
|
| 16824 | if(settings.container) { |
|
| 16825 | $container = $(settings.container); |
|
| 16826 | } |
|
| 16827 | else { |
|
| 16828 | $container = $module.offsetParent(); |
|
| 16829 | } |
|
| 16830 | }, |
|
| 16831 | ||
| 16832 | determineContext: function() { |
|
| 16833 | if(settings.context) { |
|
| 16834 | $context = $(settings.context); |
|
| 16835 | } |
|
| 16836 | else { |
|
| 16837 | $context = $container; |
|
| 16838 | } |
|
| 16839 | if($context.length === 0) { |
|
| 16840 | module.error(error.invalidContext, settings.context, $module); |
|
| 16841 | return; |
|
| 16842 | } |
|
| 16843 | }, |
|
| 16844 | ||
| 16845 | checkErrors: function() { |
|
| 16846 | if( module.is.hidden() ) { |
|
| 16847 | module.error(error.visible, $module); |
|
| 16848 | } |
|
| 16849 | if(module.cache.element.height > module.cache.context.height) { |
|
| 16850 | module.reset(); |
|
| 16851 | module.error(error.elementSize, $module); |
|
| 16852 | return; |
|
| 16853 | } |
|
| 16854 | }, |
|
| 16855 | ||
| 16856 | bind: { |
|
| 16857 | events: function() { |
|
| 16858 | $window |
|
| 16859 | .on('load' + eventNamespace, module.event.load) |
|
| 16860 | .on('resize' + eventNamespace, module.event.resize) |
|
| 16861 | ; |
|
| 16862 | // pub/sub pattern |
|
| 16863 | $scroll |
|
| 16864 | .off('scroll' + eventNamespace) |
|
| 16865 | .on('scroll' + eventNamespace, module.event.scroll) |
|
| 16866 | .on('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 16867 | ; |
|
| 16868 | } |
|
| 16869 | }, |
|
| 16870 | ||
| 16871 | event: { |
|
| 16872 | changed: function(mutations) { |
|
| 16873 | clearTimeout(module.timer); |
|
| 16874 | module.timer = setTimeout(function() { |
|
| 16875 | module.verbose('DOM tree modified, updating sticky menu', mutations); |
|
| 16876 | module.refresh(); |
|
| 16877 | }, 100); |
|
| 16878 | }, |
|
| 16879 | documentChanged: function(mutations) { |
|
| 16880 | [].forEach.call(mutations, function(mutation) { |
|
| 16881 | if(mutation.removedNodes) { |
|
| 16882 | [].forEach.call(mutation.removedNodes, function(node) { |
|
| 16883 | if(node == element || $(node).find(element).length > 0) { |
|
| 16884 | module.debug('Element removed from DOM, tearing down events'); |
|
| 16885 | module.destroy(); |
|
| 16886 | } |
|
| 16887 | }); |
|
| 16888 | } |
|
| 16889 | }); |
|
| 16890 | }, |
|
| 16891 | load: function() { |
|
| 16892 | module.verbose('Page contents finished loading'); |
|
| 16893 | requestAnimationFrame(module.refresh); |
|
| 16894 | }, |
|
| 16895 | resize: function() { |
|
| 16896 | module.verbose('Window resized'); |
|
| 16897 | requestAnimationFrame(module.refresh); |
|
| 16898 | }, |
|
| 16899 | scroll: function() { |
|
| 16900 | requestAnimationFrame(function() { |
|
| 16901 | $scroll.triggerHandler('scrollchange' + eventNamespace, $scroll.scrollTop() ); |
|
| 16902 | }); |
|
| 16903 | }, |
|
| 16904 | scrollchange: function(event, scrollPosition) { |
|
| 16905 | module.stick(scrollPosition); |
|
| 16906 | settings.onScroll.call(element); |
|
| 16907 | } |
|
| 16908 | }, |
|
| 16909 | ||
| 16910 | refresh: function(hardRefresh) { |
|
| 16911 | module.reset(); |
|
| 16912 | if(!settings.context) { |
|
| 16913 | module.determineContext(); |
|
| 16914 | } |
|
| 16915 | if(hardRefresh) { |
|
| 16916 | module.determineContainer(); |
|
| 16917 | } |
|
| 16918 | module.save.positions(); |
|
| 16919 | module.stick(); |
|
| 16920 | settings.onReposition.call(element); |
|
| 16921 | }, |
|
| 16922 | ||
| 16923 | supports: { |
|
| 16924 | sticky: function() { |
|
| 16925 | var |
|
| 16926 | $element = $('<div/>'), |
|
| 16927 | element = $element[0] |
|
| 16928 | ; |
|
| 16929 | $element.addClass(className.supported); |
|
| 16930 | return($element.css('position').match('sticky')); |
|
| 16931 | } |
|
| 16932 | }, |
|
| 16933 | ||
| 16934 | save: { |
|
| 16935 | lastScroll: function(scroll) { |
|
| 16936 | module.lastScroll = scroll; |
|
| 16937 | }, |
|
| 16938 | elementScroll: function(scroll) { |
|
| 16939 | module.elementScroll = scroll; |
|
| 16940 | }, |
|
| 16941 | positions: function() { |
|
| 16942 | var |
|
| 16943 | scrollContext = { |
|
| 16944 | height : $scroll.height() |
|
| 16945 | }, |
|
| 16946 | element = { |
|
| 16947 | margin: { |
|
| 16948 | top : parseInt($module.css('margin-top'), 10), |
|
| 16949 | bottom : parseInt($module.css('margin-bottom'), 10), |
|
| 16950 | }, |
|
| 16951 | offset : $module.offset(), |
|
| 16952 | width : $module.outerWidth(), |
|
| 16953 | height : $module.outerHeight() |
|
| 16954 | }, |
|
| 16955 | context = { |
|
| 16956 | offset : $context.offset(), |
|
| 16957 | height : $context.outerHeight() |
|
| 16958 | }, |
|
| 16959 | container = { |
|
| 16960 | height: $container.outerHeight() |
|
| 16961 | } |
|
| 16962 | ; |
|
| 16963 | if( !module.is.standardScroll() ) { |
|
| 16964 | module.debug('Non-standard scroll. Removing scroll offset from element offset'); |
|
| 16965 | ||
| 16966 | scrollContext.top = $scroll.scrollTop(); |
|
| 16967 | scrollContext.left = $scroll.scrollLeft(); |
|
| 16968 | ||
| 16969 | element.offset.top += scrollContext.top; |
|
| 16970 | context.offset.top += scrollContext.top; |
|
| 16971 | element.offset.left += scrollContext.left; |
|
| 16972 | context.offset.left += scrollContext.left; |
|
| 16973 | } |
|
| 16974 | module.cache = { |
|
| 16975 | fits : ( (element.height + settings.offset) <= scrollContext.height), |
|
| 16976 | sameHeight : (element.height == context.height), |
|
| 16977 | scrollContext : { |
|
| 16978 | height : scrollContext.height |
|
| 16979 | }, |
|
| 16980 | element: { |
|
| 16981 | margin : element.margin, |
|
| 16982 | top : element.offset.top - element.margin.top, |
|
| 16983 | left : element.offset.left, |
|
| 16984 | width : element.width, |
|
| 16985 | height : element.height, |
|
| 16986 | bottom : element.offset.top + element.height |
|
| 16987 | }, |
|
| 16988 | context: { |
|
| 16989 | top : context.offset.top, |
|
| 16990 | height : context.height, |
|
| 16991 | bottom : context.offset.top + context.height |
|
| 16992 | } |
|
| 16993 | }; |
|
| 16994 | module.set.containerSize(); |
|
| 16995 | ||
| 16996 | module.stick(); |
|
| 16997 | module.debug('Caching element positions', module.cache); |
|
| 16998 | } |
|
| 16999 | }, |
|
| 17000 | ||
| 17001 | get: { |
|
| 17002 | direction: function(scroll) { |
|
| 17003 | var |
|
| 17004 | direction = 'down' |
|
| 17005 | ; |
|
| 17006 | scroll = scroll || $scroll.scrollTop(); |
|
| 17007 | if(module.lastScroll !== undefined) { |
|
| 17008 | if(module.lastScroll < scroll) { |
|
| 17009 | direction = 'down'; |
|
| 17010 | } |
|
| 17011 | else if(module.lastScroll > scroll) { |
|
| 17012 | direction = 'up'; |
|
| 17013 | } |
|
| 17014 | } |
|
| 17015 | return direction; |
|
| 17016 | }, |
|
| 17017 | scrollChange: function(scroll) { |
|
| 17018 | scroll = scroll || $scroll.scrollTop(); |
|
| 17019 | return (module.lastScroll) |
|
| 17020 | ? (scroll - module.lastScroll) |
|
| 17021 | : 0 |
|
| 17022 | ; |
|
| 17023 | }, |
|
| 17024 | currentElementScroll: function() { |
|
| 17025 | if(module.elementScroll) { |
|
| 17026 | return module.elementScroll; |
|
| 17027 | } |
|
| 17028 | return ( module.is.top() ) |
|
| 17029 | ? Math.abs(parseInt($module.css('top'), 10)) || 0 |
|
| 17030 | : Math.abs(parseInt($module.css('bottom'), 10)) || 0 |
|
| 17031 | ; |
|
| 17032 | }, |
|
| 17033 | ||
| 17034 | elementScroll: function(scroll) { |
|
| 17035 | scroll = scroll || $scroll.scrollTop(); |
|
| 17036 | var |
|
| 17037 | element = module.cache.element, |
|
| 17038 | scrollContext = module.cache.scrollContext, |
|
| 17039 | delta = module.get.scrollChange(scroll), |
|
| 17040 | maxScroll = (element.height - scrollContext.height + settings.offset), |
|
| 17041 | elementScroll = module.get.currentElementScroll(), |
|
| 17042 | possibleScroll = (elementScroll + delta) |
|
| 17043 | ; |
|
| 17044 | if(module.cache.fits || possibleScroll < 0) { |
|
| 17045 | elementScroll = 0; |
|
| 17046 | } |
|
| 17047 | else if(possibleScroll > maxScroll ) { |
|
| 17048 | elementScroll = maxScroll; |
|
| 17049 | } |
|
| 17050 | else { |
|
| 17051 | elementScroll = possibleScroll; |
|
| 17052 | } |
|
| 17053 | return elementScroll; |
|
| 17054 | } |
|
| 17055 | }, |
|
| 17056 | ||
| 17057 | remove: { |
|
| 17058 | lastScroll: function() { |
|
| 17059 | delete module.lastScroll; |
|
| 17060 | }, |
|
| 17061 | elementScroll: function(scroll) { |
|
| 17062 | delete module.elementScroll; |
|
| 17063 | }, |
|
| 17064 | minimumSize: function() { |
|
| 17065 | $container |
|
| 17066 | .css('min-height', '') |
|
| 17067 | ; |
|
| 17068 | }, |
|
| 17069 | offset: function() { |
|
| 17070 | $module.css('margin-top', ''); |
|
| 17071 | } |
|
| 17072 | }, |
|
| 17073 | ||
| 17074 | set: { |
|
| 17075 | offset: function() { |
|
| 17076 | module.verbose('Setting offset on element', settings.offset); |
|
| 17077 | $module |
|
| 17078 | .css('margin-top', settings.offset) |
|
| 17079 | ; |
|
| 17080 | }, |
|
| 17081 | containerSize: function() { |
|
| 17082 | var |
|
| 17083 | tagName = $container.get(0).tagName |
|
| 17084 | ; |
|
| 17085 | if(tagName === 'HTML' || tagName == 'body') { |
|
| 17086 | // this can trigger for too many reasons |
|
| 17087 | //module.error(error.container, tagName, $module); |
|
| 17088 | module.determineContainer(); |
|
| 17089 | } |
|
| 17090 | else { |
|
| 17091 | if( Math.abs($container.outerHeight() - module.cache.context.height) > settings.jitter) { |
|
| 17092 | module.debug('Context has padding, specifying exact height for container', module.cache.context.height); |
|
| 17093 | $container.css({ |
|
| 17094 | height: module.cache.context.height |
|
| 17095 | }); |
|
| 17096 | } |
|
| 17097 | } |
|
| 17098 | }, |
|
| 17099 | minimumSize: function() { |
|
| 17100 | var |
|
| 17101 | element = module.cache.element |
|
| 17102 | ; |
|
| 17103 | $container |
|
| 17104 | .css('min-height', element.height) |
|
| 17105 | ; |
|
| 17106 | }, |
|
| 17107 | scroll: function(scroll) { |
|
| 17108 | module.debug('Setting scroll on element', scroll); |
|
| 17109 | if(module.elementScroll == scroll) { |
|
| 17110 | return; |
|
| 17111 | } |
|
| 17112 | if( module.is.top() ) { |
|
| 17113 | $module |
|
| 17114 | .css('bottom', '') |
|
| 17115 | .css('top', -scroll) |
|
| 17116 | ; |
|
| 17117 | } |
|
| 17118 | if( module.is.bottom() ) { |
|
| 17119 | $module |
|
| 17120 | .css('top', '') |
|
| 17121 | .css('bottom', scroll) |
|
| 17122 | ; |
|
| 17123 | } |
|
| 17124 | }, |
|
| 17125 | size: function() { |
|
| 17126 | if(module.cache.element.height !== 0 && module.cache.element.width !== 0) { |
|
| 17127 | element.style.setProperty('width', module.cache.element.width + 'px', 'important'); |
|
| 17128 | element.style.setProperty('height', module.cache.element.height + 'px', 'important'); |
|
| 17129 | } |
|
| 17130 | } |
|
| 17131 | }, |
|
| 17132 | ||
| 17133 | is: { |
|
| 17134 | standardScroll: function() { |
|
| 17135 | return ($scroll[0] == window); |
|
| 17136 | }, |
|
| 17137 | top: function() { |
|
| 17138 | return $module.hasClass(className.top); |
|
| 17139 | }, |
|
| 17140 | bottom: function() { |
|
| 17141 | return $module.hasClass(className.bottom); |
|
| 17142 | }, |
|
| 17143 | initialPosition: function() { |
|
| 17144 | return (!module.is.fixed() && !module.is.bound()); |
|
| 17145 | }, |
|
| 17146 | hidden: function() { |
|
| 17147 | return (!$module.is(':visible')); |
|
| 17148 | }, |
|
| 17149 | bound: function() { |
|
| 17150 | return $module.hasClass(className.bound); |
|
| 17151 | }, |
|
| 17152 | fixed: function() { |
|
| 17153 | return $module.hasClass(className.fixed); |
|
| 17154 | } |
|
| 17155 | }, |
|
| 17156 | ||
| 17157 | stick: function(scroll) { |
|
| 17158 | var |
|
| 17159 | cachedPosition = scroll || $scroll.scrollTop(), |
|
| 17160 | cache = module.cache, |
|
| 17161 | fits = cache.fits, |
|
| 17162 | sameHeight = cache.sameHeight, |
|
| 17163 | element = cache.element, |
|
| 17164 | scrollContext = cache.scrollContext, |
|
| 17165 | context = cache.context, |
|
| 17166 | offset = (module.is.bottom() && settings.pushing) |
|
| 17167 | ? settings.bottomOffset |
|
| 17168 | : settings.offset, |
|
| 17169 | scroll = { |
|
| 17170 | top : cachedPosition + offset, |
|
| 17171 | bottom : cachedPosition + offset + scrollContext.height |
|
| 17172 | }, |
|
| 17173 | direction = module.get.direction(scroll.top), |
|
| 17174 | elementScroll = (fits) |
|
| 17175 | ? 0 |
|
| 17176 | : module.get.elementScroll(scroll.top), |
|
| 17177 | ||
| 17178 | // shorthand |
|
| 17179 | doesntFit = !fits, |
|
| 17180 | elementVisible = (element.height !== 0) |
|
| 17181 | ; |
|
| 17182 | if(elementVisible && !sameHeight) { |
|
| 17183 | ||
| 17184 | if( module.is.initialPosition() ) { |
|
| 17185 | if(scroll.top >= context.bottom) { |
|
| 17186 | module.debug('Initial element position is bottom of container'); |
|
| 17187 | module.bindBottom(); |
|
| 17188 | } |
|
| 17189 | else if(scroll.top > element.top) { |
|
| 17190 | if( (element.height + scroll.top - elementScroll) >= context.bottom ) { |
|
| 17191 | module.debug('Initial element position is bottom of container'); |
|
| 17192 | module.bindBottom(); |
|
| 17193 | } |
|
| 17194 | else { |
|
| 17195 | module.debug('Initial element position is fixed'); |
|
| 17196 | module.fixTop(); |
|
| 17197 | } |
|
| 17198 | } |
|
| 17199 | ||
| 17200 | } |
|
| 17201 | else if( module.is.fixed() ) { |
|
| 17202 | ||
| 17203 | // currently fixed top |
|
| 17204 | if( module.is.top() ) { |
|
| 17205 | if( scroll.top <= element.top ) { |
|
| 17206 | module.debug('Fixed element reached top of container'); |
|
| 17207 | module.setInitialPosition(); |
|
| 17208 | } |
|
| 17209 | else if( (element.height + scroll.top - elementScroll) >= context.bottom ) { |
|
| 17210 | module.debug('Fixed element reached bottom of container'); |
|
| 17211 | module.bindBottom(); |
|
| 17212 | } |
|
| 17213 | // scroll element if larger than screen |
|
| 17214 | else if(doesntFit) { |
|
| 17215 | module.set.scroll(elementScroll); |
|
| 17216 | module.save.lastScroll(scroll.top); |
|
| 17217 | module.save.elementScroll(elementScroll); |
|
| 17218 | } |
|
| 17219 | } |
|
| 17220 | ||
| 17221 | // currently fixed bottom |
|
| 17222 | else if(module.is.bottom() ) { |
|
| 17223 | ||
| 17224 | // top edge |
|
| 17225 | if( (scroll.bottom - element.height) <= element.top) { |
|
| 17226 | module.debug('Bottom fixed rail has reached top of container'); |
|
| 17227 | module.setInitialPosition(); |
|
| 17228 | } |
|
| 17229 | // bottom edge |
|
| 17230 | else if(scroll.bottom >= context.bottom) { |
|
| 17231 | module.debug('Bottom fixed rail has reached bottom of container'); |
|
| 17232 | module.bindBottom(); |
|
| 17233 | } |
|
| 17234 | // scroll element if larger than screen |
|
| 17235 | else if(doesntFit) { |
|
| 17236 | module.set.scroll(elementScroll); |
|
| 17237 | module.save.lastScroll(scroll.top); |
|
| 17238 | module.save.elementScroll(elementScroll); |
|
| 17239 | } |
|
| 17240 | ||
| 17241 | } |
|
| 17242 | } |
|
| 17243 | else if( module.is.bottom() ) { |
|
| 17244 | if( scroll.top <= element.top ) { |
|
| 17245 | module.debug('Jumped from bottom fixed to top fixed, most likely used home/end button'); |
|
| 17246 | module.setInitialPosition(); |
|
| 17247 | } |
|
| 17248 | else { |
|
| 17249 | if(settings.pushing) { |
|
| 17250 | if(module.is.bound() && scroll.bottom <= context.bottom ) { |
|
| 17251 | module.debug('Fixing bottom attached element to bottom of browser.'); |
|
| 17252 | module.fixBottom(); |
|
| 17253 | } |
|
| 17254 | } |
|
| 17255 | else { |
|
| 17256 | if(module.is.bound() && (scroll.top <= context.bottom - element.height) ) { |
|
| 17257 | module.debug('Fixing bottom attached element to top of browser.'); |
|
| 17258 | module.fixTop(); |
|
| 17259 | } |
|
| 17260 | } |
|
| 17261 | } |
|
| 17262 | } |
|
| 17263 | } |
|
| 17264 | }, |
|
| 17265 | ||
| 17266 | bindTop: function() { |
|
| 17267 | module.debug('Binding element to top of parent container'); |
|
| 17268 | module.remove.offset(); |
|
| 17269 | $module |
|
| 17270 | .css({ |
|
| 17271 | left : '', |
|
| 17272 | top : '', |
|
| 17273 | marginBottom : '' |
|
| 17274 | }) |
|
| 17275 | .removeClass(className.fixed) |
|
| 17276 | .removeClass(className.bottom) |
|
| 17277 | .addClass(className.bound) |
|
| 17278 | .addClass(className.top) |
|
| 17279 | ; |
|
| 17280 | settings.onTop.call(element); |
|
| 17281 | settings.onUnstick.call(element); |
|
| 17282 | }, |
|
| 17283 | bindBottom: function() { |
|
| 17284 | module.debug('Binding element to bottom of parent container'); |
|
| 17285 | module.remove.offset(); |
|
| 17286 | $module |
|
| 17287 | .css({ |
|
| 17288 | left : '', |
|
| 17289 | top : '' |
|
| 17290 | }) |
|
| 17291 | .removeClass(className.fixed) |
|
| 17292 | .removeClass(className.top) |
|
| 17293 | .addClass(className.bound) |
|
| 17294 | .addClass(className.bottom) |
|
| 17295 | ; |
|
| 17296 | settings.onBottom.call(element); |
|
| 17297 | settings.onUnstick.call(element); |
|
| 17298 | }, |
|
| 17299 | ||
| 17300 | setInitialPosition: function() { |
|
| 17301 | module.debug('Returning to initial position'); |
|
| 17302 | module.unfix(); |
|
| 17303 | module.unbind(); |
|
| 17304 | }, |
|
| 17305 | ||
| 17306 | ||
| 17307 | fixTop: function() { |
|
| 17308 | module.debug('Fixing element to top of page'); |
|
| 17309 | if(settings.setSize) { |
|
| 17310 | module.set.size(); |
|
| 17311 | } |
|
| 17312 | module.set.minimumSize(); |
|
| 17313 | module.set.offset(); |
|
| 17314 | $module |
|
| 17315 | .css({ |
|
| 17316 | left : module.cache.element.left, |
|
| 17317 | bottom : '', |
|
| 17318 | marginBottom : '' |
|
| 17319 | }) |
|
| 17320 | .removeClass(className.bound) |
|
| 17321 | .removeClass(className.bottom) |
|
| 17322 | .addClass(className.fixed) |
|
| 17323 | .addClass(className.top) |
|
| 17324 | ; |
|
| 17325 | settings.onStick.call(element); |
|
| 17326 | }, |
|
| 17327 | ||
| 17328 | fixBottom: function() { |
|
| 17329 | module.debug('Sticking element to bottom of page'); |
|
| 17330 | if(settings.setSize) { |
|
| 17331 | module.set.size(); |
|
| 17332 | } |
|
| 17333 | module.set.minimumSize(); |
|
| 17334 | module.set.offset(); |
|
| 17335 | $module |
|
| 17336 | .css({ |
|
| 17337 | left : module.cache.element.left, |
|
| 17338 | bottom : '', |
|
| 17339 | marginBottom : '' |
|
| 17340 | }) |
|
| 17341 | .removeClass(className.bound) |
|
| 17342 | .removeClass(className.top) |
|
| 17343 | .addClass(className.fixed) |
|
| 17344 | .addClass(className.bottom) |
|
| 17345 | ; |
|
| 17346 | settings.onStick.call(element); |
|
| 17347 | }, |
|
| 17348 | ||
| 17349 | unbind: function() { |
|
| 17350 | if( module.is.bound() ) { |
|
| 17351 | module.debug('Removing container bound position on element'); |
|
| 17352 | module.remove.offset(); |
|
| 17353 | $module |
|
| 17354 | .removeClass(className.bound) |
|
| 17355 | .removeClass(className.top) |
|
| 17356 | .removeClass(className.bottom) |
|
| 17357 | ; |
|
| 17358 | } |
|
| 17359 | }, |
|
| 17360 | ||
| 17361 | unfix: function() { |
|
| 17362 | if( module.is.fixed() ) { |
|
| 17363 | module.debug('Removing fixed position on element'); |
|
| 17364 | module.remove.minimumSize(); |
|
| 17365 | module.remove.offset(); |
|
| 17366 | $module |
|
| 17367 | .removeClass(className.fixed) |
|
| 17368 | .removeClass(className.top) |
|
| 17369 | .removeClass(className.bottom) |
|
| 17370 | ; |
|
| 17371 | settings.onUnstick.call(element); |
|
| 17372 | } |
|
| 17373 | }, |
|
| 17374 | ||
| 17375 | reset: function() { |
|
| 17376 | module.debug('Resetting elements position'); |
|
| 17377 | module.unbind(); |
|
| 17378 | module.unfix(); |
|
| 17379 | module.resetCSS(); |
|
| 17380 | module.remove.offset(); |
|
| 17381 | module.remove.lastScroll(); |
|
| 17382 | }, |
|
| 17383 | ||
| 17384 | resetCSS: function() { |
|
| 17385 | $module |
|
| 17386 | .css({ |
|
| 17387 | width : '', |
|
| 17388 | height : '' |
|
| 17389 | }) |
|
| 17390 | ; |
|
| 17391 | $container |
|
| 17392 | .css({ |
|
| 17393 | height: '' |
|
| 17394 | }) |
|
| 17395 | ; |
|
| 17396 | }, |
|
| 17397 | ||
| 17398 | setting: function(name, value) { |
|
| 17399 | if( $.isPlainObject(name) ) { |
|
| 17400 | $.extend(true, settings, name); |
|
| 17401 | } |
|
| 17402 | else if(value !== undefined) { |
|
| 17403 | settings[name] = value; |
|
| 17404 | } |
|
| 17405 | else { |
|
| 17406 | return settings[name]; |
|
| 17407 | } |
|
| 17408 | }, |
|
| 17409 | internal: function(name, value) { |
|
| 17410 | if( $.isPlainObject(name) ) { |
|
| 17411 | $.extend(true, module, name); |
|
| 17412 | } |
|
| 17413 | else if(value !== undefined) { |
|
| 17414 | module[name] = value; |
|
| 17415 | } |
|
| 17416 | else { |
|
| 17417 | return module[name]; |
|
| 17418 | } |
|
| 17419 | }, |
|
| 17420 | debug: function() { |
|
| 17421 | if(!settings.silent && settings.debug) { |
|
| 17422 | if(settings.performance) { |
|
| 17423 | module.performance.log(arguments); |
|
| 17424 | } |
|
| 17425 | else { |
|
| 17426 | module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 17427 | module.debug.apply(console, arguments); |
|
| 17428 | } |
|
| 17429 | } |
|
| 17430 | }, |
|
| 17431 | verbose: function() { |
|
| 17432 | if(!settings.silent && settings.verbose && settings.debug) { |
|
| 17433 | if(settings.performance) { |
|
| 17434 | module.performance.log(arguments); |
|
| 17435 | } |
|
| 17436 | else { |
|
| 17437 | module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 17438 | module.verbose.apply(console, arguments); |
|
| 17439 | } |
|
| 17440 | } |
|
| 17441 | }, |
|
| 17442 | error: function() { |
|
| 17443 | if(!settings.silent) { |
|
| 17444 | module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); |
|
| 17445 | module.error.apply(console, arguments); |
|
| 17446 | } |
|
| 17447 | }, |
|
| 17448 | performance: { |
|
| 17449 | log: function(message) { |
|
| 17450 | var |
|
| 17451 | currentTime, |
|
| 17452 | executionTime, |
|
| 17453 | previousTime |
|
| 17454 | ; |
|
| 17455 | if(settings.performance) { |
|
| 17456 | currentTime = new Date().getTime(); |
|
| 17457 | previousTime = time || currentTime; |
|
| 17458 | executionTime = currentTime - previousTime; |
|
| 17459 | time = currentTime; |
|
| 17460 | performance.push({ |
|
| 17461 | 'Name' : message[0], |
|
| 17462 | 'Arguments' : [].slice.call(message, 1) || '', |
|
| 17463 | 'Element' : element, |
|
| 17464 | 'Execution Time' : executionTime |
|
| 17465 | }); |
|
| 17466 | } |
|
| 17467 | clearTimeout(module.performance.timer); |
|
| 17468 | module.performance.timer = setTimeout(module.performance.display, 0); |
|
| 17469 | }, |
|
| 17470 | display: function() { |
|
| 17471 | var |
|
| 17472 | title = settings.name + ':', |
|
| 17473 | totalTime = 0 |
|
| 17474 | ; |
|
| 17475 | time = false; |
|
| 17476 | clearTimeout(module.performance.timer); |
|
| 17477 | $.each(performance, function(index, data) { |
|
| 17478 | totalTime += data['Execution Time']; |
|
| 17479 | }); |
|
| 17480 | title += ' ' + totalTime + 'ms'; |
|
| 17481 | if(moduleSelector) { |
|
| 17482 | title += ' \'' + moduleSelector + '\''; |
|
| 17483 | } |
|
| 17484 | if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { |
|
| 17485 | console.groupCollapsed(title); |
|
| 17486 | if(console.table) { |
|
| 17487 | console.table(performance); |
|
| 17488 | } |
|
| 17489 | else { |
|
| 17490 | $.each(performance, function(index, data) { |
|
| 17491 | console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); |
|
| 17492 | }); |
|
| 17493 | } |
|
| 17494 | console.groupEnd(); |
|
| 17495 | } |
|
| 17496 | performance = []; |
|
| 17497 | } |
|
| 17498 | }, |
|
| 17499 | invoke: function(query, passedArguments, context) { |
|
| 17500 | var |
|
| 17501 | object = instance, |
|
| 17502 | maxDepth, |
|
| 17503 | found, |
|
| 17504 | response |
|
| 17505 | ; |
|
| 17506 | passedArguments = passedArguments || queryArguments; |
|
| 17507 | context = element || context; |
|
| 17508 | if(typeof query == 'string' && object !== undefined) { |
|
| 17509 | query = query.split(/[\. ]/); |
|
| 17510 | maxDepth = query.length - 1; |
|
| 17511 | $.each(query, function(depth, value) { |
|
| 17512 | var camelCaseValue = (depth != maxDepth) |
|
| 17513 | ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) |
|
| 17514 | : query |
|
| 17515 | ; |
|
| 17516 | if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { |
|
| 17517 | object = object[camelCaseValue]; |
|
| 17518 | } |
|
| 17519 | else if( object[camelCaseValue] !== undefined ) { |
|
| 17520 | found = object[camelCaseValue]; |
|
| 17521 | return false; |
|
| 17522 | } |
|
| 17523 | else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { |
|
| 17524 | object = object[value]; |
|
| 17525 | } |
|
| 17526 | else if( object[value] !== undefined ) { |
|
| 17527 | found = object[value]; |
|
| 17528 | return false; |
|
| 17529 | } |
|
| 17530 | else { |
|
| 17531 | return false; |
|
| 17532 | } |
|
| 17533 | }); |
|
| 17534 | } |
|
| 17535 | if ( $.isFunction( found ) ) { |
|
| 17536 | response = found.apply(context, passedArguments); |
|
| 17537 | } |
|
| 17538 | else if(found !== undefined) { |
|
| 17539 | response = found; |
|
| 17540 | } |
|
| 17541 | if($.isArray(returnedValue)) { |
|
| 17542 | returnedValue.push(response); |
|
| 17543 | } |
|
| 17544 | else if(returnedValue !== undefined) { |
|
| 17545 | returnedValue = [returnedValue, response]; |
|
| 17546 | } |
|
| 17547 | else if(response !== undefined) { |
|
| 17548 | returnedValue = response; |
|
| 17549 | } |
|
| 17550 | return found; |
|
| 17551 | } |
|
| 17552 | }; |
|
| 17553 | ||
| 17554 | if(methodInvoked) { |
|
| 17555 | if(instance === undefined) { |
|
| 17556 | module.initialize(); |
|
| 17557 | } |
|
| 17558 | module.invoke(query); |
|
| 17559 | } |
|
| 17560 | else { |
|
| 17561 | if(instance !== undefined) { |
|
| 17562 | instance.invoke('destroy'); |
|
| 17563 | } |
|
| 17564 | module.initialize(); |
|
| 17565 | } |
|
| 17566 | }) |
|
| 17567 | ; |
|
| 17568 | ||
| 17569 | return (returnedValue !== undefined) |
|
| 17570 | ? returnedValue |
|
| 17571 | : this |
|
| 17572 | ; |
|
| 17573 | }; |
|
| 17574 | ||
| 17575 | $.fn.sticky.settings = { |
|
| 17576 | ||
| 17577 | name : 'Sticky', |
|
| 17578 | namespace : 'sticky', |
|
| 17579 | ||
| 17580 | silent : false, |
|
| 17581 | debug : false, |
|
| 17582 | verbose : true, |
|
| 17583 | performance : true, |
|
| 17584 | ||
| 17585 | // whether to stick in the opposite direction on scroll up |
|
| 17586 | pushing : false, |
|
| 17587 | ||
| 17588 | context : false, |
|
| 17589 | container : false, |
|
| 17590 | ||
| 17591 | // Context to watch scroll events |
|
| 17592 | scrollContext : window, |
|
| 17593 | ||
| 17594 | // Offset to adjust scroll |
|
| 17595 | offset : 0, |
|
| 17596 | ||
| 17597 | // Offset to adjust scroll when attached to bottom of screen |
|
| 17598 | bottomOffset : 0, |
|
| 17599 | ||
| 17600 | // will only set container height if difference between context and container is larger than this number |
|
| 17601 | jitter : 5, |
|
| 17602 | ||
| 17603 | // set width of sticky element when it is fixed to page (used to make sure 100% width is maintained if no fixed size set) |
|
| 17604 | setSize : true, |
|
| 17605 | ||
| 17606 | // Whether to automatically observe changes with Mutation Observers |
|
| 17607 | observeChanges : false, |
|
| 17608 | ||
| 17609 | // Called when position is recalculated |
|
| 17610 | onReposition : function(){}, |
|
| 17611 | ||
| 17612 | // Called on each scroll |
|
| 17613 | onScroll : function(){}, |
|
| 17614 | ||
| 17615 | // Called when element is stuck to viewport |
|
| 17616 | onStick : function(){}, |
|
| 17617 | ||
| 17618 | // Called when element is unstuck from viewport |
|
| 17619 | onUnstick : function(){}, |
|
| 17620 | ||
| 17621 | // Called when element reaches top of context |
|
| 17622 | onTop : function(){}, |
|
| 17623 | ||
| 17624 | // Called when element reaches bottom of context |
|
| 17625 | onBottom : function(){}, |
|
| 17626 | ||
| 17627 | error : { |
|
| 17628 | container : 'Sticky element must be inside a relative container', |
|
| 17629 | visible : 'Element is hidden, you must call refresh after element becomes visible. Use silent setting to surpress this warning in production.', |
|
| 17630 | method : 'The method you called is not defined.', |
|
| 17631 | invalidContext : 'Context specified does not exist', |
|
| 17632 | elementSize : 'Sticky element is larger than its container, cannot create sticky.' |
|
| 17633 | }, |
|
| 17634 | ||
| 17635 | className : { |
|
| 17636 | bound : 'bound', |
|
| 17637 | fixed : 'fixed', |
|
| 17638 | supported : 'native', |
|
| 17639 | top : 'top', |
|
| 17640 | bottom : 'bottom' |
|
| 17641 | } |
|
| 17642 | ||
| 17643 | }; |
|
| 17644 | ||
| 17645 | })( jQuery, window, document ); |
|
| 17646 | ||
| 17647 | /*! |
|
| 17648 | * # Semantic UI 2.2.11 - Tab |
|
| @@ 11-959 (lines=949) @@ | ||
| 8 | * |
|
| 9 | */ |
|
| 10 | ||
| 11 | ;(function ($, window, document, undefined) { |
|
| 12 | ||
| 13 | "use strict"; |
|
| 14 | ||
| 15 | window = (typeof window != 'undefined' && window.Math == Math) |
|
| 16 | ? window |
|
| 17 | : (typeof self != 'undefined' && self.Math == Math) |
|
| 18 | ? self |
|
| 19 | : Function('return this')() |
|
| 20 | ; |
|
| 21 | ||
| 22 | $.fn.sticky = function(parameters) { |
|
| 23 | var |
|
| 24 | $allModules = $(this), |
|
| 25 | moduleSelector = $allModules.selector || '', |
|
| 26 | ||
| 27 | time = new Date().getTime(), |
|
| 28 | performance = [], |
|
| 29 | ||
| 30 | query = arguments[0], |
|
| 31 | methodInvoked = (typeof query == 'string'), |
|
| 32 | queryArguments = [].slice.call(arguments, 1), |
|
| 33 | returnedValue |
|
| 34 | ; |
|
| 35 | ||
| 36 | $allModules |
|
| 37 | .each(function() { |
|
| 38 | var |
|
| 39 | settings = ( $.isPlainObject(parameters) ) |
|
| 40 | ? $.extend(true, {}, $.fn.sticky.settings, parameters) |
|
| 41 | : $.extend({}, $.fn.sticky.settings), |
|
| 42 | ||
| 43 | className = settings.className, |
|
| 44 | namespace = settings.namespace, |
|
| 45 | error = settings.error, |
|
| 46 | ||
| 47 | eventNamespace = '.' + namespace, |
|
| 48 | moduleNamespace = 'module-' + namespace, |
|
| 49 | ||
| 50 | $module = $(this), |
|
| 51 | $window = $(window), |
|
| 52 | $scroll = $(settings.scrollContext), |
|
| 53 | $container, |
|
| 54 | $context, |
|
| 55 | ||
| 56 | selector = $module.selector || '', |
|
| 57 | instance = $module.data(moduleNamespace), |
|
| 58 | ||
| 59 | requestAnimationFrame = window.requestAnimationFrame |
|
| 60 | || window.mozRequestAnimationFrame |
|
| 61 | || window.webkitRequestAnimationFrame |
|
| 62 | || window.msRequestAnimationFrame |
|
| 63 | || function(callback) { setTimeout(callback, 0); }, |
|
| 64 | ||
| 65 | element = this, |
|
| 66 | ||
| 67 | documentObserver, |
|
| 68 | observer, |
|
| 69 | module |
|
| 70 | ; |
|
| 71 | ||
| 72 | module = { |
|
| 73 | ||
| 74 | initialize: function() { |
|
| 75 | ||
| 76 | module.determineContainer(); |
|
| 77 | module.determineContext(); |
|
| 78 | module.verbose('Initializing sticky', settings, $container); |
|
| 79 | ||
| 80 | module.save.positions(); |
|
| 81 | module.checkErrors(); |
|
| 82 | module.bind.events(); |
|
| 83 | ||
| 84 | if(settings.observeChanges) { |
|
| 85 | module.observeChanges(); |
|
| 86 | } |
|
| 87 | module.instantiate(); |
|
| 88 | }, |
|
| 89 | ||
| 90 | instantiate: function() { |
|
| 91 | module.verbose('Storing instance of module', module); |
|
| 92 | instance = module; |
|
| 93 | $module |
|
| 94 | .data(moduleNamespace, module) |
|
| 95 | ; |
|
| 96 | }, |
|
| 97 | ||
| 98 | destroy: function() { |
|
| 99 | module.verbose('Destroying previous instance'); |
|
| 100 | module.reset(); |
|
| 101 | if(documentObserver) { |
|
| 102 | documentObserver.disconnect(); |
|
| 103 | } |
|
| 104 | if(observer) { |
|
| 105 | observer.disconnect(); |
|
| 106 | } |
|
| 107 | $window |
|
| 108 | .off('load' + eventNamespace, module.event.load) |
|
| 109 | .off('resize' + eventNamespace, module.event.resize) |
|
| 110 | ; |
|
| 111 | $scroll |
|
| 112 | .off('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 113 | ; |
|
| 114 | $module.removeData(moduleNamespace); |
|
| 115 | }, |
|
| 116 | ||
| 117 | observeChanges: function() { |
|
| 118 | if('MutationObserver' in window) { |
|
| 119 | documentObserver = new MutationObserver(module.event.documentChanged); |
|
| 120 | observer = new MutationObserver(module.event.changed); |
|
| 121 | documentObserver.observe(document, { |
|
| 122 | childList : true, |
|
| 123 | subtree : true |
|
| 124 | }); |
|
| 125 | observer.observe(element, { |
|
| 126 | childList : true, |
|
| 127 | subtree : true |
|
| 128 | }); |
|
| 129 | observer.observe($context[0], { |
|
| 130 | childList : true, |
|
| 131 | subtree : true |
|
| 132 | }); |
|
| 133 | module.debug('Setting up mutation observer', observer); |
|
| 134 | } |
|
| 135 | }, |
|
| 136 | ||
| 137 | determineContainer: function() { |
|
| 138 | if(settings.container) { |
|
| 139 | $container = $(settings.container); |
|
| 140 | } |
|
| 141 | else { |
|
| 142 | $container = $module.offsetParent(); |
|
| 143 | } |
|
| 144 | }, |
|
| 145 | ||
| 146 | determineContext: function() { |
|
| 147 | if(settings.context) { |
|
| 148 | $context = $(settings.context); |
|
| 149 | } |
|
| 150 | else { |
|
| 151 | $context = $container; |
|
| 152 | } |
|
| 153 | if($context.length === 0) { |
|
| 154 | module.error(error.invalidContext, settings.context, $module); |
|
| 155 | return; |
|
| 156 | } |
|
| 157 | }, |
|
| 158 | ||
| 159 | checkErrors: function() { |
|
| 160 | if( module.is.hidden() ) { |
|
| 161 | module.error(error.visible, $module); |
|
| 162 | } |
|
| 163 | if(module.cache.element.height > module.cache.context.height) { |
|
| 164 | module.reset(); |
|
| 165 | module.error(error.elementSize, $module); |
|
| 166 | return; |
|
| 167 | } |
|
| 168 | }, |
|
| 169 | ||
| 170 | bind: { |
|
| 171 | events: function() { |
|
| 172 | $window |
|
| 173 | .on('load' + eventNamespace, module.event.load) |
|
| 174 | .on('resize' + eventNamespace, module.event.resize) |
|
| 175 | ; |
|
| 176 | // pub/sub pattern |
|
| 177 | $scroll |
|
| 178 | .off('scroll' + eventNamespace) |
|
| 179 | .on('scroll' + eventNamespace, module.event.scroll) |
|
| 180 | .on('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 181 | ; |
|
| 182 | } |
|
| 183 | }, |
|
| 184 | ||
| 185 | event: { |
|
| 186 | changed: function(mutations) { |
|
| 187 | clearTimeout(module.timer); |
|
| 188 | module.timer = setTimeout(function() { |
|
| 189 | module.verbose('DOM tree modified, updating sticky menu', mutations); |
|
| 190 | module.refresh(); |
|
| 191 | }, 100); |
|
| 192 | }, |
|
| 193 | documentChanged: function(mutations) { |
|
| 194 | [].forEach.call(mutations, function(mutation) { |
|
| 195 | if(mutation.removedNodes) { |
|
| 196 | [].forEach.call(mutation.removedNodes, function(node) { |
|
| 197 | if(node == element || $(node).find(element).length > 0) { |
|
| 198 | module.debug('Element removed from DOM, tearing down events'); |
|
| 199 | module.destroy(); |
|
| 200 | } |
|
| 201 | }); |
|
| 202 | } |
|
| 203 | }); |
|
| 204 | }, |
|
| 205 | load: function() { |
|
| 206 | module.verbose('Page contents finished loading'); |
|
| 207 | requestAnimationFrame(module.refresh); |
|
| 208 | }, |
|
| 209 | resize: function() { |
|
| 210 | module.verbose('Window resized'); |
|
| 211 | requestAnimationFrame(module.refresh); |
|
| 212 | }, |
|
| 213 | scroll: function() { |
|
| 214 | requestAnimationFrame(function() { |
|
| 215 | $scroll.triggerHandler('scrollchange' + eventNamespace, $scroll.scrollTop() ); |
|
| 216 | }); |
|
| 217 | }, |
|
| 218 | scrollchange: function(event, scrollPosition) { |
|
| 219 | module.stick(scrollPosition); |
|
| 220 | settings.onScroll.call(element); |
|
| 221 | } |
|
| 222 | }, |
|
| 223 | ||
| 224 | refresh: function(hardRefresh) { |
|
| 225 | module.reset(); |
|
| 226 | if(!settings.context) { |
|
| 227 | module.determineContext(); |
|
| 228 | } |
|
| 229 | if(hardRefresh) { |
|
| 230 | module.determineContainer(); |
|
| 231 | } |
|
| 232 | module.save.positions(); |
|
| 233 | module.stick(); |
|
| 234 | settings.onReposition.call(element); |
|
| 235 | }, |
|
| 236 | ||
| 237 | supports: { |
|
| 238 | sticky: function() { |
|
| 239 | var |
|
| 240 | $element = $('<div/>'), |
|
| 241 | element = $element[0] |
|
| 242 | ; |
|
| 243 | $element.addClass(className.supported); |
|
| 244 | return($element.css('position').match('sticky')); |
|
| 245 | } |
|
| 246 | }, |
|
| 247 | ||
| 248 | save: { |
|
| 249 | lastScroll: function(scroll) { |
|
| 250 | module.lastScroll = scroll; |
|
| 251 | }, |
|
| 252 | elementScroll: function(scroll) { |
|
| 253 | module.elementScroll = scroll; |
|
| 254 | }, |
|
| 255 | positions: function() { |
|
| 256 | var |
|
| 257 | scrollContext = { |
|
| 258 | height : $scroll.height() |
|
| 259 | }, |
|
| 260 | element = { |
|
| 261 | margin: { |
|
| 262 | top : parseInt($module.css('margin-top'), 10), |
|
| 263 | bottom : parseInt($module.css('margin-bottom'), 10), |
|
| 264 | }, |
|
| 265 | offset : $module.offset(), |
|
| 266 | width : $module.outerWidth(), |
|
| 267 | height : $module.outerHeight() |
|
| 268 | }, |
|
| 269 | context = { |
|
| 270 | offset : $context.offset(), |
|
| 271 | height : $context.outerHeight() |
|
| 272 | }, |
|
| 273 | container = { |
|
| 274 | height: $container.outerHeight() |
|
| 275 | } |
|
| 276 | ; |
|
| 277 | if( !module.is.standardScroll() ) { |
|
| 278 | module.debug('Non-standard scroll. Removing scroll offset from element offset'); |
|
| 279 | ||
| 280 | scrollContext.top = $scroll.scrollTop(); |
|
| 281 | scrollContext.left = $scroll.scrollLeft(); |
|
| 282 | ||
| 283 | element.offset.top += scrollContext.top; |
|
| 284 | context.offset.top += scrollContext.top; |
|
| 285 | element.offset.left += scrollContext.left; |
|
| 286 | context.offset.left += scrollContext.left; |
|
| 287 | } |
|
| 288 | module.cache = { |
|
| 289 | fits : ( (element.height + settings.offset) <= scrollContext.height), |
|
| 290 | sameHeight : (element.height == context.height), |
|
| 291 | scrollContext : { |
|
| 292 | height : scrollContext.height |
|
| 293 | }, |
|
| 294 | element: { |
|
| 295 | margin : element.margin, |
|
| 296 | top : element.offset.top - element.margin.top, |
|
| 297 | left : element.offset.left, |
|
| 298 | width : element.width, |
|
| 299 | height : element.height, |
|
| 300 | bottom : element.offset.top + element.height |
|
| 301 | }, |
|
| 302 | context: { |
|
| 303 | top : context.offset.top, |
|
| 304 | height : context.height, |
|
| 305 | bottom : context.offset.top + context.height |
|
| 306 | } |
|
| 307 | }; |
|
| 308 | module.set.containerSize(); |
|
| 309 | ||
| 310 | module.stick(); |
|
| 311 | module.debug('Caching element positions', module.cache); |
|
| 312 | } |
|
| 313 | }, |
|
| 314 | ||
| 315 | get: { |
|
| 316 | direction: function(scroll) { |
|
| 317 | var |
|
| 318 | direction = 'down' |
|
| 319 | ; |
|
| 320 | scroll = scroll || $scroll.scrollTop(); |
|
| 321 | if(module.lastScroll !== undefined) { |
|
| 322 | if(module.lastScroll < scroll) { |
|
| 323 | direction = 'down'; |
|
| 324 | } |
|
| 325 | else if(module.lastScroll > scroll) { |
|
| 326 | direction = 'up'; |
|
| 327 | } |
|
| 328 | } |
|
| 329 | return direction; |
|
| 330 | }, |
|
| 331 | scrollChange: function(scroll) { |
|
| 332 | scroll = scroll || $scroll.scrollTop(); |
|
| 333 | return (module.lastScroll) |
|
| 334 | ? (scroll - module.lastScroll) |
|
| 335 | : 0 |
|
| 336 | ; |
|
| 337 | }, |
|
| 338 | currentElementScroll: function() { |
|
| 339 | if(module.elementScroll) { |
|
| 340 | return module.elementScroll; |
|
| 341 | } |
|
| 342 | return ( module.is.top() ) |
|
| 343 | ? Math.abs(parseInt($module.css('top'), 10)) || 0 |
|
| 344 | : Math.abs(parseInt($module.css('bottom'), 10)) || 0 |
|
| 345 | ; |
|
| 346 | }, |
|
| 347 | ||
| 348 | elementScroll: function(scroll) { |
|
| 349 | scroll = scroll || $scroll.scrollTop(); |
|
| 350 | var |
|
| 351 | element = module.cache.element, |
|
| 352 | scrollContext = module.cache.scrollContext, |
|
| 353 | delta = module.get.scrollChange(scroll), |
|
| 354 | maxScroll = (element.height - scrollContext.height + settings.offset), |
|
| 355 | elementScroll = module.get.currentElementScroll(), |
|
| 356 | possibleScroll = (elementScroll + delta) |
|
| 357 | ; |
|
| 358 | if(module.cache.fits || possibleScroll < 0) { |
|
| 359 | elementScroll = 0; |
|
| 360 | } |
|
| 361 | else if(possibleScroll > maxScroll ) { |
|
| 362 | elementScroll = maxScroll; |
|
| 363 | } |
|
| 364 | else { |
|
| 365 | elementScroll = possibleScroll; |
|
| 366 | } |
|
| 367 | return elementScroll; |
|
| 368 | } |
|
| 369 | }, |
|
| 370 | ||
| 371 | remove: { |
|
| 372 | lastScroll: function() { |
|
| 373 | delete module.lastScroll; |
|
| 374 | }, |
|
| 375 | elementScroll: function(scroll) { |
|
| 376 | delete module.elementScroll; |
|
| 377 | }, |
|
| 378 | minimumSize: function() { |
|
| 379 | $container |
|
| 380 | .css('min-height', '') |
|
| 381 | ; |
|
| 382 | }, |
|
| 383 | offset: function() { |
|
| 384 | $module.css('margin-top', ''); |
|
| 385 | } |
|
| 386 | }, |
|
| 387 | ||
| 388 | set: { |
|
| 389 | offset: function() { |
|
| 390 | module.verbose('Setting offset on element', settings.offset); |
|
| 391 | $module |
|
| 392 | .css('margin-top', settings.offset) |
|
| 393 | ; |
|
| 394 | }, |
|
| 395 | containerSize: function() { |
|
| 396 | var |
|
| 397 | tagName = $container.get(0).tagName |
|
| 398 | ; |
|
| 399 | if(tagName === 'HTML' || tagName == 'body') { |
|
| 400 | // this can trigger for too many reasons |
|
| 401 | //module.error(error.container, tagName, $module); |
|
| 402 | module.determineContainer(); |
|
| 403 | } |
|
| 404 | else { |
|
| 405 | if( Math.abs($container.outerHeight() - module.cache.context.height) > settings.jitter) { |
|
| 406 | module.debug('Context has padding, specifying exact height for container', module.cache.context.height); |
|
| 407 | $container.css({ |
|
| 408 | height: module.cache.context.height |
|
| 409 | }); |
|
| 410 | } |
|
| 411 | } |
|
| 412 | }, |
|
| 413 | minimumSize: function() { |
|
| 414 | var |
|
| 415 | element = module.cache.element |
|
| 416 | ; |
|
| 417 | $container |
|
| 418 | .css('min-height', element.height) |
|
| 419 | ; |
|
| 420 | }, |
|
| 421 | scroll: function(scroll) { |
|
| 422 | module.debug('Setting scroll on element', scroll); |
|
| 423 | if(module.elementScroll == scroll) { |
|
| 424 | return; |
|
| 425 | } |
|
| 426 | if( module.is.top() ) { |
|
| 427 | $module |
|
| 428 | .css('bottom', '') |
|
| 429 | .css('top', -scroll) |
|
| 430 | ; |
|
| 431 | } |
|
| 432 | if( module.is.bottom() ) { |
|
| 433 | $module |
|
| 434 | .css('top', '') |
|
| 435 | .css('bottom', scroll) |
|
| 436 | ; |
|
| 437 | } |
|
| 438 | }, |
|
| 439 | size: function() { |
|
| 440 | if(module.cache.element.height !== 0 && module.cache.element.width !== 0) { |
|
| 441 | element.style.setProperty('width', module.cache.element.width + 'px', 'important'); |
|
| 442 | element.style.setProperty('height', module.cache.element.height + 'px', 'important'); |
|
| 443 | } |
|
| 444 | } |
|
| 445 | }, |
|
| 446 | ||
| 447 | is: { |
|
| 448 | standardScroll: function() { |
|
| 449 | return ($scroll[0] == window); |
|
| 450 | }, |
|
| 451 | top: function() { |
|
| 452 | return $module.hasClass(className.top); |
|
| 453 | }, |
|
| 454 | bottom: function() { |
|
| 455 | return $module.hasClass(className.bottom); |
|
| 456 | }, |
|
| 457 | initialPosition: function() { |
|
| 458 | return (!module.is.fixed() && !module.is.bound()); |
|
| 459 | }, |
|
| 460 | hidden: function() { |
|
| 461 | return (!$module.is(':visible')); |
|
| 462 | }, |
|
| 463 | bound: function() { |
|
| 464 | return $module.hasClass(className.bound); |
|
| 465 | }, |
|
| 466 | fixed: function() { |
|
| 467 | return $module.hasClass(className.fixed); |
|
| 468 | } |
|
| 469 | }, |
|
| 470 | ||
| 471 | stick: function(scroll) { |
|
| 472 | var |
|
| 473 | cachedPosition = scroll || $scroll.scrollTop(), |
|
| 474 | cache = module.cache, |
|
| 475 | fits = cache.fits, |
|
| 476 | sameHeight = cache.sameHeight, |
|
| 477 | element = cache.element, |
|
| 478 | scrollContext = cache.scrollContext, |
|
| 479 | context = cache.context, |
|
| 480 | offset = (module.is.bottom() && settings.pushing) |
|
| 481 | ? settings.bottomOffset |
|
| 482 | : settings.offset, |
|
| 483 | scroll = { |
|
| 484 | top : cachedPosition + offset, |
|
| 485 | bottom : cachedPosition + offset + scrollContext.height |
|
| 486 | }, |
|
| 487 | direction = module.get.direction(scroll.top), |
|
| 488 | elementScroll = (fits) |
|
| 489 | ? 0 |
|
| 490 | : module.get.elementScroll(scroll.top), |
|
| 491 | ||
| 492 | // shorthand |
|
| 493 | doesntFit = !fits, |
|
| 494 | elementVisible = (element.height !== 0) |
|
| 495 | ; |
|
| 496 | if(elementVisible && !sameHeight) { |
|
| 497 | ||
| 498 | if( module.is.initialPosition() ) { |
|
| 499 | if(scroll.top >= context.bottom) { |
|
| 500 | module.debug('Initial element position is bottom of container'); |
|
| 501 | module.bindBottom(); |
|
| 502 | } |
|
| 503 | else if(scroll.top > element.top) { |
|
| 504 | if( (element.height + scroll.top - elementScroll) >= context.bottom ) { |
|
| 505 | module.debug('Initial element position is bottom of container'); |
|
| 506 | module.bindBottom(); |
|
| 507 | } |
|
| 508 | else { |
|
| 509 | module.debug('Initial element position is fixed'); |
|
| 510 | module.fixTop(); |
|
| 511 | } |
|
| 512 | } |
|
| 513 | ||
| 514 | } |
|
| 515 | else if( module.is.fixed() ) { |
|
| 516 | ||
| 517 | // currently fixed top |
|
| 518 | if( module.is.top() ) { |
|
| 519 | if( scroll.top <= element.top ) { |
|
| 520 | module.debug('Fixed element reached top of container'); |
|
| 521 | module.setInitialPosition(); |
|
| 522 | } |
|
| 523 | else if( (element.height + scroll.top - elementScroll) >= context.bottom ) { |
|
| 524 | module.debug('Fixed element reached bottom of container'); |
|
| 525 | module.bindBottom(); |
|
| 526 | } |
|
| 527 | // scroll element if larger than screen |
|
| 528 | else if(doesntFit) { |
|
| 529 | module.set.scroll(elementScroll); |
|
| 530 | module.save.lastScroll(scroll.top); |
|
| 531 | module.save.elementScroll(elementScroll); |
|
| 532 | } |
|
| 533 | } |
|
| 534 | ||
| 535 | // currently fixed bottom |
|
| 536 | else if(module.is.bottom() ) { |
|
| 537 | ||
| 538 | // top edge |
|
| 539 | if( (scroll.bottom - element.height) <= element.top) { |
|
| 540 | module.debug('Bottom fixed rail has reached top of container'); |
|
| 541 | module.setInitialPosition(); |
|
| 542 | } |
|
| 543 | // bottom edge |
|
| 544 | else if(scroll.bottom >= context.bottom) { |
|
| 545 | module.debug('Bottom fixed rail has reached bottom of container'); |
|
| 546 | module.bindBottom(); |
|
| 547 | } |
|
| 548 | // scroll element if larger than screen |
|
| 549 | else if(doesntFit) { |
|
| 550 | module.set.scroll(elementScroll); |
|
| 551 | module.save.lastScroll(scroll.top); |
|
| 552 | module.save.elementScroll(elementScroll); |
|
| 553 | } |
|
| 554 | ||
| 555 | } |
|
| 556 | } |
|
| 557 | else if( module.is.bottom() ) { |
|
| 558 | if( scroll.top <= element.top ) { |
|
| 559 | module.debug('Jumped from bottom fixed to top fixed, most likely used home/end button'); |
|
| 560 | module.setInitialPosition(); |
|
| 561 | } |
|
| 562 | else { |
|
| 563 | if(settings.pushing) { |
|
| 564 | if(module.is.bound() && scroll.bottom <= context.bottom ) { |
|
| 565 | module.debug('Fixing bottom attached element to bottom of browser.'); |
|
| 566 | module.fixBottom(); |
|
| 567 | } |
|
| 568 | } |
|
| 569 | else { |
|
| 570 | if(module.is.bound() && (scroll.top <= context.bottom - element.height) ) { |
|
| 571 | module.debug('Fixing bottom attached element to top of browser.'); |
|
| 572 | module.fixTop(); |
|
| 573 | } |
|
| 574 | } |
|
| 575 | } |
|
| 576 | } |
|
| 577 | } |
|
| 578 | }, |
|
| 579 | ||
| 580 | bindTop: function() { |
|
| 581 | module.debug('Binding element to top of parent container'); |
|
| 582 | module.remove.offset(); |
|
| 583 | $module |
|
| 584 | .css({ |
|
| 585 | left : '', |
|
| 586 | top : '', |
|
| 587 | marginBottom : '' |
|
| 588 | }) |
|
| 589 | .removeClass(className.fixed) |
|
| 590 | .removeClass(className.bottom) |
|
| 591 | .addClass(className.bound) |
|
| 592 | .addClass(className.top) |
|
| 593 | ; |
|
| 594 | settings.onTop.call(element); |
|
| 595 | settings.onUnstick.call(element); |
|
| 596 | }, |
|
| 597 | bindBottom: function() { |
|
| 598 | module.debug('Binding element to bottom of parent container'); |
|
| 599 | module.remove.offset(); |
|
| 600 | $module |
|
| 601 | .css({ |
|
| 602 | left : '', |
|
| 603 | top : '' |
|
| 604 | }) |
|
| 605 | .removeClass(className.fixed) |
|
| 606 | .removeClass(className.top) |
|
| 607 | .addClass(className.bound) |
|
| 608 | .addClass(className.bottom) |
|
| 609 | ; |
|
| 610 | settings.onBottom.call(element); |
|
| 611 | settings.onUnstick.call(element); |
|
| 612 | }, |
|
| 613 | ||
| 614 | setInitialPosition: function() { |
|
| 615 | module.debug('Returning to initial position'); |
|
| 616 | module.unfix(); |
|
| 617 | module.unbind(); |
|
| 618 | }, |
|
| 619 | ||
| 620 | ||
| 621 | fixTop: function() { |
|
| 622 | module.debug('Fixing element to top of page'); |
|
| 623 | if(settings.setSize) { |
|
| 624 | module.set.size(); |
|
| 625 | } |
|
| 626 | module.set.minimumSize(); |
|
| 627 | module.set.offset(); |
|
| 628 | $module |
|
| 629 | .css({ |
|
| 630 | left : module.cache.element.left, |
|
| 631 | bottom : '', |
|
| 632 | marginBottom : '' |
|
| 633 | }) |
|
| 634 | .removeClass(className.bound) |
|
| 635 | .removeClass(className.bottom) |
|
| 636 | .addClass(className.fixed) |
|
| 637 | .addClass(className.top) |
|
| 638 | ; |
|
| 639 | settings.onStick.call(element); |
|
| 640 | }, |
|
| 641 | ||
| 642 | fixBottom: function() { |
|
| 643 | module.debug('Sticking element to bottom of page'); |
|
| 644 | if(settings.setSize) { |
|
| 645 | module.set.size(); |
|
| 646 | } |
|
| 647 | module.set.minimumSize(); |
|
| 648 | module.set.offset(); |
|
| 649 | $module |
|
| 650 | .css({ |
|
| 651 | left : module.cache.element.left, |
|
| 652 | bottom : '', |
|
| 653 | marginBottom : '' |
|
| 654 | }) |
|
| 655 | .removeClass(className.bound) |
|
| 656 | .removeClass(className.top) |
|
| 657 | .addClass(className.fixed) |
|
| 658 | .addClass(className.bottom) |
|
| 659 | ; |
|
| 660 | settings.onStick.call(element); |
|
| 661 | }, |
|
| 662 | ||
| 663 | unbind: function() { |
|
| 664 | if( module.is.bound() ) { |
|
| 665 | module.debug('Removing container bound position on element'); |
|
| 666 | module.remove.offset(); |
|
| 667 | $module |
|
| 668 | .removeClass(className.bound) |
|
| 669 | .removeClass(className.top) |
|
| 670 | .removeClass(className.bottom) |
|
| 671 | ; |
|
| 672 | } |
|
| 673 | }, |
|
| 674 | ||
| 675 | unfix: function() { |
|
| 676 | if( module.is.fixed() ) { |
|
| 677 | module.debug('Removing fixed position on element'); |
|
| 678 | module.remove.minimumSize(); |
|
| 679 | module.remove.offset(); |
|
| 680 | $module |
|
| 681 | .removeClass(className.fixed) |
|
| 682 | .removeClass(className.top) |
|
| 683 | .removeClass(className.bottom) |
|
| 684 | ; |
|
| 685 | settings.onUnstick.call(element); |
|
| 686 | } |
|
| 687 | }, |
|
| 688 | ||
| 689 | reset: function() { |
|
| 690 | module.debug('Resetting elements position'); |
|
| 691 | module.unbind(); |
|
| 692 | module.unfix(); |
|
| 693 | module.resetCSS(); |
|
| 694 | module.remove.offset(); |
|
| 695 | module.remove.lastScroll(); |
|
| 696 | }, |
|
| 697 | ||
| 698 | resetCSS: function() { |
|
| 699 | $module |
|
| 700 | .css({ |
|
| 701 | width : '', |
|
| 702 | height : '' |
|
| 703 | }) |
|
| 704 | ; |
|
| 705 | $container |
|
| 706 | .css({ |
|
| 707 | height: '' |
|
| 708 | }) |
|
| 709 | ; |
|
| 710 | }, |
|
| 711 | ||
| 712 | setting: function(name, value) { |
|
| 713 | if( $.isPlainObject(name) ) { |
|
| 714 | $.extend(true, settings, name); |
|
| 715 | } |
|
| 716 | else if(value !== undefined) { |
|
| 717 | settings[name] = value; |
|
| 718 | } |
|
| 719 | else { |
|
| 720 | return settings[name]; |
|
| 721 | } |
|
| 722 | }, |
|
| 723 | internal: function(name, value) { |
|
| 724 | if( $.isPlainObject(name) ) { |
|
| 725 | $.extend(true, module, name); |
|
| 726 | } |
|
| 727 | else if(value !== undefined) { |
|
| 728 | module[name] = value; |
|
| 729 | } |
|
| 730 | else { |
|
| 731 | return module[name]; |
|
| 732 | } |
|
| 733 | }, |
|
| 734 | debug: function() { |
|
| 735 | if(!settings.silent && settings.debug) { |
|
| 736 | if(settings.performance) { |
|
| 737 | module.performance.log(arguments); |
|
| 738 | } |
|
| 739 | else { |
|
| 740 | module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 741 | module.debug.apply(console, arguments); |
|
| 742 | } |
|
| 743 | } |
|
| 744 | }, |
|
| 745 | verbose: function() { |
|
| 746 | if(!settings.silent && settings.verbose && settings.debug) { |
|
| 747 | if(settings.performance) { |
|
| 748 | module.performance.log(arguments); |
|
| 749 | } |
|
| 750 | else { |
|
| 751 | module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 752 | module.verbose.apply(console, arguments); |
|
| 753 | } |
|
| 754 | } |
|
| 755 | }, |
|
| 756 | error: function() { |
|
| 757 | if(!settings.silent) { |
|
| 758 | module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); |
|
| 759 | module.error.apply(console, arguments); |
|
| 760 | } |
|
| 761 | }, |
|
| 762 | performance: { |
|
| 763 | log: function(message) { |
|
| 764 | var |
|
| 765 | currentTime, |
|
| 766 | executionTime, |
|
| 767 | previousTime |
|
| 768 | ; |
|
| 769 | if(settings.performance) { |
|
| 770 | currentTime = new Date().getTime(); |
|
| 771 | previousTime = time || currentTime; |
|
| 772 | executionTime = currentTime - previousTime; |
|
| 773 | time = currentTime; |
|
| 774 | performance.push({ |
|
| 775 | 'Name' : message[0], |
|
| 776 | 'Arguments' : [].slice.call(message, 1) || '', |
|
| 777 | 'Element' : element, |
|
| 778 | 'Execution Time' : executionTime |
|
| 779 | }); |
|
| 780 | } |
|
| 781 | clearTimeout(module.performance.timer); |
|
| 782 | module.performance.timer = setTimeout(module.performance.display, 0); |
|
| 783 | }, |
|
| 784 | display: function() { |
|
| 785 | var |
|
| 786 | title = settings.name + ':', |
|
| 787 | totalTime = 0 |
|
| 788 | ; |
|
| 789 | time = false; |
|
| 790 | clearTimeout(module.performance.timer); |
|
| 791 | $.each(performance, function(index, data) { |
|
| 792 | totalTime += data['Execution Time']; |
|
| 793 | }); |
|
| 794 | title += ' ' + totalTime + 'ms'; |
|
| 795 | if(moduleSelector) { |
|
| 796 | title += ' \'' + moduleSelector + '\''; |
|
| 797 | } |
|
| 798 | if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { |
|
| 799 | console.groupCollapsed(title); |
|
| 800 | if(console.table) { |
|
| 801 | console.table(performance); |
|
| 802 | } |
|
| 803 | else { |
|
| 804 | $.each(performance, function(index, data) { |
|
| 805 | console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); |
|
| 806 | }); |
|
| 807 | } |
|
| 808 | console.groupEnd(); |
|
| 809 | } |
|
| 810 | performance = []; |
|
| 811 | } |
|
| 812 | }, |
|
| 813 | invoke: function(query, passedArguments, context) { |
|
| 814 | var |
|
| 815 | object = instance, |
|
| 816 | maxDepth, |
|
| 817 | found, |
|
| 818 | response |
|
| 819 | ; |
|
| 820 | passedArguments = passedArguments || queryArguments; |
|
| 821 | context = element || context; |
|
| 822 | if(typeof query == 'string' && object !== undefined) { |
|
| 823 | query = query.split(/[\. ]/); |
|
| 824 | maxDepth = query.length - 1; |
|
| 825 | $.each(query, function(depth, value) { |
|
| 826 | var camelCaseValue = (depth != maxDepth) |
|
| 827 | ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) |
|
| 828 | : query |
|
| 829 | ; |
|
| 830 | if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { |
|
| 831 | object = object[camelCaseValue]; |
|
| 832 | } |
|
| 833 | else if( object[camelCaseValue] !== undefined ) { |
|
| 834 | found = object[camelCaseValue]; |
|
| 835 | return false; |
|
| 836 | } |
|
| 837 | else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { |
|
| 838 | object = object[value]; |
|
| 839 | } |
|
| 840 | else if( object[value] !== undefined ) { |
|
| 841 | found = object[value]; |
|
| 842 | return false; |
|
| 843 | } |
|
| 844 | else { |
|
| 845 | return false; |
|
| 846 | } |
|
| 847 | }); |
|
| 848 | } |
|
| 849 | if ( $.isFunction( found ) ) { |
|
| 850 | response = found.apply(context, passedArguments); |
|
| 851 | } |
|
| 852 | else if(found !== undefined) { |
|
| 853 | response = found; |
|
| 854 | } |
|
| 855 | if($.isArray(returnedValue)) { |
|
| 856 | returnedValue.push(response); |
|
| 857 | } |
|
| 858 | else if(returnedValue !== undefined) { |
|
| 859 | returnedValue = [returnedValue, response]; |
|
| 860 | } |
|
| 861 | else if(response !== undefined) { |
|
| 862 | returnedValue = response; |
|
| 863 | } |
|
| 864 | return found; |
|
| 865 | } |
|
| 866 | }; |
|
| 867 | ||
| 868 | if(methodInvoked) { |
|
| 869 | if(instance === undefined) { |
|
| 870 | module.initialize(); |
|
| 871 | } |
|
| 872 | module.invoke(query); |
|
| 873 | } |
|
| 874 | else { |
|
| 875 | if(instance !== undefined) { |
|
| 876 | instance.invoke('destroy'); |
|
| 877 | } |
|
| 878 | module.initialize(); |
|
| 879 | } |
|
| 880 | }) |
|
| 881 | ; |
|
| 882 | ||
| 883 | return (returnedValue !== undefined) |
|
| 884 | ? returnedValue |
|
| 885 | : this |
|
| 886 | ; |
|
| 887 | }; |
|
| 888 | ||
| 889 | $.fn.sticky.settings = { |
|
| 890 | ||
| 891 | name : 'Sticky', |
|
| 892 | namespace : 'sticky', |
|
| 893 | ||
| 894 | silent : false, |
|
| 895 | debug : false, |
|
| 896 | verbose : true, |
|
| 897 | performance : true, |
|
| 898 | ||
| 899 | // whether to stick in the opposite direction on scroll up |
|
| 900 | pushing : false, |
|
| 901 | ||
| 902 | context : false, |
|
| 903 | container : false, |
|
| 904 | ||
| 905 | // Context to watch scroll events |
|
| 906 | scrollContext : window, |
|
| 907 | ||
| 908 | // Offset to adjust scroll |
|
| 909 | offset : 0, |
|
| 910 | ||
| 911 | // Offset to adjust scroll when attached to bottom of screen |
|
| 912 | bottomOffset : 0, |
|
| 913 | ||
| 914 | // will only set container height if difference between context and container is larger than this number |
|
| 915 | jitter : 5, |
|
| 916 | ||
| 917 | // set width of sticky element when it is fixed to page (used to make sure 100% width is maintained if no fixed size set) |
|
| 918 | setSize : true, |
|
| 919 | ||
| 920 | // Whether to automatically observe changes with Mutation Observers |
|
| 921 | observeChanges : false, |
|
| 922 | ||
| 923 | // Called when position is recalculated |
|
| 924 | onReposition : function(){}, |
|
| 925 | ||
| 926 | // Called on each scroll |
|
| 927 | onScroll : function(){}, |
|
| 928 | ||
| 929 | // Called when element is stuck to viewport |
|
| 930 | onStick : function(){}, |
|
| 931 | ||
| 932 | // Called when element is unstuck from viewport |
|
| 933 | onUnstick : function(){}, |
|
| 934 | ||
| 935 | // Called when element reaches top of context |
|
| 936 | onTop : function(){}, |
|
| 937 | ||
| 938 | // Called when element reaches bottom of context |
|
| 939 | onBottom : function(){}, |
|
| 940 | ||
| 941 | error : { |
|
| 942 | container : 'Sticky element must be inside a relative container', |
|
| 943 | visible : 'Element is hidden, you must call refresh after element becomes visible. Use silent setting to surpress this warning in production.', |
|
| 944 | method : 'The method you called is not defined.', |
|
| 945 | invalidContext : 'Context specified does not exist', |
|
| 946 | elementSize : 'Sticky element is larger than its container, cannot create sticky.' |
|
| 947 | }, |
|
| 948 | ||
| 949 | className : { |
|
| 950 | bound : 'bound', |
|
| 951 | fixed : 'fixed', |
|
| 952 | supported : 'native', |
|
| 953 | top : 'top', |
|
| 954 | bottom : 'bottom' |
|
| 955 | } |
|
| 956 | ||
| 957 | }; |
|
| 958 | ||
| 959 | })( jQuery, window, document ); |
|
| 960 | ||