| @@ 21583-22883 (lines=1301) @@ | ||
| 21580 | * |
|
| 21581 | */ |
|
| 21582 | ||
| 21583 | ;(function ($, window, document, undefined) { |
|
| 21584 | ||
| 21585 | "use strict"; |
|
| 21586 | ||
| 21587 | window = (typeof window != 'undefined' && window.Math == Math) |
|
| 21588 | ? window |
|
| 21589 | : (typeof self != 'undefined' && self.Math == Math) |
|
| 21590 | ? self |
|
| 21591 | : Function('return this')() |
|
| 21592 | ; |
|
| 21593 | ||
| 21594 | $.fn.visibility = function(parameters) { |
|
| 21595 | var |
|
| 21596 | $allModules = $(this), |
|
| 21597 | moduleSelector = $allModules.selector || '', |
|
| 21598 | ||
| 21599 | time = new Date().getTime(), |
|
| 21600 | performance = [], |
|
| 21601 | ||
| 21602 | query = arguments[0], |
|
| 21603 | methodInvoked = (typeof query == 'string'), |
|
| 21604 | queryArguments = [].slice.call(arguments, 1), |
|
| 21605 | returnedValue, |
|
| 21606 | ||
| 21607 | moduleCount = $allModules.length, |
|
| 21608 | loadedCount = 0 |
|
| 21609 | ; |
|
| 21610 | ||
| 21611 | $allModules |
|
| 21612 | .each(function() { |
|
| 21613 | var |
|
| 21614 | settings = ( $.isPlainObject(parameters) ) |
|
| 21615 | ? $.extend(true, {}, $.fn.visibility.settings, parameters) |
|
| 21616 | : $.extend({}, $.fn.visibility.settings), |
|
| 21617 | ||
| 21618 | className = settings.className, |
|
| 21619 | namespace = settings.namespace, |
|
| 21620 | error = settings.error, |
|
| 21621 | metadata = settings.metadata, |
|
| 21622 | ||
| 21623 | eventNamespace = '.' + namespace, |
|
| 21624 | moduleNamespace = 'module-' + namespace, |
|
| 21625 | ||
| 21626 | $window = $(window), |
|
| 21627 | ||
| 21628 | $module = $(this), |
|
| 21629 | $context = $(settings.context), |
|
| 21630 | ||
| 21631 | $placeholder, |
|
| 21632 | ||
| 21633 | selector = $module.selector || '', |
|
| 21634 | instance = $module.data(moduleNamespace), |
|
| 21635 | ||
| 21636 | requestAnimationFrame = window.requestAnimationFrame |
|
| 21637 | || window.mozRequestAnimationFrame |
|
| 21638 | || window.webkitRequestAnimationFrame |
|
| 21639 | || window.msRequestAnimationFrame |
|
| 21640 | || function(callback) { setTimeout(callback, 0); }, |
|
| 21641 | ||
| 21642 | element = this, |
|
| 21643 | disabled = false, |
|
| 21644 | ||
| 21645 | contextObserver, |
|
| 21646 | observer, |
|
| 21647 | module |
|
| 21648 | ; |
|
| 21649 | ||
| 21650 | module = { |
|
| 21651 | ||
| 21652 | initialize: function() { |
|
| 21653 | module.debug('Initializing', settings); |
|
| 21654 | ||
| 21655 | module.setup.cache(); |
|
| 21656 | ||
| 21657 | if( module.should.trackChanges() ) { |
|
| 21658 | ||
| 21659 | if(settings.type == 'image') { |
|
| 21660 | module.setup.image(); |
|
| 21661 | } |
|
| 21662 | if(settings.type == 'fixed') { |
|
| 21663 | module.setup.fixed(); |
|
| 21664 | } |
|
| 21665 | ||
| 21666 | if(settings.observeChanges) { |
|
| 21667 | module.observeChanges(); |
|
| 21668 | } |
|
| 21669 | module.bind.events(); |
|
| 21670 | } |
|
| 21671 | ||
| 21672 | module.save.position(); |
|
| 21673 | if( !module.is.visible() ) { |
|
| 21674 | module.error(error.visible, $module); |
|
| 21675 | } |
|
| 21676 | ||
| 21677 | if(settings.initialCheck) { |
|
| 21678 | module.checkVisibility(); |
|
| 21679 | } |
|
| 21680 | module.instantiate(); |
|
| 21681 | }, |
|
| 21682 | ||
| 21683 | instantiate: function() { |
|
| 21684 | module.debug('Storing instance', module); |
|
| 21685 | $module |
|
| 21686 | .data(moduleNamespace, module) |
|
| 21687 | ; |
|
| 21688 | instance = module; |
|
| 21689 | }, |
|
| 21690 | ||
| 21691 | destroy: function() { |
|
| 21692 | module.verbose('Destroying previous module'); |
|
| 21693 | if(observer) { |
|
| 21694 | observer.disconnect(); |
|
| 21695 | } |
|
| 21696 | if(contextObserver) { |
|
| 21697 | contextObserver.disconnect(); |
|
| 21698 | } |
|
| 21699 | $window |
|
| 21700 | .off('load' + eventNamespace, module.event.load) |
|
| 21701 | .off('resize' + eventNamespace, module.event.resize) |
|
| 21702 | ; |
|
| 21703 | $context |
|
| 21704 | .off('scroll' + eventNamespace, module.event.scroll) |
|
| 21705 | .off('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 21706 | ; |
|
| 21707 | if(settings.type == 'fixed') { |
|
| 21708 | module.resetFixed(); |
|
| 21709 | module.remove.placeholder(); |
|
| 21710 | } |
|
| 21711 | $module |
|
| 21712 | .off(eventNamespace) |
|
| 21713 | .removeData(moduleNamespace) |
|
| 21714 | ; |
|
| 21715 | }, |
|
| 21716 | ||
| 21717 | observeChanges: function() { |
|
| 21718 | if('MutationObserver' in window) { |
|
| 21719 | contextObserver = new MutationObserver(module.event.contextChanged); |
|
| 21720 | observer = new MutationObserver(module.event.changed); |
|
| 21721 | contextObserver.observe(document, { |
|
| 21722 | childList : true, |
|
| 21723 | subtree : true |
|
| 21724 | }); |
|
| 21725 | observer.observe(element, { |
|
| 21726 | childList : true, |
|
| 21727 | subtree : true |
|
| 21728 | }); |
|
| 21729 | module.debug('Setting up mutation observer', observer); |
|
| 21730 | } |
|
| 21731 | }, |
|
| 21732 | ||
| 21733 | bind: { |
|
| 21734 | events: function() { |
|
| 21735 | module.verbose('Binding visibility events to scroll and resize'); |
|
| 21736 | if(settings.refreshOnLoad) { |
|
| 21737 | $window |
|
| 21738 | .on('load' + eventNamespace, module.event.load) |
|
| 21739 | ; |
|
| 21740 | } |
|
| 21741 | $window |
|
| 21742 | .on('resize' + eventNamespace, module.event.resize) |
|
| 21743 | ; |
|
| 21744 | // pub/sub pattern |
|
| 21745 | $context |
|
| 21746 | .off('scroll' + eventNamespace) |
|
| 21747 | .on('scroll' + eventNamespace, module.event.scroll) |
|
| 21748 | .on('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 21749 | ; |
|
| 21750 | } |
|
| 21751 | }, |
|
| 21752 | ||
| 21753 | event: { |
|
| 21754 | changed: function(mutations) { |
|
| 21755 | module.verbose('DOM tree modified, updating visibility calculations'); |
|
| 21756 | module.timer = setTimeout(function() { |
|
| 21757 | module.verbose('DOM tree modified, updating sticky menu'); |
|
| 21758 | module.refresh(); |
|
| 21759 | }, 100); |
|
| 21760 | }, |
|
| 21761 | contextChanged: function(mutations) { |
|
| 21762 | [].forEach.call(mutations, function(mutation) { |
|
| 21763 | if(mutation.removedNodes) { |
|
| 21764 | [].forEach.call(mutation.removedNodes, function(node) { |
|
| 21765 | if(node == element || $(node).find(element).length > 0) { |
|
| 21766 | module.debug('Element removed from DOM, tearing down events'); |
|
| 21767 | module.destroy(); |
|
| 21768 | } |
|
| 21769 | }); |
|
| 21770 | } |
|
| 21771 | }); |
|
| 21772 | }, |
|
| 21773 | resize: function() { |
|
| 21774 | module.debug('Window resized'); |
|
| 21775 | if(settings.refreshOnResize) { |
|
| 21776 | requestAnimationFrame(module.refresh); |
|
| 21777 | } |
|
| 21778 | }, |
|
| 21779 | load: function() { |
|
| 21780 | module.debug('Page finished loading'); |
|
| 21781 | requestAnimationFrame(module.refresh); |
|
| 21782 | }, |
|
| 21783 | // publishes scrollchange event on one scroll |
|
| 21784 | scroll: function() { |
|
| 21785 | if(settings.throttle) { |
|
| 21786 | clearTimeout(module.timer); |
|
| 21787 | module.timer = setTimeout(function() { |
|
| 21788 | $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]); |
|
| 21789 | }, settings.throttle); |
|
| 21790 | } |
|
| 21791 | else { |
|
| 21792 | requestAnimationFrame(function() { |
|
| 21793 | $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]); |
|
| 21794 | }); |
|
| 21795 | } |
|
| 21796 | }, |
|
| 21797 | // subscribes to scrollchange |
|
| 21798 | scrollchange: function(event, scrollPosition) { |
|
| 21799 | module.checkVisibility(scrollPosition); |
|
| 21800 | }, |
|
| 21801 | }, |
|
| 21802 | ||
| 21803 | precache: function(images, callback) { |
|
| 21804 | if (!(images instanceof Array)) { |
|
| 21805 | images = [images]; |
|
| 21806 | } |
|
| 21807 | var |
|
| 21808 | imagesLength = images.length, |
|
| 21809 | loadedCounter = 0, |
|
| 21810 | cache = [], |
|
| 21811 | cacheImage = document.createElement('img'), |
|
| 21812 | handleLoad = function() { |
|
| 21813 | loadedCounter++; |
|
| 21814 | if (loadedCounter >= images.length) { |
|
| 21815 | if ($.isFunction(callback)) { |
|
| 21816 | callback(); |
|
| 21817 | } |
|
| 21818 | } |
|
| 21819 | } |
|
| 21820 | ; |
|
| 21821 | while (imagesLength--) { |
|
| 21822 | cacheImage = document.createElement('img'); |
|
| 21823 | cacheImage.onload = handleLoad; |
|
| 21824 | cacheImage.onerror = handleLoad; |
|
| 21825 | cacheImage.src = images[imagesLength]; |
|
| 21826 | cache.push(cacheImage); |
|
| 21827 | } |
|
| 21828 | }, |
|
| 21829 | ||
| 21830 | enableCallbacks: function() { |
|
| 21831 | module.debug('Allowing callbacks to occur'); |
|
| 21832 | disabled = false; |
|
| 21833 | }, |
|
| 21834 | ||
| 21835 | disableCallbacks: function() { |
|
| 21836 | module.debug('Disabling all callbacks temporarily'); |
|
| 21837 | disabled = true; |
|
| 21838 | }, |
|
| 21839 | ||
| 21840 | should: { |
|
| 21841 | trackChanges: function() { |
|
| 21842 | if(methodInvoked) { |
|
| 21843 | module.debug('One time query, no need to bind events'); |
|
| 21844 | return false; |
|
| 21845 | } |
|
| 21846 | module.debug('Callbacks being attached'); |
|
| 21847 | return true; |
|
| 21848 | } |
|
| 21849 | }, |
|
| 21850 | ||
| 21851 | setup: { |
|
| 21852 | cache: function() { |
|
| 21853 | module.cache = { |
|
| 21854 | occurred : {}, |
|
| 21855 | screen : {}, |
|
| 21856 | element : {}, |
|
| 21857 | }; |
|
| 21858 | }, |
|
| 21859 | image: function() { |
|
| 21860 | var |
|
| 21861 | src = $module.data(metadata.src) |
|
| 21862 | ; |
|
| 21863 | if(src) { |
|
| 21864 | module.verbose('Lazy loading image', src); |
|
| 21865 | settings.once = true; |
|
| 21866 | settings.observeChanges = false; |
|
| 21867 | ||
| 21868 | // show when top visible |
|
| 21869 | settings.onOnScreen = function() { |
|
| 21870 | module.debug('Image on screen', element); |
|
| 21871 | module.precache(src, function() { |
|
| 21872 | module.set.image(src, function() { |
|
| 21873 | loadedCount++; |
|
| 21874 | if(loadedCount == moduleCount) { |
|
| 21875 | settings.onAllLoaded.call(this); |
|
| 21876 | } |
|
| 21877 | settings.onLoad.call(this); |
|
| 21878 | }); |
|
| 21879 | }); |
|
| 21880 | }; |
|
| 21881 | } |
|
| 21882 | }, |
|
| 21883 | fixed: function() { |
|
| 21884 | module.debug('Setting up fixed'); |
|
| 21885 | settings.once = false; |
|
| 21886 | settings.observeChanges = false; |
|
| 21887 | settings.initialCheck = true; |
|
| 21888 | settings.refreshOnLoad = true; |
|
| 21889 | if(!parameters.transition) { |
|
| 21890 | settings.transition = false; |
|
| 21891 | } |
|
| 21892 | module.create.placeholder(); |
|
| 21893 | module.debug('Added placeholder', $placeholder); |
|
| 21894 | settings.onTopPassed = function() { |
|
| 21895 | module.debug('Element passed, adding fixed position', $module); |
|
| 21896 | module.show.placeholder(); |
|
| 21897 | module.set.fixed(); |
|
| 21898 | if(settings.transition) { |
|
| 21899 | if($.fn.transition !== undefined) { |
|
| 21900 | $module.transition(settings.transition, settings.duration); |
|
| 21901 | } |
|
| 21902 | } |
|
| 21903 | }; |
|
| 21904 | settings.onTopPassedReverse = function() { |
|
| 21905 | module.debug('Element returned to position, removing fixed', $module); |
|
| 21906 | module.hide.placeholder(); |
|
| 21907 | module.remove.fixed(); |
|
| 21908 | }; |
|
| 21909 | } |
|
| 21910 | }, |
|
| 21911 | ||
| 21912 | create: { |
|
| 21913 | placeholder: function() { |
|
| 21914 | module.verbose('Creating fixed position placeholder'); |
|
| 21915 | $placeholder = $module |
|
| 21916 | .clone(false) |
|
| 21917 | .css('display', 'none') |
|
| 21918 | .addClass(className.placeholder) |
|
| 21919 | .insertAfter($module) |
|
| 21920 | ; |
|
| 21921 | } |
|
| 21922 | }, |
|
| 21923 | ||
| 21924 | show: { |
|
| 21925 | placeholder: function() { |
|
| 21926 | module.verbose('Showing placeholder'); |
|
| 21927 | $placeholder |
|
| 21928 | .css('display', 'block') |
|
| 21929 | .css('visibility', 'hidden') |
|
| 21930 | ; |
|
| 21931 | } |
|
| 21932 | }, |
|
| 21933 | hide: { |
|
| 21934 | placeholder: function() { |
|
| 21935 | module.verbose('Hiding placeholder'); |
|
| 21936 | $placeholder |
|
| 21937 | .css('display', 'none') |
|
| 21938 | .css('visibility', '') |
|
| 21939 | ; |
|
| 21940 | } |
|
| 21941 | }, |
|
| 21942 | ||
| 21943 | set: { |
|
| 21944 | fixed: function() { |
|
| 21945 | module.verbose('Setting element to fixed position'); |
|
| 21946 | $module |
|
| 21947 | .addClass(className.fixed) |
|
| 21948 | .css({ |
|
| 21949 | position : 'fixed', |
|
| 21950 | top : settings.offset + 'px', |
|
| 21951 | left : 'auto', |
|
| 21952 | zIndex : settings.zIndex |
|
| 21953 | }) |
|
| 21954 | ; |
|
| 21955 | settings.onFixed.call(element); |
|
| 21956 | }, |
|
| 21957 | image: function(src, callback) { |
|
| 21958 | $module |
|
| 21959 | .attr('src', src) |
|
| 21960 | ; |
|
| 21961 | if(settings.transition) { |
|
| 21962 | if( $.fn.transition !== undefined) { |
|
| 21963 | if($module.hasClass(className.visible)) { |
|
| 21964 | module.debug('Transition already occurred on this image, skipping animation'); |
|
| 21965 | return; |
|
| 21966 | } |
|
| 21967 | $module.transition(settings.transition, settings.duration, callback); |
|
| 21968 | } |
|
| 21969 | else { |
|
| 21970 | $module.fadeIn(settings.duration, callback); |
|
| 21971 | } |
|
| 21972 | } |
|
| 21973 | else { |
|
| 21974 | $module.show(); |
|
| 21975 | } |
|
| 21976 | } |
|
| 21977 | }, |
|
| 21978 | ||
| 21979 | is: { |
|
| 21980 | onScreen: function() { |
|
| 21981 | var |
|
| 21982 | calculations = module.get.elementCalculations() |
|
| 21983 | ; |
|
| 21984 | return calculations.onScreen; |
|
| 21985 | }, |
|
| 21986 | offScreen: function() { |
|
| 21987 | var |
|
| 21988 | calculations = module.get.elementCalculations() |
|
| 21989 | ; |
|
| 21990 | return calculations.offScreen; |
|
| 21991 | }, |
|
| 21992 | visible: function() { |
|
| 21993 | if(module.cache && module.cache.element) { |
|
| 21994 | return !(module.cache.element.width === 0 && module.cache.element.offset.top === 0); |
|
| 21995 | } |
|
| 21996 | return false; |
|
| 21997 | }, |
|
| 21998 | verticallyScrollableContext: function() { |
|
| 21999 | var |
|
| 22000 | overflowY = ($context.get(0) !== window) |
|
| 22001 | ? $context.css('overflow-y') |
|
| 22002 | : false |
|
| 22003 | ; |
|
| 22004 | return (overflowY == 'auto' || overflowY == 'scroll'); |
|
| 22005 | }, |
|
| 22006 | horizontallyScrollableContext: function() { |
|
| 22007 | var |
|
| 22008 | overflowX = ($context.get(0) !== window) |
|
| 22009 | ? $context.css('overflow-x') |
|
| 22010 | : false |
|
| 22011 | ; |
|
| 22012 | return (overflowX == 'auto' || overflowX == 'scroll'); |
|
| 22013 | } |
|
| 22014 | }, |
|
| 22015 | ||
| 22016 | refresh: function() { |
|
| 22017 | module.debug('Refreshing constants (width/height)'); |
|
| 22018 | if(settings.type == 'fixed') { |
|
| 22019 | module.resetFixed(); |
|
| 22020 | } |
|
| 22021 | module.reset(); |
|
| 22022 | module.save.position(); |
|
| 22023 | if(settings.checkOnRefresh) { |
|
| 22024 | module.checkVisibility(); |
|
| 22025 | } |
|
| 22026 | settings.onRefresh.call(element); |
|
| 22027 | }, |
|
| 22028 | ||
| 22029 | resetFixed: function () { |
|
| 22030 | module.remove.fixed(); |
|
| 22031 | module.remove.occurred(); |
|
| 22032 | }, |
|
| 22033 | ||
| 22034 | reset: function() { |
|
| 22035 | module.verbose('Resetting all cached values'); |
|
| 22036 | if( $.isPlainObject(module.cache) ) { |
|
| 22037 | module.cache.screen = {}; |
|
| 22038 | module.cache.element = {}; |
|
| 22039 | } |
|
| 22040 | }, |
|
| 22041 | ||
| 22042 | checkVisibility: function(scroll) { |
|
| 22043 | module.verbose('Checking visibility of element', module.cache.element); |
|
| 22044 | ||
| 22045 | if( !disabled && module.is.visible() ) { |
|
| 22046 | ||
| 22047 | // save scroll position |
|
| 22048 | module.save.scroll(scroll); |
|
| 22049 | ||
| 22050 | // update calculations derived from scroll |
|
| 22051 | module.save.calculations(); |
|
| 22052 | ||
| 22053 | // percentage |
|
| 22054 | module.passed(); |
|
| 22055 | ||
| 22056 | // reverse (must be first) |
|
| 22057 | module.passingReverse(); |
|
| 22058 | module.topVisibleReverse(); |
|
| 22059 | module.bottomVisibleReverse(); |
|
| 22060 | module.topPassedReverse(); |
|
| 22061 | module.bottomPassedReverse(); |
|
| 22062 | ||
| 22063 | // one time |
|
| 22064 | module.onScreen(); |
|
| 22065 | module.offScreen(); |
|
| 22066 | module.passing(); |
|
| 22067 | module.topVisible(); |
|
| 22068 | module.bottomVisible(); |
|
| 22069 | module.topPassed(); |
|
| 22070 | module.bottomPassed(); |
|
| 22071 | ||
| 22072 | // on update callback |
|
| 22073 | if(settings.onUpdate) { |
|
| 22074 | settings.onUpdate.call(element, module.get.elementCalculations()); |
|
| 22075 | } |
|
| 22076 | } |
|
| 22077 | }, |
|
| 22078 | ||
| 22079 | passed: function(amount, newCallback) { |
|
| 22080 | var |
|
| 22081 | calculations = module.get.elementCalculations(), |
|
| 22082 | amountInPixels |
|
| 22083 | ; |
|
| 22084 | // assign callback |
|
| 22085 | if(amount && newCallback) { |
|
| 22086 | settings.onPassed[amount] = newCallback; |
|
| 22087 | } |
|
| 22088 | else if(amount !== undefined) { |
|
| 22089 | return (module.get.pixelsPassed(amount) > calculations.pixelsPassed); |
|
| 22090 | } |
|
| 22091 | else if(calculations.passing) { |
|
| 22092 | $.each(settings.onPassed, function(amount, callback) { |
|
| 22093 | if(calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) { |
|
| 22094 | module.execute(callback, amount); |
|
| 22095 | } |
|
| 22096 | else if(!settings.once) { |
|
| 22097 | module.remove.occurred(callback); |
|
| 22098 | } |
|
| 22099 | }); |
|
| 22100 | } |
|
| 22101 | }, |
|
| 22102 | ||
| 22103 | onScreen: function(newCallback) { |
|
| 22104 | var |
|
| 22105 | calculations = module.get.elementCalculations(), |
|
| 22106 | callback = newCallback || settings.onOnScreen, |
|
| 22107 | callbackName = 'onScreen' |
|
| 22108 | ; |
|
| 22109 | if(newCallback) { |
|
| 22110 | module.debug('Adding callback for onScreen', newCallback); |
|
| 22111 | settings.onOnScreen = newCallback; |
|
| 22112 | } |
|
| 22113 | if(calculations.onScreen) { |
|
| 22114 | module.execute(callback, callbackName); |
|
| 22115 | } |
|
| 22116 | else if(!settings.once) { |
|
| 22117 | module.remove.occurred(callbackName); |
|
| 22118 | } |
|
| 22119 | if(newCallback !== undefined) { |
|
| 22120 | return calculations.onOnScreen; |
|
| 22121 | } |
|
| 22122 | }, |
|
| 22123 | ||
| 22124 | offScreen: function(newCallback) { |
|
| 22125 | var |
|
| 22126 | calculations = module.get.elementCalculations(), |
|
| 22127 | callback = newCallback || settings.onOffScreen, |
|
| 22128 | callbackName = 'offScreen' |
|
| 22129 | ; |
|
| 22130 | if(newCallback) { |
|
| 22131 | module.debug('Adding callback for offScreen', newCallback); |
|
| 22132 | settings.onOffScreen = newCallback; |
|
| 22133 | } |
|
| 22134 | if(calculations.offScreen) { |
|
| 22135 | module.execute(callback, callbackName); |
|
| 22136 | } |
|
| 22137 | else if(!settings.once) { |
|
| 22138 | module.remove.occurred(callbackName); |
|
| 22139 | } |
|
| 22140 | if(newCallback !== undefined) { |
|
| 22141 | return calculations.onOffScreen; |
|
| 22142 | } |
|
| 22143 | }, |
|
| 22144 | ||
| 22145 | passing: function(newCallback) { |
|
| 22146 | var |
|
| 22147 | calculations = module.get.elementCalculations(), |
|
| 22148 | callback = newCallback || settings.onPassing, |
|
| 22149 | callbackName = 'passing' |
|
| 22150 | ; |
|
| 22151 | if(newCallback) { |
|
| 22152 | module.debug('Adding callback for passing', newCallback); |
|
| 22153 | settings.onPassing = newCallback; |
|
| 22154 | } |
|
| 22155 | if(calculations.passing) { |
|
| 22156 | module.execute(callback, callbackName); |
|
| 22157 | } |
|
| 22158 | else if(!settings.once) { |
|
| 22159 | module.remove.occurred(callbackName); |
|
| 22160 | } |
|
| 22161 | if(newCallback !== undefined) { |
|
| 22162 | return calculations.passing; |
|
| 22163 | } |
|
| 22164 | }, |
|
| 22165 | ||
| 22166 | ||
| 22167 | topVisible: function(newCallback) { |
|
| 22168 | var |
|
| 22169 | calculations = module.get.elementCalculations(), |
|
| 22170 | callback = newCallback || settings.onTopVisible, |
|
| 22171 | callbackName = 'topVisible' |
|
| 22172 | ; |
|
| 22173 | if(newCallback) { |
|
| 22174 | module.debug('Adding callback for top visible', newCallback); |
|
| 22175 | settings.onTopVisible = newCallback; |
|
| 22176 | } |
|
| 22177 | if(calculations.topVisible) { |
|
| 22178 | module.execute(callback, callbackName); |
|
| 22179 | } |
|
| 22180 | else if(!settings.once) { |
|
| 22181 | module.remove.occurred(callbackName); |
|
| 22182 | } |
|
| 22183 | if(newCallback === undefined) { |
|
| 22184 | return calculations.topVisible; |
|
| 22185 | } |
|
| 22186 | }, |
|
| 22187 | ||
| 22188 | bottomVisible: function(newCallback) { |
|
| 22189 | var |
|
| 22190 | calculations = module.get.elementCalculations(), |
|
| 22191 | callback = newCallback || settings.onBottomVisible, |
|
| 22192 | callbackName = 'bottomVisible' |
|
| 22193 | ; |
|
| 22194 | if(newCallback) { |
|
| 22195 | module.debug('Adding callback for bottom visible', newCallback); |
|
| 22196 | settings.onBottomVisible = newCallback; |
|
| 22197 | } |
|
| 22198 | if(calculations.bottomVisible) { |
|
| 22199 | module.execute(callback, callbackName); |
|
| 22200 | } |
|
| 22201 | else if(!settings.once) { |
|
| 22202 | module.remove.occurred(callbackName); |
|
| 22203 | } |
|
| 22204 | if(newCallback === undefined) { |
|
| 22205 | return calculations.bottomVisible; |
|
| 22206 | } |
|
| 22207 | }, |
|
| 22208 | ||
| 22209 | topPassed: function(newCallback) { |
|
| 22210 | var |
|
| 22211 | calculations = module.get.elementCalculations(), |
|
| 22212 | callback = newCallback || settings.onTopPassed, |
|
| 22213 | callbackName = 'topPassed' |
|
| 22214 | ; |
|
| 22215 | if(newCallback) { |
|
| 22216 | module.debug('Adding callback for top passed', newCallback); |
|
| 22217 | settings.onTopPassed = newCallback; |
|
| 22218 | } |
|
| 22219 | if(calculations.topPassed) { |
|
| 22220 | module.execute(callback, callbackName); |
|
| 22221 | } |
|
| 22222 | else if(!settings.once) { |
|
| 22223 | module.remove.occurred(callbackName); |
|
| 22224 | } |
|
| 22225 | if(newCallback === undefined) { |
|
| 22226 | return calculations.topPassed; |
|
| 22227 | } |
|
| 22228 | }, |
|
| 22229 | ||
| 22230 | bottomPassed: function(newCallback) { |
|
| 22231 | var |
|
| 22232 | calculations = module.get.elementCalculations(), |
|
| 22233 | callback = newCallback || settings.onBottomPassed, |
|
| 22234 | callbackName = 'bottomPassed' |
|
| 22235 | ; |
|
| 22236 | if(newCallback) { |
|
| 22237 | module.debug('Adding callback for bottom passed', newCallback); |
|
| 22238 | settings.onBottomPassed = newCallback; |
|
| 22239 | } |
|
| 22240 | if(calculations.bottomPassed) { |
|
| 22241 | module.execute(callback, callbackName); |
|
| 22242 | } |
|
| 22243 | else if(!settings.once) { |
|
| 22244 | module.remove.occurred(callbackName); |
|
| 22245 | } |
|
| 22246 | if(newCallback === undefined) { |
|
| 22247 | return calculations.bottomPassed; |
|
| 22248 | } |
|
| 22249 | }, |
|
| 22250 | ||
| 22251 | passingReverse: function(newCallback) { |
|
| 22252 | var |
|
| 22253 | calculations = module.get.elementCalculations(), |
|
| 22254 | callback = newCallback || settings.onPassingReverse, |
|
| 22255 | callbackName = 'passingReverse' |
|
| 22256 | ; |
|
| 22257 | if(newCallback) { |
|
| 22258 | module.debug('Adding callback for passing reverse', newCallback); |
|
| 22259 | settings.onPassingReverse = newCallback; |
|
| 22260 | } |
|
| 22261 | if(!calculations.passing) { |
|
| 22262 | if(module.get.occurred('passing')) { |
|
| 22263 | module.execute(callback, callbackName); |
|
| 22264 | } |
|
| 22265 | } |
|
| 22266 | else if(!settings.once) { |
|
| 22267 | module.remove.occurred(callbackName); |
|
| 22268 | } |
|
| 22269 | if(newCallback !== undefined) { |
|
| 22270 | return !calculations.passing; |
|
| 22271 | } |
|
| 22272 | }, |
|
| 22273 | ||
| 22274 | ||
| 22275 | topVisibleReverse: function(newCallback) { |
|
| 22276 | var |
|
| 22277 | calculations = module.get.elementCalculations(), |
|
| 22278 | callback = newCallback || settings.onTopVisibleReverse, |
|
| 22279 | callbackName = 'topVisibleReverse' |
|
| 22280 | ; |
|
| 22281 | if(newCallback) { |
|
| 22282 | module.debug('Adding callback for top visible reverse', newCallback); |
|
| 22283 | settings.onTopVisibleReverse = newCallback; |
|
| 22284 | } |
|
| 22285 | if(!calculations.topVisible) { |
|
| 22286 | if(module.get.occurred('topVisible')) { |
|
| 22287 | module.execute(callback, callbackName); |
|
| 22288 | } |
|
| 22289 | } |
|
| 22290 | else if(!settings.once) { |
|
| 22291 | module.remove.occurred(callbackName); |
|
| 22292 | } |
|
| 22293 | if(newCallback === undefined) { |
|
| 22294 | return !calculations.topVisible; |
|
| 22295 | } |
|
| 22296 | }, |
|
| 22297 | ||
| 22298 | bottomVisibleReverse: function(newCallback) { |
|
| 22299 | var |
|
| 22300 | calculations = module.get.elementCalculations(), |
|
| 22301 | callback = newCallback || settings.onBottomVisibleReverse, |
|
| 22302 | callbackName = 'bottomVisibleReverse' |
|
| 22303 | ; |
|
| 22304 | if(newCallback) { |
|
| 22305 | module.debug('Adding callback for bottom visible reverse', newCallback); |
|
| 22306 | settings.onBottomVisibleReverse = newCallback; |
|
| 22307 | } |
|
| 22308 | if(!calculations.bottomVisible) { |
|
| 22309 | if(module.get.occurred('bottomVisible')) { |
|
| 22310 | module.execute(callback, callbackName); |
|
| 22311 | } |
|
| 22312 | } |
|
| 22313 | else if(!settings.once) { |
|
| 22314 | module.remove.occurred(callbackName); |
|
| 22315 | } |
|
| 22316 | if(newCallback === undefined) { |
|
| 22317 | return !calculations.bottomVisible; |
|
| 22318 | } |
|
| 22319 | }, |
|
| 22320 | ||
| 22321 | topPassedReverse: function(newCallback) { |
|
| 22322 | var |
|
| 22323 | calculations = module.get.elementCalculations(), |
|
| 22324 | callback = newCallback || settings.onTopPassedReverse, |
|
| 22325 | callbackName = 'topPassedReverse' |
|
| 22326 | ; |
|
| 22327 | if(newCallback) { |
|
| 22328 | module.debug('Adding callback for top passed reverse', newCallback); |
|
| 22329 | settings.onTopPassedReverse = newCallback; |
|
| 22330 | } |
|
| 22331 | if(!calculations.topPassed) { |
|
| 22332 | if(module.get.occurred('topPassed')) { |
|
| 22333 | module.execute(callback, callbackName); |
|
| 22334 | } |
|
| 22335 | } |
|
| 22336 | else if(!settings.once) { |
|
| 22337 | module.remove.occurred(callbackName); |
|
| 22338 | } |
|
| 22339 | if(newCallback === undefined) { |
|
| 22340 | return !calculations.onTopPassed; |
|
| 22341 | } |
|
| 22342 | }, |
|
| 22343 | ||
| 22344 | bottomPassedReverse: function(newCallback) { |
|
| 22345 | var |
|
| 22346 | calculations = module.get.elementCalculations(), |
|
| 22347 | callback = newCallback || settings.onBottomPassedReverse, |
|
| 22348 | callbackName = 'bottomPassedReverse' |
|
| 22349 | ; |
|
| 22350 | if(newCallback) { |
|
| 22351 | module.debug('Adding callback for bottom passed reverse', newCallback); |
|
| 22352 | settings.onBottomPassedReverse = newCallback; |
|
| 22353 | } |
|
| 22354 | if(!calculations.bottomPassed) { |
|
| 22355 | if(module.get.occurred('bottomPassed')) { |
|
| 22356 | module.execute(callback, callbackName); |
|
| 22357 | } |
|
| 22358 | } |
|
| 22359 | else if(!settings.once) { |
|
| 22360 | module.remove.occurred(callbackName); |
|
| 22361 | } |
|
| 22362 | if(newCallback === undefined) { |
|
| 22363 | return !calculations.bottomPassed; |
|
| 22364 | } |
|
| 22365 | }, |
|
| 22366 | ||
| 22367 | execute: function(callback, callbackName) { |
|
| 22368 | var |
|
| 22369 | calculations = module.get.elementCalculations(), |
|
| 22370 | screen = module.get.screenCalculations() |
|
| 22371 | ; |
|
| 22372 | callback = callback || false; |
|
| 22373 | if(callback) { |
|
| 22374 | if(settings.continuous) { |
|
| 22375 | module.debug('Callback being called continuously', callbackName, calculations); |
|
| 22376 | callback.call(element, calculations, screen); |
|
| 22377 | } |
|
| 22378 | else if(!module.get.occurred(callbackName)) { |
|
| 22379 | module.debug('Conditions met', callbackName, calculations); |
|
| 22380 | callback.call(element, calculations, screen); |
|
| 22381 | } |
|
| 22382 | } |
|
| 22383 | module.save.occurred(callbackName); |
|
| 22384 | }, |
|
| 22385 | ||
| 22386 | remove: { |
|
| 22387 | fixed: function() { |
|
| 22388 | module.debug('Removing fixed position'); |
|
| 22389 | $module |
|
| 22390 | .removeClass(className.fixed) |
|
| 22391 | .css({ |
|
| 22392 | position : '', |
|
| 22393 | top : '', |
|
| 22394 | left : '', |
|
| 22395 | zIndex : '' |
|
| 22396 | }) |
|
| 22397 | ; |
|
| 22398 | settings.onUnfixed.call(element); |
|
| 22399 | }, |
|
| 22400 | placeholder: function() { |
|
| 22401 | module.debug('Removing placeholder content'); |
|
| 22402 | if($placeholder) { |
|
| 22403 | $placeholder.remove(); |
|
| 22404 | } |
|
| 22405 | }, |
|
| 22406 | occurred: function(callback) { |
|
| 22407 | if(callback) { |
|
| 22408 | var |
|
| 22409 | occurred = module.cache.occurred |
|
| 22410 | ; |
|
| 22411 | if(occurred[callback] !== undefined && occurred[callback] === true) { |
|
| 22412 | module.debug('Callback can now be called again', callback); |
|
| 22413 | module.cache.occurred[callback] = false; |
|
| 22414 | } |
|
| 22415 | } |
|
| 22416 | else { |
|
| 22417 | module.cache.occurred = {}; |
|
| 22418 | } |
|
| 22419 | } |
|
| 22420 | }, |
|
| 22421 | ||
| 22422 | save: { |
|
| 22423 | calculations: function() { |
|
| 22424 | module.verbose('Saving all calculations necessary to determine positioning'); |
|
| 22425 | module.save.direction(); |
|
| 22426 | module.save.screenCalculations(); |
|
| 22427 | module.save.elementCalculations(); |
|
| 22428 | }, |
|
| 22429 | occurred: function(callback) { |
|
| 22430 | if(callback) { |
|
| 22431 | if(module.cache.occurred[callback] === undefined || (module.cache.occurred[callback] !== true)) { |
|
| 22432 | module.verbose('Saving callback occurred', callback); |
|
| 22433 | module.cache.occurred[callback] = true; |
|
| 22434 | } |
|
| 22435 | } |
|
| 22436 | }, |
|
| 22437 | scroll: function(scrollPosition) { |
|
| 22438 | scrollPosition = scrollPosition + settings.offset || $context.scrollTop() + settings.offset; |
|
| 22439 | module.cache.scroll = scrollPosition; |
|
| 22440 | }, |
|
| 22441 | direction: function() { |
|
| 22442 | var |
|
| 22443 | scroll = module.get.scroll(), |
|
| 22444 | lastScroll = module.get.lastScroll(), |
|
| 22445 | direction |
|
| 22446 | ; |
|
| 22447 | if(scroll > lastScroll && lastScroll) { |
|
| 22448 | direction = 'down'; |
|
| 22449 | } |
|
| 22450 | else if(scroll < lastScroll && lastScroll) { |
|
| 22451 | direction = 'up'; |
|
| 22452 | } |
|
| 22453 | else { |
|
| 22454 | direction = 'static'; |
|
| 22455 | } |
|
| 22456 | module.cache.direction = direction; |
|
| 22457 | return module.cache.direction; |
|
| 22458 | }, |
|
| 22459 | elementPosition: function() { |
|
| 22460 | var |
|
| 22461 | element = module.cache.element, |
|
| 22462 | screen = module.get.screenSize() |
|
| 22463 | ; |
|
| 22464 | module.verbose('Saving element position'); |
|
| 22465 | // (quicker than $.extend) |
|
| 22466 | element.fits = (element.height < screen.height); |
|
| 22467 | element.offset = $module.offset(); |
|
| 22468 | element.width = $module.outerWidth(); |
|
| 22469 | element.height = $module.outerHeight(); |
|
| 22470 | // compensate for scroll in context |
|
| 22471 | if(module.is.verticallyScrollableContext()) { |
|
| 22472 | element.offset.top += $context.scrollTop() - $context.offset().top; |
|
| 22473 | } |
|
| 22474 | if(module.is.horizontallyScrollableContext()) { |
|
| 22475 | element.offset.left += $context.scrollLeft - $context.offset().left; |
|
| 22476 | } |
|
| 22477 | // store |
|
| 22478 | module.cache.element = element; |
|
| 22479 | return element; |
|
| 22480 | }, |
|
| 22481 | elementCalculations: function() { |
|
| 22482 | var |
|
| 22483 | screen = module.get.screenCalculations(), |
|
| 22484 | element = module.get.elementPosition() |
|
| 22485 | ; |
|
| 22486 | // offset |
|
| 22487 | if(settings.includeMargin) { |
|
| 22488 | element.margin = {}; |
|
| 22489 | element.margin.top = parseInt($module.css('margin-top'), 10); |
|
| 22490 | element.margin.bottom = parseInt($module.css('margin-bottom'), 10); |
|
| 22491 | element.top = element.offset.top - element.margin.top; |
|
| 22492 | element.bottom = element.offset.top + element.height + element.margin.bottom; |
|
| 22493 | } |
|
| 22494 | else { |
|
| 22495 | element.top = element.offset.top; |
|
| 22496 | element.bottom = element.offset.top + element.height; |
|
| 22497 | } |
|
| 22498 | ||
| 22499 | // visibility |
|
| 22500 | element.topPassed = (screen.top >= element.top); |
|
| 22501 | element.bottomPassed = (screen.top >= element.bottom); |
|
| 22502 | element.topVisible = (screen.bottom >= element.top) && !element.bottomPassed; |
|
| 22503 | element.bottomVisible = (screen.bottom >= element.bottom) && !element.topPassed; |
|
| 22504 | element.pixelsPassed = 0; |
|
| 22505 | element.percentagePassed = 0; |
|
| 22506 | ||
| 22507 | // meta calculations |
|
| 22508 | element.onScreen = (element.topVisible && !element.bottomPassed); |
|
| 22509 | element.passing = (element.topPassed && !element.bottomPassed); |
|
| 22510 | element.offScreen = (!element.onScreen); |
|
| 22511 | ||
| 22512 | // passing calculations |
|
| 22513 | if(element.passing) { |
|
| 22514 | element.pixelsPassed = (screen.top - element.top); |
|
| 22515 | element.percentagePassed = (screen.top - element.top) / element.height; |
|
| 22516 | } |
|
| 22517 | module.cache.element = element; |
|
| 22518 | module.verbose('Updated element calculations', element); |
|
| 22519 | return element; |
|
| 22520 | }, |
|
| 22521 | screenCalculations: function() { |
|
| 22522 | var |
|
| 22523 | scroll = module.get.scroll() |
|
| 22524 | ; |
|
| 22525 | module.save.direction(); |
|
| 22526 | module.cache.screen.top = scroll; |
|
| 22527 | module.cache.screen.bottom = scroll + module.cache.screen.height; |
|
| 22528 | return module.cache.screen; |
|
| 22529 | }, |
|
| 22530 | screenSize: function() { |
|
| 22531 | module.verbose('Saving window position'); |
|
| 22532 | module.cache.screen = { |
|
| 22533 | height: $context.height() |
|
| 22534 | }; |
|
| 22535 | }, |
|
| 22536 | position: function() { |
|
| 22537 | module.save.screenSize(); |
|
| 22538 | module.save.elementPosition(); |
|
| 22539 | } |
|
| 22540 | }, |
|
| 22541 | ||
| 22542 | get: { |
|
| 22543 | pixelsPassed: function(amount) { |
|
| 22544 | var |
|
| 22545 | element = module.get.elementCalculations() |
|
| 22546 | ; |
|
| 22547 | if(amount.search('%') > -1) { |
|
| 22548 | return ( element.height * (parseInt(amount, 10) / 100) ); |
|
| 22549 | } |
|
| 22550 | return parseInt(amount, 10); |
|
| 22551 | }, |
|
| 22552 | occurred: function(callback) { |
|
| 22553 | return (module.cache.occurred !== undefined) |
|
| 22554 | ? module.cache.occurred[callback] || false |
|
| 22555 | : false |
|
| 22556 | ; |
|
| 22557 | }, |
|
| 22558 | direction: function() { |
|
| 22559 | if(module.cache.direction === undefined) { |
|
| 22560 | module.save.direction(); |
|
| 22561 | } |
|
| 22562 | return module.cache.direction; |
|
| 22563 | }, |
|
| 22564 | elementPosition: function() { |
|
| 22565 | if(module.cache.element === undefined) { |
|
| 22566 | module.save.elementPosition(); |
|
| 22567 | } |
|
| 22568 | return module.cache.element; |
|
| 22569 | }, |
|
| 22570 | elementCalculations: function() { |
|
| 22571 | if(module.cache.element === undefined) { |
|
| 22572 | module.save.elementCalculations(); |
|
| 22573 | } |
|
| 22574 | return module.cache.element; |
|
| 22575 | }, |
|
| 22576 | screenCalculations: function() { |
|
| 22577 | if(module.cache.screen === undefined) { |
|
| 22578 | module.save.screenCalculations(); |
|
| 22579 | } |
|
| 22580 | return module.cache.screen; |
|
| 22581 | }, |
|
| 22582 | screenSize: function() { |
|
| 22583 | if(module.cache.screen === undefined) { |
|
| 22584 | module.save.screenSize(); |
|
| 22585 | } |
|
| 22586 | return module.cache.screen; |
|
| 22587 | }, |
|
| 22588 | scroll: function() { |
|
| 22589 | if(module.cache.scroll === undefined) { |
|
| 22590 | module.save.scroll(); |
|
| 22591 | } |
|
| 22592 | return module.cache.scroll; |
|
| 22593 | }, |
|
| 22594 | lastScroll: function() { |
|
| 22595 | if(module.cache.screen === undefined) { |
|
| 22596 | module.debug('First scroll event, no last scroll could be found'); |
|
| 22597 | return false; |
|
| 22598 | } |
|
| 22599 | return module.cache.screen.top; |
|
| 22600 | } |
|
| 22601 | }, |
|
| 22602 | ||
| 22603 | setting: function(name, value) { |
|
| 22604 | if( $.isPlainObject(name) ) { |
|
| 22605 | $.extend(true, settings, name); |
|
| 22606 | } |
|
| 22607 | else if(value !== undefined) { |
|
| 22608 | settings[name] = value; |
|
| 22609 | } |
|
| 22610 | else { |
|
| 22611 | return settings[name]; |
|
| 22612 | } |
|
| 22613 | }, |
|
| 22614 | internal: function(name, value) { |
|
| 22615 | if( $.isPlainObject(name) ) { |
|
| 22616 | $.extend(true, module, name); |
|
| 22617 | } |
|
| 22618 | else if(value !== undefined) { |
|
| 22619 | module[name] = value; |
|
| 22620 | } |
|
| 22621 | else { |
|
| 22622 | return module[name]; |
|
| 22623 | } |
|
| 22624 | }, |
|
| 22625 | debug: function() { |
|
| 22626 | if(!settings.silent && settings.debug) { |
|
| 22627 | if(settings.performance) { |
|
| 22628 | module.performance.log(arguments); |
|
| 22629 | } |
|
| 22630 | else { |
|
| 22631 | module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 22632 | module.debug.apply(console, arguments); |
|
| 22633 | } |
|
| 22634 | } |
|
| 22635 | }, |
|
| 22636 | verbose: function() { |
|
| 22637 | if(!settings.silent && settings.verbose && settings.debug) { |
|
| 22638 | if(settings.performance) { |
|
| 22639 | module.performance.log(arguments); |
|
| 22640 | } |
|
| 22641 | else { |
|
| 22642 | module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 22643 | module.verbose.apply(console, arguments); |
|
| 22644 | } |
|
| 22645 | } |
|
| 22646 | }, |
|
| 22647 | error: function() { |
|
| 22648 | if(!settings.silent) { |
|
| 22649 | module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); |
|
| 22650 | module.error.apply(console, arguments); |
|
| 22651 | } |
|
| 22652 | }, |
|
| 22653 | performance: { |
|
| 22654 | log: function(message) { |
|
| 22655 | var |
|
| 22656 | currentTime, |
|
| 22657 | executionTime, |
|
| 22658 | previousTime |
|
| 22659 | ; |
|
| 22660 | if(settings.performance) { |
|
| 22661 | currentTime = new Date().getTime(); |
|
| 22662 | previousTime = time || currentTime; |
|
| 22663 | executionTime = currentTime - previousTime; |
|
| 22664 | time = currentTime; |
|
| 22665 | performance.push({ |
|
| 22666 | 'Name' : message[0], |
|
| 22667 | 'Arguments' : [].slice.call(message, 1) || '', |
|
| 22668 | 'Element' : element, |
|
| 22669 | 'Execution Time' : executionTime |
|
| 22670 | }); |
|
| 22671 | } |
|
| 22672 | clearTimeout(module.performance.timer); |
|
| 22673 | module.performance.timer = setTimeout(module.performance.display, 500); |
|
| 22674 | }, |
|
| 22675 | display: function() { |
|
| 22676 | var |
|
| 22677 | title = settings.name + ':', |
|
| 22678 | totalTime = 0 |
|
| 22679 | ; |
|
| 22680 | time = false; |
|
| 22681 | clearTimeout(module.performance.timer); |
|
| 22682 | $.each(performance, function(index, data) { |
|
| 22683 | totalTime += data['Execution Time']; |
|
| 22684 | }); |
|
| 22685 | title += ' ' + totalTime + 'ms'; |
|
| 22686 | if(moduleSelector) { |
|
| 22687 | title += ' \'' + moduleSelector + '\''; |
|
| 22688 | } |
|
| 22689 | if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { |
|
| 22690 | console.groupCollapsed(title); |
|
| 22691 | if(console.table) { |
|
| 22692 | console.table(performance); |
|
| 22693 | } |
|
| 22694 | else { |
|
| 22695 | $.each(performance, function(index, data) { |
|
| 22696 | console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); |
|
| 22697 | }); |
|
| 22698 | } |
|
| 22699 | console.groupEnd(); |
|
| 22700 | } |
|
| 22701 | performance = []; |
|
| 22702 | } |
|
| 22703 | }, |
|
| 22704 | invoke: function(query, passedArguments, context) { |
|
| 22705 | var |
|
| 22706 | object = instance, |
|
| 22707 | maxDepth, |
|
| 22708 | found, |
|
| 22709 | response |
|
| 22710 | ; |
|
| 22711 | passedArguments = passedArguments || queryArguments; |
|
| 22712 | context = element || context; |
|
| 22713 | if(typeof query == 'string' && object !== undefined) { |
|
| 22714 | query = query.split(/[\. ]/); |
|
| 22715 | maxDepth = query.length - 1; |
|
| 22716 | $.each(query, function(depth, value) { |
|
| 22717 | var camelCaseValue = (depth != maxDepth) |
|
| 22718 | ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) |
|
| 22719 | : query |
|
| 22720 | ; |
|
| 22721 | if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { |
|
| 22722 | object = object[camelCaseValue]; |
|
| 22723 | } |
|
| 22724 | else if( object[camelCaseValue] !== undefined ) { |
|
| 22725 | found = object[camelCaseValue]; |
|
| 22726 | return false; |
|
| 22727 | } |
|
| 22728 | else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { |
|
| 22729 | object = object[value]; |
|
| 22730 | } |
|
| 22731 | else if( object[value] !== undefined ) { |
|
| 22732 | found = object[value]; |
|
| 22733 | return false; |
|
| 22734 | } |
|
| 22735 | else { |
|
| 22736 | module.error(error.method, query); |
|
| 22737 | return false; |
|
| 22738 | } |
|
| 22739 | }); |
|
| 22740 | } |
|
| 22741 | if ( $.isFunction( found ) ) { |
|
| 22742 | response = found.apply(context, passedArguments); |
|
| 22743 | } |
|
| 22744 | else if(found !== undefined) { |
|
| 22745 | response = found; |
|
| 22746 | } |
|
| 22747 | if($.isArray(returnedValue)) { |
|
| 22748 | returnedValue.push(response); |
|
| 22749 | } |
|
| 22750 | else if(returnedValue !== undefined) { |
|
| 22751 | returnedValue = [returnedValue, response]; |
|
| 22752 | } |
|
| 22753 | else if(response !== undefined) { |
|
| 22754 | returnedValue = response; |
|
| 22755 | } |
|
| 22756 | return found; |
|
| 22757 | } |
|
| 22758 | }; |
|
| 22759 | ||
| 22760 | if(methodInvoked) { |
|
| 22761 | if(instance === undefined) { |
|
| 22762 | module.initialize(); |
|
| 22763 | } |
|
| 22764 | instance.save.scroll(); |
|
| 22765 | instance.save.calculations(); |
|
| 22766 | module.invoke(query); |
|
| 22767 | } |
|
| 22768 | else { |
|
| 22769 | if(instance !== undefined) { |
|
| 22770 | instance.invoke('destroy'); |
|
| 22771 | } |
|
| 22772 | module.initialize(); |
|
| 22773 | } |
|
| 22774 | }) |
|
| 22775 | ; |
|
| 22776 | ||
| 22777 | return (returnedValue !== undefined) |
|
| 22778 | ? returnedValue |
|
| 22779 | : this |
|
| 22780 | ; |
|
| 22781 | }; |
|
| 22782 | ||
| 22783 | $.fn.visibility.settings = { |
|
| 22784 | ||
| 22785 | name : 'Visibility', |
|
| 22786 | namespace : 'visibility', |
|
| 22787 | ||
| 22788 | debug : false, |
|
| 22789 | verbose : false, |
|
| 22790 | performance : true, |
|
| 22791 | ||
| 22792 | // whether to use mutation observers to follow changes |
|
| 22793 | observeChanges : true, |
|
| 22794 | ||
| 22795 | // check position immediately on init |
|
| 22796 | initialCheck : true, |
|
| 22797 | ||
| 22798 | // whether to refresh calculations after all page images load |
|
| 22799 | refreshOnLoad : true, |
|
| 22800 | ||
| 22801 | // whether to refresh calculations after page resize event |
|
| 22802 | refreshOnResize : true, |
|
| 22803 | ||
| 22804 | // should call callbacks on refresh event (resize, etc) |
|
| 22805 | checkOnRefresh : true, |
|
| 22806 | ||
| 22807 | // callback should only occur one time |
|
| 22808 | once : true, |
|
| 22809 | ||
| 22810 | // callback should fire continuously whe evaluates to true |
|
| 22811 | continuous : false, |
|
| 22812 | ||
| 22813 | // offset to use with scroll top |
|
| 22814 | offset : 0, |
|
| 22815 | ||
| 22816 | // whether to include margin in elements position |
|
| 22817 | includeMargin : false, |
|
| 22818 | ||
| 22819 | // scroll context for visibility checks |
|
| 22820 | context : window, |
|
| 22821 | ||
| 22822 | // visibility check delay in ms (defaults to animationFrame) |
|
| 22823 | throttle : false, |
|
| 22824 | ||
| 22825 | // special visibility type (image, fixed) |
|
| 22826 | type : false, |
|
| 22827 | ||
| 22828 | // z-index to use with visibility 'fixed' |
|
| 22829 | zIndex : '10', |
|
| 22830 | ||
| 22831 | // image only animation settings |
|
| 22832 | transition : 'fade in', |
|
| 22833 | duration : 1000, |
|
| 22834 | ||
| 22835 | // array of callbacks for percentage |
|
| 22836 | onPassed : {}, |
|
| 22837 | ||
| 22838 | // standard callbacks |
|
| 22839 | onOnScreen : false, |
|
| 22840 | onOffScreen : false, |
|
| 22841 | onPassing : false, |
|
| 22842 | onTopVisible : false, |
|
| 22843 | onBottomVisible : false, |
|
| 22844 | onTopPassed : false, |
|
| 22845 | onBottomPassed : false, |
|
| 22846 | ||
| 22847 | // reverse callbacks |
|
| 22848 | onPassingReverse : false, |
|
| 22849 | onTopVisibleReverse : false, |
|
| 22850 | onBottomVisibleReverse : false, |
|
| 22851 | onTopPassedReverse : false, |
|
| 22852 | onBottomPassedReverse : false, |
|
| 22853 | ||
| 22854 | // special callbacks for image |
|
| 22855 | onLoad : function() {}, |
|
| 22856 | onAllLoaded : function() {}, |
|
| 22857 | ||
| 22858 | // special callbacks for fixed position |
|
| 22859 | onFixed : function() {}, |
|
| 22860 | onUnfixed : function() {}, |
|
| 22861 | ||
| 22862 | // utility callbacks |
|
| 22863 | onUpdate : false, // disabled by default for performance |
|
| 22864 | onRefresh : function(){}, |
|
| 22865 | ||
| 22866 | metadata : { |
|
| 22867 | src: 'src' |
|
| 22868 | }, |
|
| 22869 | ||
| 22870 | className: { |
|
| 22871 | fixed : 'fixed', |
|
| 22872 | placeholder : 'placeholder', |
|
| 22873 | visible : 'visible' |
|
| 22874 | }, |
|
| 22875 | ||
| 22876 | error : { |
|
| 22877 | method : 'The method you called is not defined.', |
|
| 22878 | visible : 'Element is hidden, you must call refresh after element becomes visible' |
|
| 22879 | } |
|
| 22880 | ||
| 22881 | }; |
|
| 22882 | ||
| 22883 | })( jQuery, window, document ); |
|
| 22884 | ||
| @@ 11-1311 (lines=1301) @@ | ||
| 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.visibility = 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 | moduleCount = $allModules.length, |
|
| 36 | loadedCount = 0 |
|
| 37 | ; |
|
| 38 | ||
| 39 | $allModules |
|
| 40 | .each(function() { |
|
| 41 | var |
|
| 42 | settings = ( $.isPlainObject(parameters) ) |
|
| 43 | ? $.extend(true, {}, $.fn.visibility.settings, parameters) |
|
| 44 | : $.extend({}, $.fn.visibility.settings), |
|
| 45 | ||
| 46 | className = settings.className, |
|
| 47 | namespace = settings.namespace, |
|
| 48 | error = settings.error, |
|
| 49 | metadata = settings.metadata, |
|
| 50 | ||
| 51 | eventNamespace = '.' + namespace, |
|
| 52 | moduleNamespace = 'module-' + namespace, |
|
| 53 | ||
| 54 | $window = $(window), |
|
| 55 | ||
| 56 | $module = $(this), |
|
| 57 | $context = $(settings.context), |
|
| 58 | ||
| 59 | $placeholder, |
|
| 60 | ||
| 61 | selector = $module.selector || '', |
|
| 62 | instance = $module.data(moduleNamespace), |
|
| 63 | ||
| 64 | requestAnimationFrame = window.requestAnimationFrame |
|
| 65 | || window.mozRequestAnimationFrame |
|
| 66 | || window.webkitRequestAnimationFrame |
|
| 67 | || window.msRequestAnimationFrame |
|
| 68 | || function(callback) { setTimeout(callback, 0); }, |
|
| 69 | ||
| 70 | element = this, |
|
| 71 | disabled = false, |
|
| 72 | ||
| 73 | contextObserver, |
|
| 74 | observer, |
|
| 75 | module |
|
| 76 | ; |
|
| 77 | ||
| 78 | module = { |
|
| 79 | ||
| 80 | initialize: function() { |
|
| 81 | module.debug('Initializing', settings); |
|
| 82 | ||
| 83 | module.setup.cache(); |
|
| 84 | ||
| 85 | if( module.should.trackChanges() ) { |
|
| 86 | ||
| 87 | if(settings.type == 'image') { |
|
| 88 | module.setup.image(); |
|
| 89 | } |
|
| 90 | if(settings.type == 'fixed') { |
|
| 91 | module.setup.fixed(); |
|
| 92 | } |
|
| 93 | ||
| 94 | if(settings.observeChanges) { |
|
| 95 | module.observeChanges(); |
|
| 96 | } |
|
| 97 | module.bind.events(); |
|
| 98 | } |
|
| 99 | ||
| 100 | module.save.position(); |
|
| 101 | if( !module.is.visible() ) { |
|
| 102 | module.error(error.visible, $module); |
|
| 103 | } |
|
| 104 | ||
| 105 | if(settings.initialCheck) { |
|
| 106 | module.checkVisibility(); |
|
| 107 | } |
|
| 108 | module.instantiate(); |
|
| 109 | }, |
|
| 110 | ||
| 111 | instantiate: function() { |
|
| 112 | module.debug('Storing instance', module); |
|
| 113 | $module |
|
| 114 | .data(moduleNamespace, module) |
|
| 115 | ; |
|
| 116 | instance = module; |
|
| 117 | }, |
|
| 118 | ||
| 119 | destroy: function() { |
|
| 120 | module.verbose('Destroying previous module'); |
|
| 121 | if(observer) { |
|
| 122 | observer.disconnect(); |
|
| 123 | } |
|
| 124 | if(contextObserver) { |
|
| 125 | contextObserver.disconnect(); |
|
| 126 | } |
|
| 127 | $window |
|
| 128 | .off('load' + eventNamespace, module.event.load) |
|
| 129 | .off('resize' + eventNamespace, module.event.resize) |
|
| 130 | ; |
|
| 131 | $context |
|
| 132 | .off('scroll' + eventNamespace, module.event.scroll) |
|
| 133 | .off('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 134 | ; |
|
| 135 | if(settings.type == 'fixed') { |
|
| 136 | module.resetFixed(); |
|
| 137 | module.remove.placeholder(); |
|
| 138 | } |
|
| 139 | $module |
|
| 140 | .off(eventNamespace) |
|
| 141 | .removeData(moduleNamespace) |
|
| 142 | ; |
|
| 143 | }, |
|
| 144 | ||
| 145 | observeChanges: function() { |
|
| 146 | if('MutationObserver' in window) { |
|
| 147 | contextObserver = new MutationObserver(module.event.contextChanged); |
|
| 148 | observer = new MutationObserver(module.event.changed); |
|
| 149 | contextObserver.observe(document, { |
|
| 150 | childList : true, |
|
| 151 | subtree : true |
|
| 152 | }); |
|
| 153 | observer.observe(element, { |
|
| 154 | childList : true, |
|
| 155 | subtree : true |
|
| 156 | }); |
|
| 157 | module.debug('Setting up mutation observer', observer); |
|
| 158 | } |
|
| 159 | }, |
|
| 160 | ||
| 161 | bind: { |
|
| 162 | events: function() { |
|
| 163 | module.verbose('Binding visibility events to scroll and resize'); |
|
| 164 | if(settings.refreshOnLoad) { |
|
| 165 | $window |
|
| 166 | .on('load' + eventNamespace, module.event.load) |
|
| 167 | ; |
|
| 168 | } |
|
| 169 | $window |
|
| 170 | .on('resize' + eventNamespace, module.event.resize) |
|
| 171 | ; |
|
| 172 | // pub/sub pattern |
|
| 173 | $context |
|
| 174 | .off('scroll' + eventNamespace) |
|
| 175 | .on('scroll' + eventNamespace, module.event.scroll) |
|
| 176 | .on('scrollchange' + eventNamespace, module.event.scrollchange) |
|
| 177 | ; |
|
| 178 | } |
|
| 179 | }, |
|
| 180 | ||
| 181 | event: { |
|
| 182 | changed: function(mutations) { |
|
| 183 | module.verbose('DOM tree modified, updating visibility calculations'); |
|
| 184 | module.timer = setTimeout(function() { |
|
| 185 | module.verbose('DOM tree modified, updating sticky menu'); |
|
| 186 | module.refresh(); |
|
| 187 | }, 100); |
|
| 188 | }, |
|
| 189 | contextChanged: function(mutations) { |
|
| 190 | [].forEach.call(mutations, function(mutation) { |
|
| 191 | if(mutation.removedNodes) { |
|
| 192 | [].forEach.call(mutation.removedNodes, function(node) { |
|
| 193 | if(node == element || $(node).find(element).length > 0) { |
|
| 194 | module.debug('Element removed from DOM, tearing down events'); |
|
| 195 | module.destroy(); |
|
| 196 | } |
|
| 197 | }); |
|
| 198 | } |
|
| 199 | }); |
|
| 200 | }, |
|
| 201 | resize: function() { |
|
| 202 | module.debug('Window resized'); |
|
| 203 | if(settings.refreshOnResize) { |
|
| 204 | requestAnimationFrame(module.refresh); |
|
| 205 | } |
|
| 206 | }, |
|
| 207 | load: function() { |
|
| 208 | module.debug('Page finished loading'); |
|
| 209 | requestAnimationFrame(module.refresh); |
|
| 210 | }, |
|
| 211 | // publishes scrollchange event on one scroll |
|
| 212 | scroll: function() { |
|
| 213 | if(settings.throttle) { |
|
| 214 | clearTimeout(module.timer); |
|
| 215 | module.timer = setTimeout(function() { |
|
| 216 | $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]); |
|
| 217 | }, settings.throttle); |
|
| 218 | } |
|
| 219 | else { |
|
| 220 | requestAnimationFrame(function() { |
|
| 221 | $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]); |
|
| 222 | }); |
|
| 223 | } |
|
| 224 | }, |
|
| 225 | // subscribes to scrollchange |
|
| 226 | scrollchange: function(event, scrollPosition) { |
|
| 227 | module.checkVisibility(scrollPosition); |
|
| 228 | }, |
|
| 229 | }, |
|
| 230 | ||
| 231 | precache: function(images, callback) { |
|
| 232 | if (!(images instanceof Array)) { |
|
| 233 | images = [images]; |
|
| 234 | } |
|
| 235 | var |
|
| 236 | imagesLength = images.length, |
|
| 237 | loadedCounter = 0, |
|
| 238 | cache = [], |
|
| 239 | cacheImage = document.createElement('img'), |
|
| 240 | handleLoad = function() { |
|
| 241 | loadedCounter++; |
|
| 242 | if (loadedCounter >= images.length) { |
|
| 243 | if ($.isFunction(callback)) { |
|
| 244 | callback(); |
|
| 245 | } |
|
| 246 | } |
|
| 247 | } |
|
| 248 | ; |
|
| 249 | while (imagesLength--) { |
|
| 250 | cacheImage = document.createElement('img'); |
|
| 251 | cacheImage.onload = handleLoad; |
|
| 252 | cacheImage.onerror = handleLoad; |
|
| 253 | cacheImage.src = images[imagesLength]; |
|
| 254 | cache.push(cacheImage); |
|
| 255 | } |
|
| 256 | }, |
|
| 257 | ||
| 258 | enableCallbacks: function() { |
|
| 259 | module.debug('Allowing callbacks to occur'); |
|
| 260 | disabled = false; |
|
| 261 | }, |
|
| 262 | ||
| 263 | disableCallbacks: function() { |
|
| 264 | module.debug('Disabling all callbacks temporarily'); |
|
| 265 | disabled = true; |
|
| 266 | }, |
|
| 267 | ||
| 268 | should: { |
|
| 269 | trackChanges: function() { |
|
| 270 | if(methodInvoked) { |
|
| 271 | module.debug('One time query, no need to bind events'); |
|
| 272 | return false; |
|
| 273 | } |
|
| 274 | module.debug('Callbacks being attached'); |
|
| 275 | return true; |
|
| 276 | } |
|
| 277 | }, |
|
| 278 | ||
| 279 | setup: { |
|
| 280 | cache: function() { |
|
| 281 | module.cache = { |
|
| 282 | occurred : {}, |
|
| 283 | screen : {}, |
|
| 284 | element : {}, |
|
| 285 | }; |
|
| 286 | }, |
|
| 287 | image: function() { |
|
| 288 | var |
|
| 289 | src = $module.data(metadata.src) |
|
| 290 | ; |
|
| 291 | if(src) { |
|
| 292 | module.verbose('Lazy loading image', src); |
|
| 293 | settings.once = true; |
|
| 294 | settings.observeChanges = false; |
|
| 295 | ||
| 296 | // show when top visible |
|
| 297 | settings.onOnScreen = function() { |
|
| 298 | module.debug('Image on screen', element); |
|
| 299 | module.precache(src, function() { |
|
| 300 | module.set.image(src, function() { |
|
| 301 | loadedCount++; |
|
| 302 | if(loadedCount == moduleCount) { |
|
| 303 | settings.onAllLoaded.call(this); |
|
| 304 | } |
|
| 305 | settings.onLoad.call(this); |
|
| 306 | }); |
|
| 307 | }); |
|
| 308 | }; |
|
| 309 | } |
|
| 310 | }, |
|
| 311 | fixed: function() { |
|
| 312 | module.debug('Setting up fixed'); |
|
| 313 | settings.once = false; |
|
| 314 | settings.observeChanges = false; |
|
| 315 | settings.initialCheck = true; |
|
| 316 | settings.refreshOnLoad = true; |
|
| 317 | if(!parameters.transition) { |
|
| 318 | settings.transition = false; |
|
| 319 | } |
|
| 320 | module.create.placeholder(); |
|
| 321 | module.debug('Added placeholder', $placeholder); |
|
| 322 | settings.onTopPassed = function() { |
|
| 323 | module.debug('Element passed, adding fixed position', $module); |
|
| 324 | module.show.placeholder(); |
|
| 325 | module.set.fixed(); |
|
| 326 | if(settings.transition) { |
|
| 327 | if($.fn.transition !== undefined) { |
|
| 328 | $module.transition(settings.transition, settings.duration); |
|
| 329 | } |
|
| 330 | } |
|
| 331 | }; |
|
| 332 | settings.onTopPassedReverse = function() { |
|
| 333 | module.debug('Element returned to position, removing fixed', $module); |
|
| 334 | module.hide.placeholder(); |
|
| 335 | module.remove.fixed(); |
|
| 336 | }; |
|
| 337 | } |
|
| 338 | }, |
|
| 339 | ||
| 340 | create: { |
|
| 341 | placeholder: function() { |
|
| 342 | module.verbose('Creating fixed position placeholder'); |
|
| 343 | $placeholder = $module |
|
| 344 | .clone(false) |
|
| 345 | .css('display', 'none') |
|
| 346 | .addClass(className.placeholder) |
|
| 347 | .insertAfter($module) |
|
| 348 | ; |
|
| 349 | } |
|
| 350 | }, |
|
| 351 | ||
| 352 | show: { |
|
| 353 | placeholder: function() { |
|
| 354 | module.verbose('Showing placeholder'); |
|
| 355 | $placeholder |
|
| 356 | .css('display', 'block') |
|
| 357 | .css('visibility', 'hidden') |
|
| 358 | ; |
|
| 359 | } |
|
| 360 | }, |
|
| 361 | hide: { |
|
| 362 | placeholder: function() { |
|
| 363 | module.verbose('Hiding placeholder'); |
|
| 364 | $placeholder |
|
| 365 | .css('display', 'none') |
|
| 366 | .css('visibility', '') |
|
| 367 | ; |
|
| 368 | } |
|
| 369 | }, |
|
| 370 | ||
| 371 | set: { |
|
| 372 | fixed: function() { |
|
| 373 | module.verbose('Setting element to fixed position'); |
|
| 374 | $module |
|
| 375 | .addClass(className.fixed) |
|
| 376 | .css({ |
|
| 377 | position : 'fixed', |
|
| 378 | top : settings.offset + 'px', |
|
| 379 | left : 'auto', |
|
| 380 | zIndex : settings.zIndex |
|
| 381 | }) |
|
| 382 | ; |
|
| 383 | settings.onFixed.call(element); |
|
| 384 | }, |
|
| 385 | image: function(src, callback) { |
|
| 386 | $module |
|
| 387 | .attr('src', src) |
|
| 388 | ; |
|
| 389 | if(settings.transition) { |
|
| 390 | if( $.fn.transition !== undefined) { |
|
| 391 | if($module.hasClass(className.visible)) { |
|
| 392 | module.debug('Transition already occurred on this image, skipping animation'); |
|
| 393 | return; |
|
| 394 | } |
|
| 395 | $module.transition(settings.transition, settings.duration, callback); |
|
| 396 | } |
|
| 397 | else { |
|
| 398 | $module.fadeIn(settings.duration, callback); |
|
| 399 | } |
|
| 400 | } |
|
| 401 | else { |
|
| 402 | $module.show(); |
|
| 403 | } |
|
| 404 | } |
|
| 405 | }, |
|
| 406 | ||
| 407 | is: { |
|
| 408 | onScreen: function() { |
|
| 409 | var |
|
| 410 | calculations = module.get.elementCalculations() |
|
| 411 | ; |
|
| 412 | return calculations.onScreen; |
|
| 413 | }, |
|
| 414 | offScreen: function() { |
|
| 415 | var |
|
| 416 | calculations = module.get.elementCalculations() |
|
| 417 | ; |
|
| 418 | return calculations.offScreen; |
|
| 419 | }, |
|
| 420 | visible: function() { |
|
| 421 | if(module.cache && module.cache.element) { |
|
| 422 | return !(module.cache.element.width === 0 && module.cache.element.offset.top === 0); |
|
| 423 | } |
|
| 424 | return false; |
|
| 425 | }, |
|
| 426 | verticallyScrollableContext: function() { |
|
| 427 | var |
|
| 428 | overflowY = ($context.get(0) !== window) |
|
| 429 | ? $context.css('overflow-y') |
|
| 430 | : false |
|
| 431 | ; |
|
| 432 | return (overflowY == 'auto' || overflowY == 'scroll'); |
|
| 433 | }, |
|
| 434 | horizontallyScrollableContext: function() { |
|
| 435 | var |
|
| 436 | overflowX = ($context.get(0) !== window) |
|
| 437 | ? $context.css('overflow-x') |
|
| 438 | : false |
|
| 439 | ; |
|
| 440 | return (overflowX == 'auto' || overflowX == 'scroll'); |
|
| 441 | } |
|
| 442 | }, |
|
| 443 | ||
| 444 | refresh: function() { |
|
| 445 | module.debug('Refreshing constants (width/height)'); |
|
| 446 | if(settings.type == 'fixed') { |
|
| 447 | module.resetFixed(); |
|
| 448 | } |
|
| 449 | module.reset(); |
|
| 450 | module.save.position(); |
|
| 451 | if(settings.checkOnRefresh) { |
|
| 452 | module.checkVisibility(); |
|
| 453 | } |
|
| 454 | settings.onRefresh.call(element); |
|
| 455 | }, |
|
| 456 | ||
| 457 | resetFixed: function () { |
|
| 458 | module.remove.fixed(); |
|
| 459 | module.remove.occurred(); |
|
| 460 | }, |
|
| 461 | ||
| 462 | reset: function() { |
|
| 463 | module.verbose('Resetting all cached values'); |
|
| 464 | if( $.isPlainObject(module.cache) ) { |
|
| 465 | module.cache.screen = {}; |
|
| 466 | module.cache.element = {}; |
|
| 467 | } |
|
| 468 | }, |
|
| 469 | ||
| 470 | checkVisibility: function(scroll) { |
|
| 471 | module.verbose('Checking visibility of element', module.cache.element); |
|
| 472 | ||
| 473 | if( !disabled && module.is.visible() ) { |
|
| 474 | ||
| 475 | // save scroll position |
|
| 476 | module.save.scroll(scroll); |
|
| 477 | ||
| 478 | // update calculations derived from scroll |
|
| 479 | module.save.calculations(); |
|
| 480 | ||
| 481 | // percentage |
|
| 482 | module.passed(); |
|
| 483 | ||
| 484 | // reverse (must be first) |
|
| 485 | module.passingReverse(); |
|
| 486 | module.topVisibleReverse(); |
|
| 487 | module.bottomVisibleReverse(); |
|
| 488 | module.topPassedReverse(); |
|
| 489 | module.bottomPassedReverse(); |
|
| 490 | ||
| 491 | // one time |
|
| 492 | module.onScreen(); |
|
| 493 | module.offScreen(); |
|
| 494 | module.passing(); |
|
| 495 | module.topVisible(); |
|
| 496 | module.bottomVisible(); |
|
| 497 | module.topPassed(); |
|
| 498 | module.bottomPassed(); |
|
| 499 | ||
| 500 | // on update callback |
|
| 501 | if(settings.onUpdate) { |
|
| 502 | settings.onUpdate.call(element, module.get.elementCalculations()); |
|
| 503 | } |
|
| 504 | } |
|
| 505 | }, |
|
| 506 | ||
| 507 | passed: function(amount, newCallback) { |
|
| 508 | var |
|
| 509 | calculations = module.get.elementCalculations(), |
|
| 510 | amountInPixels |
|
| 511 | ; |
|
| 512 | // assign callback |
|
| 513 | if(amount && newCallback) { |
|
| 514 | settings.onPassed[amount] = newCallback; |
|
| 515 | } |
|
| 516 | else if(amount !== undefined) { |
|
| 517 | return (module.get.pixelsPassed(amount) > calculations.pixelsPassed); |
|
| 518 | } |
|
| 519 | else if(calculations.passing) { |
|
| 520 | $.each(settings.onPassed, function(amount, callback) { |
|
| 521 | if(calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) { |
|
| 522 | module.execute(callback, amount); |
|
| 523 | } |
|
| 524 | else if(!settings.once) { |
|
| 525 | module.remove.occurred(callback); |
|
| 526 | } |
|
| 527 | }); |
|
| 528 | } |
|
| 529 | }, |
|
| 530 | ||
| 531 | onScreen: function(newCallback) { |
|
| 532 | var |
|
| 533 | calculations = module.get.elementCalculations(), |
|
| 534 | callback = newCallback || settings.onOnScreen, |
|
| 535 | callbackName = 'onScreen' |
|
| 536 | ; |
|
| 537 | if(newCallback) { |
|
| 538 | module.debug('Adding callback for onScreen', newCallback); |
|
| 539 | settings.onOnScreen = newCallback; |
|
| 540 | } |
|
| 541 | if(calculations.onScreen) { |
|
| 542 | module.execute(callback, callbackName); |
|
| 543 | } |
|
| 544 | else if(!settings.once) { |
|
| 545 | module.remove.occurred(callbackName); |
|
| 546 | } |
|
| 547 | if(newCallback !== undefined) { |
|
| 548 | return calculations.onOnScreen; |
|
| 549 | } |
|
| 550 | }, |
|
| 551 | ||
| 552 | offScreen: function(newCallback) { |
|
| 553 | var |
|
| 554 | calculations = module.get.elementCalculations(), |
|
| 555 | callback = newCallback || settings.onOffScreen, |
|
| 556 | callbackName = 'offScreen' |
|
| 557 | ; |
|
| 558 | if(newCallback) { |
|
| 559 | module.debug('Adding callback for offScreen', newCallback); |
|
| 560 | settings.onOffScreen = newCallback; |
|
| 561 | } |
|
| 562 | if(calculations.offScreen) { |
|
| 563 | module.execute(callback, callbackName); |
|
| 564 | } |
|
| 565 | else if(!settings.once) { |
|
| 566 | module.remove.occurred(callbackName); |
|
| 567 | } |
|
| 568 | if(newCallback !== undefined) { |
|
| 569 | return calculations.onOffScreen; |
|
| 570 | } |
|
| 571 | }, |
|
| 572 | ||
| 573 | passing: function(newCallback) { |
|
| 574 | var |
|
| 575 | calculations = module.get.elementCalculations(), |
|
| 576 | callback = newCallback || settings.onPassing, |
|
| 577 | callbackName = 'passing' |
|
| 578 | ; |
|
| 579 | if(newCallback) { |
|
| 580 | module.debug('Adding callback for passing', newCallback); |
|
| 581 | settings.onPassing = newCallback; |
|
| 582 | } |
|
| 583 | if(calculations.passing) { |
|
| 584 | module.execute(callback, callbackName); |
|
| 585 | } |
|
| 586 | else if(!settings.once) { |
|
| 587 | module.remove.occurred(callbackName); |
|
| 588 | } |
|
| 589 | if(newCallback !== undefined) { |
|
| 590 | return calculations.passing; |
|
| 591 | } |
|
| 592 | }, |
|
| 593 | ||
| 594 | ||
| 595 | topVisible: function(newCallback) { |
|
| 596 | var |
|
| 597 | calculations = module.get.elementCalculations(), |
|
| 598 | callback = newCallback || settings.onTopVisible, |
|
| 599 | callbackName = 'topVisible' |
|
| 600 | ; |
|
| 601 | if(newCallback) { |
|
| 602 | module.debug('Adding callback for top visible', newCallback); |
|
| 603 | settings.onTopVisible = newCallback; |
|
| 604 | } |
|
| 605 | if(calculations.topVisible) { |
|
| 606 | module.execute(callback, callbackName); |
|
| 607 | } |
|
| 608 | else if(!settings.once) { |
|
| 609 | module.remove.occurred(callbackName); |
|
| 610 | } |
|
| 611 | if(newCallback === undefined) { |
|
| 612 | return calculations.topVisible; |
|
| 613 | } |
|
| 614 | }, |
|
| 615 | ||
| 616 | bottomVisible: function(newCallback) { |
|
| 617 | var |
|
| 618 | calculations = module.get.elementCalculations(), |
|
| 619 | callback = newCallback || settings.onBottomVisible, |
|
| 620 | callbackName = 'bottomVisible' |
|
| 621 | ; |
|
| 622 | if(newCallback) { |
|
| 623 | module.debug('Adding callback for bottom visible', newCallback); |
|
| 624 | settings.onBottomVisible = newCallback; |
|
| 625 | } |
|
| 626 | if(calculations.bottomVisible) { |
|
| 627 | module.execute(callback, callbackName); |
|
| 628 | } |
|
| 629 | else if(!settings.once) { |
|
| 630 | module.remove.occurred(callbackName); |
|
| 631 | } |
|
| 632 | if(newCallback === undefined) { |
|
| 633 | return calculations.bottomVisible; |
|
| 634 | } |
|
| 635 | }, |
|
| 636 | ||
| 637 | topPassed: function(newCallback) { |
|
| 638 | var |
|
| 639 | calculations = module.get.elementCalculations(), |
|
| 640 | callback = newCallback || settings.onTopPassed, |
|
| 641 | callbackName = 'topPassed' |
|
| 642 | ; |
|
| 643 | if(newCallback) { |
|
| 644 | module.debug('Adding callback for top passed', newCallback); |
|
| 645 | settings.onTopPassed = newCallback; |
|
| 646 | } |
|
| 647 | if(calculations.topPassed) { |
|
| 648 | module.execute(callback, callbackName); |
|
| 649 | } |
|
| 650 | else if(!settings.once) { |
|
| 651 | module.remove.occurred(callbackName); |
|
| 652 | } |
|
| 653 | if(newCallback === undefined) { |
|
| 654 | return calculations.topPassed; |
|
| 655 | } |
|
| 656 | }, |
|
| 657 | ||
| 658 | bottomPassed: function(newCallback) { |
|
| 659 | var |
|
| 660 | calculations = module.get.elementCalculations(), |
|
| 661 | callback = newCallback || settings.onBottomPassed, |
|
| 662 | callbackName = 'bottomPassed' |
|
| 663 | ; |
|
| 664 | if(newCallback) { |
|
| 665 | module.debug('Adding callback for bottom passed', newCallback); |
|
| 666 | settings.onBottomPassed = newCallback; |
|
| 667 | } |
|
| 668 | if(calculations.bottomPassed) { |
|
| 669 | module.execute(callback, callbackName); |
|
| 670 | } |
|
| 671 | else if(!settings.once) { |
|
| 672 | module.remove.occurred(callbackName); |
|
| 673 | } |
|
| 674 | if(newCallback === undefined) { |
|
| 675 | return calculations.bottomPassed; |
|
| 676 | } |
|
| 677 | }, |
|
| 678 | ||
| 679 | passingReverse: function(newCallback) { |
|
| 680 | var |
|
| 681 | calculations = module.get.elementCalculations(), |
|
| 682 | callback = newCallback || settings.onPassingReverse, |
|
| 683 | callbackName = 'passingReverse' |
|
| 684 | ; |
|
| 685 | if(newCallback) { |
|
| 686 | module.debug('Adding callback for passing reverse', newCallback); |
|
| 687 | settings.onPassingReverse = newCallback; |
|
| 688 | } |
|
| 689 | if(!calculations.passing) { |
|
| 690 | if(module.get.occurred('passing')) { |
|
| 691 | module.execute(callback, callbackName); |
|
| 692 | } |
|
| 693 | } |
|
| 694 | else if(!settings.once) { |
|
| 695 | module.remove.occurred(callbackName); |
|
| 696 | } |
|
| 697 | if(newCallback !== undefined) { |
|
| 698 | return !calculations.passing; |
|
| 699 | } |
|
| 700 | }, |
|
| 701 | ||
| 702 | ||
| 703 | topVisibleReverse: function(newCallback) { |
|
| 704 | var |
|
| 705 | calculations = module.get.elementCalculations(), |
|
| 706 | callback = newCallback || settings.onTopVisibleReverse, |
|
| 707 | callbackName = 'topVisibleReverse' |
|
| 708 | ; |
|
| 709 | if(newCallback) { |
|
| 710 | module.debug('Adding callback for top visible reverse', newCallback); |
|
| 711 | settings.onTopVisibleReverse = newCallback; |
|
| 712 | } |
|
| 713 | if(!calculations.topVisible) { |
|
| 714 | if(module.get.occurred('topVisible')) { |
|
| 715 | module.execute(callback, callbackName); |
|
| 716 | } |
|
| 717 | } |
|
| 718 | else if(!settings.once) { |
|
| 719 | module.remove.occurred(callbackName); |
|
| 720 | } |
|
| 721 | if(newCallback === undefined) { |
|
| 722 | return !calculations.topVisible; |
|
| 723 | } |
|
| 724 | }, |
|
| 725 | ||
| 726 | bottomVisibleReverse: function(newCallback) { |
|
| 727 | var |
|
| 728 | calculations = module.get.elementCalculations(), |
|
| 729 | callback = newCallback || settings.onBottomVisibleReverse, |
|
| 730 | callbackName = 'bottomVisibleReverse' |
|
| 731 | ; |
|
| 732 | if(newCallback) { |
|
| 733 | module.debug('Adding callback for bottom visible reverse', newCallback); |
|
| 734 | settings.onBottomVisibleReverse = newCallback; |
|
| 735 | } |
|
| 736 | if(!calculations.bottomVisible) { |
|
| 737 | if(module.get.occurred('bottomVisible')) { |
|
| 738 | module.execute(callback, callbackName); |
|
| 739 | } |
|
| 740 | } |
|
| 741 | else if(!settings.once) { |
|
| 742 | module.remove.occurred(callbackName); |
|
| 743 | } |
|
| 744 | if(newCallback === undefined) { |
|
| 745 | return !calculations.bottomVisible; |
|
| 746 | } |
|
| 747 | }, |
|
| 748 | ||
| 749 | topPassedReverse: function(newCallback) { |
|
| 750 | var |
|
| 751 | calculations = module.get.elementCalculations(), |
|
| 752 | callback = newCallback || settings.onTopPassedReverse, |
|
| 753 | callbackName = 'topPassedReverse' |
|
| 754 | ; |
|
| 755 | if(newCallback) { |
|
| 756 | module.debug('Adding callback for top passed reverse', newCallback); |
|
| 757 | settings.onTopPassedReverse = newCallback; |
|
| 758 | } |
|
| 759 | if(!calculations.topPassed) { |
|
| 760 | if(module.get.occurred('topPassed')) { |
|
| 761 | module.execute(callback, callbackName); |
|
| 762 | } |
|
| 763 | } |
|
| 764 | else if(!settings.once) { |
|
| 765 | module.remove.occurred(callbackName); |
|
| 766 | } |
|
| 767 | if(newCallback === undefined) { |
|
| 768 | return !calculations.onTopPassed; |
|
| 769 | } |
|
| 770 | }, |
|
| 771 | ||
| 772 | bottomPassedReverse: function(newCallback) { |
|
| 773 | var |
|
| 774 | calculations = module.get.elementCalculations(), |
|
| 775 | callback = newCallback || settings.onBottomPassedReverse, |
|
| 776 | callbackName = 'bottomPassedReverse' |
|
| 777 | ; |
|
| 778 | if(newCallback) { |
|
| 779 | module.debug('Adding callback for bottom passed reverse', newCallback); |
|
| 780 | settings.onBottomPassedReverse = newCallback; |
|
| 781 | } |
|
| 782 | if(!calculations.bottomPassed) { |
|
| 783 | if(module.get.occurred('bottomPassed')) { |
|
| 784 | module.execute(callback, callbackName); |
|
| 785 | } |
|
| 786 | } |
|
| 787 | else if(!settings.once) { |
|
| 788 | module.remove.occurred(callbackName); |
|
| 789 | } |
|
| 790 | if(newCallback === undefined) { |
|
| 791 | return !calculations.bottomPassed; |
|
| 792 | } |
|
| 793 | }, |
|
| 794 | ||
| 795 | execute: function(callback, callbackName) { |
|
| 796 | var |
|
| 797 | calculations = module.get.elementCalculations(), |
|
| 798 | screen = module.get.screenCalculations() |
|
| 799 | ; |
|
| 800 | callback = callback || false; |
|
| 801 | if(callback) { |
|
| 802 | if(settings.continuous) { |
|
| 803 | module.debug('Callback being called continuously', callbackName, calculations); |
|
| 804 | callback.call(element, calculations, screen); |
|
| 805 | } |
|
| 806 | else if(!module.get.occurred(callbackName)) { |
|
| 807 | module.debug('Conditions met', callbackName, calculations); |
|
| 808 | callback.call(element, calculations, screen); |
|
| 809 | } |
|
| 810 | } |
|
| 811 | module.save.occurred(callbackName); |
|
| 812 | }, |
|
| 813 | ||
| 814 | remove: { |
|
| 815 | fixed: function() { |
|
| 816 | module.debug('Removing fixed position'); |
|
| 817 | $module |
|
| 818 | .removeClass(className.fixed) |
|
| 819 | .css({ |
|
| 820 | position : '', |
|
| 821 | top : '', |
|
| 822 | left : '', |
|
| 823 | zIndex : '' |
|
| 824 | }) |
|
| 825 | ; |
|
| 826 | settings.onUnfixed.call(element); |
|
| 827 | }, |
|
| 828 | placeholder: function() { |
|
| 829 | module.debug('Removing placeholder content'); |
|
| 830 | if($placeholder) { |
|
| 831 | $placeholder.remove(); |
|
| 832 | } |
|
| 833 | }, |
|
| 834 | occurred: function(callback) { |
|
| 835 | if(callback) { |
|
| 836 | var |
|
| 837 | occurred = module.cache.occurred |
|
| 838 | ; |
|
| 839 | if(occurred[callback] !== undefined && occurred[callback] === true) { |
|
| 840 | module.debug('Callback can now be called again', callback); |
|
| 841 | module.cache.occurred[callback] = false; |
|
| 842 | } |
|
| 843 | } |
|
| 844 | else { |
|
| 845 | module.cache.occurred = {}; |
|
| 846 | } |
|
| 847 | } |
|
| 848 | }, |
|
| 849 | ||
| 850 | save: { |
|
| 851 | calculations: function() { |
|
| 852 | module.verbose('Saving all calculations necessary to determine positioning'); |
|
| 853 | module.save.direction(); |
|
| 854 | module.save.screenCalculations(); |
|
| 855 | module.save.elementCalculations(); |
|
| 856 | }, |
|
| 857 | occurred: function(callback) { |
|
| 858 | if(callback) { |
|
| 859 | if(module.cache.occurred[callback] === undefined || (module.cache.occurred[callback] !== true)) { |
|
| 860 | module.verbose('Saving callback occurred', callback); |
|
| 861 | module.cache.occurred[callback] = true; |
|
| 862 | } |
|
| 863 | } |
|
| 864 | }, |
|
| 865 | scroll: function(scrollPosition) { |
|
| 866 | scrollPosition = scrollPosition + settings.offset || $context.scrollTop() + settings.offset; |
|
| 867 | module.cache.scroll = scrollPosition; |
|
| 868 | }, |
|
| 869 | direction: function() { |
|
| 870 | var |
|
| 871 | scroll = module.get.scroll(), |
|
| 872 | lastScroll = module.get.lastScroll(), |
|
| 873 | direction |
|
| 874 | ; |
|
| 875 | if(scroll > lastScroll && lastScroll) { |
|
| 876 | direction = 'down'; |
|
| 877 | } |
|
| 878 | else if(scroll < lastScroll && lastScroll) { |
|
| 879 | direction = 'up'; |
|
| 880 | } |
|
| 881 | else { |
|
| 882 | direction = 'static'; |
|
| 883 | } |
|
| 884 | module.cache.direction = direction; |
|
| 885 | return module.cache.direction; |
|
| 886 | }, |
|
| 887 | elementPosition: function() { |
|
| 888 | var |
|
| 889 | element = module.cache.element, |
|
| 890 | screen = module.get.screenSize() |
|
| 891 | ; |
|
| 892 | module.verbose('Saving element position'); |
|
| 893 | // (quicker than $.extend) |
|
| 894 | element.fits = (element.height < screen.height); |
|
| 895 | element.offset = $module.offset(); |
|
| 896 | element.width = $module.outerWidth(); |
|
| 897 | element.height = $module.outerHeight(); |
|
| 898 | // compensate for scroll in context |
|
| 899 | if(module.is.verticallyScrollableContext()) { |
|
| 900 | element.offset.top += $context.scrollTop() - $context.offset().top; |
|
| 901 | } |
|
| 902 | if(module.is.horizontallyScrollableContext()) { |
|
| 903 | element.offset.left += $context.scrollLeft - $context.offset().left; |
|
| 904 | } |
|
| 905 | // store |
|
| 906 | module.cache.element = element; |
|
| 907 | return element; |
|
| 908 | }, |
|
| 909 | elementCalculations: function() { |
|
| 910 | var |
|
| 911 | screen = module.get.screenCalculations(), |
|
| 912 | element = module.get.elementPosition() |
|
| 913 | ; |
|
| 914 | // offset |
|
| 915 | if(settings.includeMargin) { |
|
| 916 | element.margin = {}; |
|
| 917 | element.margin.top = parseInt($module.css('margin-top'), 10); |
|
| 918 | element.margin.bottom = parseInt($module.css('margin-bottom'), 10); |
|
| 919 | element.top = element.offset.top - element.margin.top; |
|
| 920 | element.bottom = element.offset.top + element.height + element.margin.bottom; |
|
| 921 | } |
|
| 922 | else { |
|
| 923 | element.top = element.offset.top; |
|
| 924 | element.bottom = element.offset.top + element.height; |
|
| 925 | } |
|
| 926 | ||
| 927 | // visibility |
|
| 928 | element.topPassed = (screen.top >= element.top); |
|
| 929 | element.bottomPassed = (screen.top >= element.bottom); |
|
| 930 | element.topVisible = (screen.bottom >= element.top) && !element.bottomPassed; |
|
| 931 | element.bottomVisible = (screen.bottom >= element.bottom) && !element.topPassed; |
|
| 932 | element.pixelsPassed = 0; |
|
| 933 | element.percentagePassed = 0; |
|
| 934 | ||
| 935 | // meta calculations |
|
| 936 | element.onScreen = (element.topVisible && !element.bottomPassed); |
|
| 937 | element.passing = (element.topPassed && !element.bottomPassed); |
|
| 938 | element.offScreen = (!element.onScreen); |
|
| 939 | ||
| 940 | // passing calculations |
|
| 941 | if(element.passing) { |
|
| 942 | element.pixelsPassed = (screen.top - element.top); |
|
| 943 | element.percentagePassed = (screen.top - element.top) / element.height; |
|
| 944 | } |
|
| 945 | module.cache.element = element; |
|
| 946 | module.verbose('Updated element calculations', element); |
|
| 947 | return element; |
|
| 948 | }, |
|
| 949 | screenCalculations: function() { |
|
| 950 | var |
|
| 951 | scroll = module.get.scroll() |
|
| 952 | ; |
|
| 953 | module.save.direction(); |
|
| 954 | module.cache.screen.top = scroll; |
|
| 955 | module.cache.screen.bottom = scroll + module.cache.screen.height; |
|
| 956 | return module.cache.screen; |
|
| 957 | }, |
|
| 958 | screenSize: function() { |
|
| 959 | module.verbose('Saving window position'); |
|
| 960 | module.cache.screen = { |
|
| 961 | height: $context.height() |
|
| 962 | }; |
|
| 963 | }, |
|
| 964 | position: function() { |
|
| 965 | module.save.screenSize(); |
|
| 966 | module.save.elementPosition(); |
|
| 967 | } |
|
| 968 | }, |
|
| 969 | ||
| 970 | get: { |
|
| 971 | pixelsPassed: function(amount) { |
|
| 972 | var |
|
| 973 | element = module.get.elementCalculations() |
|
| 974 | ; |
|
| 975 | if(amount.search('%') > -1) { |
|
| 976 | return ( element.height * (parseInt(amount, 10) / 100) ); |
|
| 977 | } |
|
| 978 | return parseInt(amount, 10); |
|
| 979 | }, |
|
| 980 | occurred: function(callback) { |
|
| 981 | return (module.cache.occurred !== undefined) |
|
| 982 | ? module.cache.occurred[callback] || false |
|
| 983 | : false |
|
| 984 | ; |
|
| 985 | }, |
|
| 986 | direction: function() { |
|
| 987 | if(module.cache.direction === undefined) { |
|
| 988 | module.save.direction(); |
|
| 989 | } |
|
| 990 | return module.cache.direction; |
|
| 991 | }, |
|
| 992 | elementPosition: function() { |
|
| 993 | if(module.cache.element === undefined) { |
|
| 994 | module.save.elementPosition(); |
|
| 995 | } |
|
| 996 | return module.cache.element; |
|
| 997 | }, |
|
| 998 | elementCalculations: function() { |
|
| 999 | if(module.cache.element === undefined) { |
|
| 1000 | module.save.elementCalculations(); |
|
| 1001 | } |
|
| 1002 | return module.cache.element; |
|
| 1003 | }, |
|
| 1004 | screenCalculations: function() { |
|
| 1005 | if(module.cache.screen === undefined) { |
|
| 1006 | module.save.screenCalculations(); |
|
| 1007 | } |
|
| 1008 | return module.cache.screen; |
|
| 1009 | }, |
|
| 1010 | screenSize: function() { |
|
| 1011 | if(module.cache.screen === undefined) { |
|
| 1012 | module.save.screenSize(); |
|
| 1013 | } |
|
| 1014 | return module.cache.screen; |
|
| 1015 | }, |
|
| 1016 | scroll: function() { |
|
| 1017 | if(module.cache.scroll === undefined) { |
|
| 1018 | module.save.scroll(); |
|
| 1019 | } |
|
| 1020 | return module.cache.scroll; |
|
| 1021 | }, |
|
| 1022 | lastScroll: function() { |
|
| 1023 | if(module.cache.screen === undefined) { |
|
| 1024 | module.debug('First scroll event, no last scroll could be found'); |
|
| 1025 | return false; |
|
| 1026 | } |
|
| 1027 | return module.cache.screen.top; |
|
| 1028 | } |
|
| 1029 | }, |
|
| 1030 | ||
| 1031 | setting: function(name, value) { |
|
| 1032 | if( $.isPlainObject(name) ) { |
|
| 1033 | $.extend(true, settings, name); |
|
| 1034 | } |
|
| 1035 | else if(value !== undefined) { |
|
| 1036 | settings[name] = value; |
|
| 1037 | } |
|
| 1038 | else { |
|
| 1039 | return settings[name]; |
|
| 1040 | } |
|
| 1041 | }, |
|
| 1042 | internal: function(name, value) { |
|
| 1043 | if( $.isPlainObject(name) ) { |
|
| 1044 | $.extend(true, module, name); |
|
| 1045 | } |
|
| 1046 | else if(value !== undefined) { |
|
| 1047 | module[name] = value; |
|
| 1048 | } |
|
| 1049 | else { |
|
| 1050 | return module[name]; |
|
| 1051 | } |
|
| 1052 | }, |
|
| 1053 | debug: function() { |
|
| 1054 | if(!settings.silent && settings.debug) { |
|
| 1055 | if(settings.performance) { |
|
| 1056 | module.performance.log(arguments); |
|
| 1057 | } |
|
| 1058 | else { |
|
| 1059 | module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 1060 | module.debug.apply(console, arguments); |
|
| 1061 | } |
|
| 1062 | } |
|
| 1063 | }, |
|
| 1064 | verbose: function() { |
|
| 1065 | if(!settings.silent && settings.verbose && settings.debug) { |
|
| 1066 | if(settings.performance) { |
|
| 1067 | module.performance.log(arguments); |
|
| 1068 | } |
|
| 1069 | else { |
|
| 1070 | module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 1071 | module.verbose.apply(console, arguments); |
|
| 1072 | } |
|
| 1073 | } |
|
| 1074 | }, |
|
| 1075 | error: function() { |
|
| 1076 | if(!settings.silent) { |
|
| 1077 | module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); |
|
| 1078 | module.error.apply(console, arguments); |
|
| 1079 | } |
|
| 1080 | }, |
|
| 1081 | performance: { |
|
| 1082 | log: function(message) { |
|
| 1083 | var |
|
| 1084 | currentTime, |
|
| 1085 | executionTime, |
|
| 1086 | previousTime |
|
| 1087 | ; |
|
| 1088 | if(settings.performance) { |
|
| 1089 | currentTime = new Date().getTime(); |
|
| 1090 | previousTime = time || currentTime; |
|
| 1091 | executionTime = currentTime - previousTime; |
|
| 1092 | time = currentTime; |
|
| 1093 | performance.push({ |
|
| 1094 | 'Name' : message[0], |
|
| 1095 | 'Arguments' : [].slice.call(message, 1) || '', |
|
| 1096 | 'Element' : element, |
|
| 1097 | 'Execution Time' : executionTime |
|
| 1098 | }); |
|
| 1099 | } |
|
| 1100 | clearTimeout(module.performance.timer); |
|
| 1101 | module.performance.timer = setTimeout(module.performance.display, 500); |
|
| 1102 | }, |
|
| 1103 | display: function() { |
|
| 1104 | var |
|
| 1105 | title = settings.name + ':', |
|
| 1106 | totalTime = 0 |
|
| 1107 | ; |
|
| 1108 | time = false; |
|
| 1109 | clearTimeout(module.performance.timer); |
|
| 1110 | $.each(performance, function(index, data) { |
|
| 1111 | totalTime += data['Execution Time']; |
|
| 1112 | }); |
|
| 1113 | title += ' ' + totalTime + 'ms'; |
|
| 1114 | if(moduleSelector) { |
|
| 1115 | title += ' \'' + moduleSelector + '\''; |
|
| 1116 | } |
|
| 1117 | if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { |
|
| 1118 | console.groupCollapsed(title); |
|
| 1119 | if(console.table) { |
|
| 1120 | console.table(performance); |
|
| 1121 | } |
|
| 1122 | else { |
|
| 1123 | $.each(performance, function(index, data) { |
|
| 1124 | console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); |
|
| 1125 | }); |
|
| 1126 | } |
|
| 1127 | console.groupEnd(); |
|
| 1128 | } |
|
| 1129 | performance = []; |
|
| 1130 | } |
|
| 1131 | }, |
|
| 1132 | invoke: function(query, passedArguments, context) { |
|
| 1133 | var |
|
| 1134 | object = instance, |
|
| 1135 | maxDepth, |
|
| 1136 | found, |
|
| 1137 | response |
|
| 1138 | ; |
|
| 1139 | passedArguments = passedArguments || queryArguments; |
|
| 1140 | context = element || context; |
|
| 1141 | if(typeof query == 'string' && object !== undefined) { |
|
| 1142 | query = query.split(/[\. ]/); |
|
| 1143 | maxDepth = query.length - 1; |
|
| 1144 | $.each(query, function(depth, value) { |
|
| 1145 | var camelCaseValue = (depth != maxDepth) |
|
| 1146 | ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) |
|
| 1147 | : query |
|
| 1148 | ; |
|
| 1149 | if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { |
|
| 1150 | object = object[camelCaseValue]; |
|
| 1151 | } |
|
| 1152 | else if( object[camelCaseValue] !== undefined ) { |
|
| 1153 | found = object[camelCaseValue]; |
|
| 1154 | return false; |
|
| 1155 | } |
|
| 1156 | else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { |
|
| 1157 | object = object[value]; |
|
| 1158 | } |
|
| 1159 | else if( object[value] !== undefined ) { |
|
| 1160 | found = object[value]; |
|
| 1161 | return false; |
|
| 1162 | } |
|
| 1163 | else { |
|
| 1164 | module.error(error.method, query); |
|
| 1165 | return false; |
|
| 1166 | } |
|
| 1167 | }); |
|
| 1168 | } |
|
| 1169 | if ( $.isFunction( found ) ) { |
|
| 1170 | response = found.apply(context, passedArguments); |
|
| 1171 | } |
|
| 1172 | else if(found !== undefined) { |
|
| 1173 | response = found; |
|
| 1174 | } |
|
| 1175 | if($.isArray(returnedValue)) { |
|
| 1176 | returnedValue.push(response); |
|
| 1177 | } |
|
| 1178 | else if(returnedValue !== undefined) { |
|
| 1179 | returnedValue = [returnedValue, response]; |
|
| 1180 | } |
|
| 1181 | else if(response !== undefined) { |
|
| 1182 | returnedValue = response; |
|
| 1183 | } |
|
| 1184 | return found; |
|
| 1185 | } |
|
| 1186 | }; |
|
| 1187 | ||
| 1188 | if(methodInvoked) { |
|
| 1189 | if(instance === undefined) { |
|
| 1190 | module.initialize(); |
|
| 1191 | } |
|
| 1192 | instance.save.scroll(); |
|
| 1193 | instance.save.calculations(); |
|
| 1194 | module.invoke(query); |
|
| 1195 | } |
|
| 1196 | else { |
|
| 1197 | if(instance !== undefined) { |
|
| 1198 | instance.invoke('destroy'); |
|
| 1199 | } |
|
| 1200 | module.initialize(); |
|
| 1201 | } |
|
| 1202 | }) |
|
| 1203 | ; |
|
| 1204 | ||
| 1205 | return (returnedValue !== undefined) |
|
| 1206 | ? returnedValue |
|
| 1207 | : this |
|
| 1208 | ; |
|
| 1209 | }; |
|
| 1210 | ||
| 1211 | $.fn.visibility.settings = { |
|
| 1212 | ||
| 1213 | name : 'Visibility', |
|
| 1214 | namespace : 'visibility', |
|
| 1215 | ||
| 1216 | debug : false, |
|
| 1217 | verbose : false, |
|
| 1218 | performance : true, |
|
| 1219 | ||
| 1220 | // whether to use mutation observers to follow changes |
|
| 1221 | observeChanges : true, |
|
| 1222 | ||
| 1223 | // check position immediately on init |
|
| 1224 | initialCheck : true, |
|
| 1225 | ||
| 1226 | // whether to refresh calculations after all page images load |
|
| 1227 | refreshOnLoad : true, |
|
| 1228 | ||
| 1229 | // whether to refresh calculations after page resize event |
|
| 1230 | refreshOnResize : true, |
|
| 1231 | ||
| 1232 | // should call callbacks on refresh event (resize, etc) |
|
| 1233 | checkOnRefresh : true, |
|
| 1234 | ||
| 1235 | // callback should only occur one time |
|
| 1236 | once : true, |
|
| 1237 | ||
| 1238 | // callback should fire continuously whe evaluates to true |
|
| 1239 | continuous : false, |
|
| 1240 | ||
| 1241 | // offset to use with scroll top |
|
| 1242 | offset : 0, |
|
| 1243 | ||
| 1244 | // whether to include margin in elements position |
|
| 1245 | includeMargin : false, |
|
| 1246 | ||
| 1247 | // scroll context for visibility checks |
|
| 1248 | context : window, |
|
| 1249 | ||
| 1250 | // visibility check delay in ms (defaults to animationFrame) |
|
| 1251 | throttle : false, |
|
| 1252 | ||
| 1253 | // special visibility type (image, fixed) |
|
| 1254 | type : false, |
|
| 1255 | ||
| 1256 | // z-index to use with visibility 'fixed' |
|
| 1257 | zIndex : '10', |
|
| 1258 | ||
| 1259 | // image only animation settings |
|
| 1260 | transition : 'fade in', |
|
| 1261 | duration : 1000, |
|
| 1262 | ||
| 1263 | // array of callbacks for percentage |
|
| 1264 | onPassed : {}, |
|
| 1265 | ||
| 1266 | // standard callbacks |
|
| 1267 | onOnScreen : false, |
|
| 1268 | onOffScreen : false, |
|
| 1269 | onPassing : false, |
|
| 1270 | onTopVisible : false, |
|
| 1271 | onBottomVisible : false, |
|
| 1272 | onTopPassed : false, |
|
| 1273 | onBottomPassed : false, |
|
| 1274 | ||
| 1275 | // reverse callbacks |
|
| 1276 | onPassingReverse : false, |
|
| 1277 | onTopVisibleReverse : false, |
|
| 1278 | onBottomVisibleReverse : false, |
|
| 1279 | onTopPassedReverse : false, |
|
| 1280 | onBottomPassedReverse : false, |
|
| 1281 | ||
| 1282 | // special callbacks for image |
|
| 1283 | onLoad : function() {}, |
|
| 1284 | onAllLoaded : function() {}, |
|
| 1285 | ||
| 1286 | // special callbacks for fixed position |
|
| 1287 | onFixed : function() {}, |
|
| 1288 | onUnfixed : function() {}, |
|
| 1289 | ||
| 1290 | // utility callbacks |
|
| 1291 | onUpdate : false, // disabled by default for performance |
|
| 1292 | onRefresh : function(){}, |
|
| 1293 | ||
| 1294 | metadata : { |
|
| 1295 | src: 'src' |
|
| 1296 | }, |
|
| 1297 | ||
| 1298 | className: { |
|
| 1299 | fixed : 'fixed', |
|
| 1300 | placeholder : 'placeholder', |
|
| 1301 | visible : 'visible' |
|
| 1302 | }, |
|
| 1303 | ||
| 1304 | error : { |
|
| 1305 | method : 'The method you called is not defined.', |
|
| 1306 | visible : 'Element is hidden, you must call refresh after element becomes visible' |
|
| 1307 | } |
|
| 1308 | ||
| 1309 | }; |
|
| 1310 | ||
| 1311 | })( jQuery, window, document ); |
|
| 1312 | ||