github.com/mweagle/Sparta@v1.15.0/docs_source/themes/hugo-theme-learn/static/js/jquery.sticky.js (about)

     1  // Sticky Plugin v1.0.4 for jQuery
     2  // =============
     3  // Author: Anthony Garand
     4  // Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk)
     5  // Improvements by Leonardo C. Daronco (daronco)
     6  // Created: 02/14/2011
     7  // Date: 07/20/2015
     8  // Website: http://stickyjs.com/
     9  // Description: Makes an element on the page stick on the screen as you scroll
    10  //              It will only set the 'top' and 'position' of your element, you
    11  //              might need to adjust the width in some cases.
    12  
    13  (function (factory) {
    14      if (typeof define === 'function' && define.amd) {
    15          // AMD. Register as an anonymous module.
    16          define(['jquery'], factory);
    17      } else if (typeof module === 'object' && module.exports) {
    18          // Node/CommonJS
    19          module.exports = factory(require('jquery'));
    20      } else {
    21          // Browser globals
    22          factory(jQuery);
    23      }
    24  }(function ($) {
    25      var slice = Array.prototype.slice; // save ref to original slice()
    26      var splice = Array.prototype.splice; // save ref to original slice()
    27  
    28    var defaults = {
    29        topSpacing: 0,
    30        bottomSpacing: 0,
    31        className: 'is-sticky',
    32        wrapperClassName: 'sticky-wrapper',
    33        center: false,
    34        getWidthFrom: '',
    35        widthFromWrapper: true, // works only when .getWidthFrom is empty
    36        responsiveWidth: false,
    37        zIndex: 'inherit'
    38      },
    39      $window = $(window),
    40      $document = $(document),
    41      sticked = [],
    42      windowHeight = $window.height(),
    43      scroller = function() {
    44        var scrollTop = $window.scrollTop(),
    45          documentHeight = $document.height(),
    46          dwh = documentHeight - windowHeight,
    47          extra = (scrollTop > dwh) ? dwh - scrollTop : 0;
    48  
    49        for (var i = 0, l = sticked.length; i < l; i++) {
    50          var s = sticked[i],
    51            elementTop = s.stickyWrapper.offset().top,
    52            etse = elementTop - s.topSpacing - extra;
    53  
    54          //update height in case of dynamic content
    55          s.stickyWrapper.css('height', s.stickyElement.outerHeight());
    56  
    57          if (scrollTop <= etse) {
    58            if (s.currentTop !== null) {
    59              s.stickyElement
    60                .css({
    61                  'width': '',
    62                  'position': '',
    63                  'top': '',
    64                  'z-index': ''
    65                });
    66              s.stickyElement.parent().removeClass(s.className);
    67              s.stickyElement.trigger('sticky-end', [s]);
    68              s.currentTop = null;
    69            }
    70          }
    71          else {
    72            var newTop = documentHeight - s.stickyElement.outerHeight()
    73              - s.topSpacing - s.bottomSpacing - scrollTop - extra;
    74            if (newTop < 0) {
    75              newTop = newTop + s.topSpacing;
    76            } else {
    77              newTop = s.topSpacing;
    78            }
    79            if (s.currentTop !== newTop) {
    80              var newWidth;
    81              if (s.getWidthFrom) {
    82                  padding =  s.stickyElement.innerWidth() - s.stickyElement.width();
    83                  newWidth = $(s.getWidthFrom).width() - padding || null;
    84              } else if (s.widthFromWrapper) {
    85                  newWidth = s.stickyWrapper.width();
    86              }
    87              if (newWidth == null) {
    88                  newWidth = s.stickyElement.width();
    89              }
    90              s.stickyElement
    91                .css('width', newWidth)
    92                .css('position', 'fixed')
    93                .css('top', newTop)
    94                .css('z-index', s.zIndex);
    95  
    96              s.stickyElement.parent().addClass(s.className);
    97  
    98              if (s.currentTop === null) {
    99                s.stickyElement.trigger('sticky-start', [s]);
   100              } else {
   101                // sticky is started but it have to be repositioned
   102                s.stickyElement.trigger('sticky-update', [s]);
   103              }
   104  
   105              if (s.currentTop === s.topSpacing && s.currentTop > newTop || s.currentTop === null && newTop < s.topSpacing) {
   106                // just reached bottom || just started to stick but bottom is already reached
   107                s.stickyElement.trigger('sticky-bottom-reached', [s]);
   108              } else if(s.currentTop !== null && newTop === s.topSpacing && s.currentTop < newTop) {
   109                // sticky is started && sticked at topSpacing && overflowing from top just finished
   110                s.stickyElement.trigger('sticky-bottom-unreached', [s]);
   111              }
   112  
   113              s.currentTop = newTop;
   114            }
   115  
   116            // Check if sticky has reached end of container and stop sticking
   117            var stickyWrapperContainer = s.stickyWrapper.parent();
   118            var unstick = (s.stickyElement.offset().top + s.stickyElement.outerHeight() >= stickyWrapperContainer.offset().top + stickyWrapperContainer.outerHeight()) && (s.stickyElement.offset().top <= s.topSpacing);
   119  
   120            if( unstick ) {
   121              s.stickyElement
   122                .css('position', 'absolute')
   123                .css('top', '')
   124                .css('bottom', 0)
   125                .css('z-index', '');
   126            } else {
   127              s.stickyElement
   128                .css('position', 'fixed')
   129                .css('top', newTop)
   130                .css('bottom', '')
   131                .css('z-index', s.zIndex);
   132            }
   133          }
   134        }
   135      },
   136      resizer = function() {
   137        windowHeight = $window.height();
   138  
   139        for (var i = 0, l = sticked.length; i < l; i++) {
   140          var s = sticked[i];
   141          var newWidth = null;
   142          if (s.getWidthFrom) {
   143              if (s.responsiveWidth) {
   144                  newWidth = $(s.getWidthFrom).width();
   145              }
   146          } else if(s.widthFromWrapper) {
   147              newWidth = s.stickyWrapper.width();
   148          }
   149          if (newWidth != null) {
   150              s.stickyElement.css('width', newWidth);
   151          }
   152        }
   153      },
   154      methods = {
   155        init: function(options) {
   156          return this.each(function() {
   157            var o = $.extend({}, defaults, options);
   158            var stickyElement = $(this);
   159  
   160            var stickyId = stickyElement.attr('id');
   161            var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName;
   162            var wrapper = $('<div></div>')
   163              .attr('id', wrapperId)
   164              .addClass(o.wrapperClassName);
   165  
   166            stickyElement.wrapAll(function() {
   167              if ($(this).parent("#" + wrapperId).length == 0) {
   168                      return wrapper;
   169              }
   170  });
   171  
   172            var stickyWrapper = stickyElement.parent();
   173  
   174            if (o.center) {
   175              stickyWrapper.css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"});
   176            }
   177  
   178            if (stickyElement.css("float") === "right") {
   179              stickyElement.css({"float":"none"}).parent().css({"float":"right"});
   180            }
   181  
   182            o.stickyElement = stickyElement;
   183            o.stickyWrapper = stickyWrapper;
   184            o.currentTop    = null;
   185  
   186            sticked.push(o);
   187  
   188            methods.setWrapperHeight(this);
   189            methods.setupChangeListeners(this);
   190          });
   191        },
   192  
   193        setWrapperHeight: function(stickyElement) {
   194          var element = $(stickyElement);
   195          var stickyWrapper = element.parent();
   196          if (stickyWrapper) {
   197            stickyWrapper.css('height', element.outerHeight());
   198          }
   199        },
   200  
   201        setupChangeListeners: function(stickyElement) {
   202          if (window.MutationObserver) {
   203            var mutationObserver = new window.MutationObserver(function(mutations) {
   204              if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {
   205                methods.setWrapperHeight(stickyElement);
   206              }
   207            });
   208            mutationObserver.observe(stickyElement, {subtree: true, childList: true});
   209          } else {
   210            if (window.addEventListener) {
   211              stickyElement.addEventListener('DOMNodeInserted', function() {
   212                methods.setWrapperHeight(stickyElement);
   213              }, false);
   214              stickyElement.addEventListener('DOMNodeRemoved', function() {
   215                methods.setWrapperHeight(stickyElement);
   216              }, false);
   217            } else if (window.attachEvent) {
   218              stickyElement.attachEvent('onDOMNodeInserted', function() {
   219                methods.setWrapperHeight(stickyElement);
   220              });
   221              stickyElement.attachEvent('onDOMNodeRemoved', function() {
   222                methods.setWrapperHeight(stickyElement);
   223              });
   224            }
   225          }
   226        },
   227        update: scroller,
   228        unstick: function(options) {
   229          return this.each(function() {
   230            var that = this;
   231            var unstickyElement = $(that);
   232  
   233            var removeIdx = -1;
   234            var i = sticked.length;
   235            while (i-- > 0) {
   236              if (sticked[i].stickyElement.get(0) === that) {
   237                  splice.call(sticked,i,1);
   238                  removeIdx = i;
   239              }
   240            }
   241            if(removeIdx !== -1) {
   242              unstickyElement.unwrap();
   243              unstickyElement
   244                .css({
   245                  'width': '',
   246                  'position': '',
   247                  'top': '',
   248                  'float': '',
   249                  'z-index': ''
   250                })
   251              ;
   252            }
   253          });
   254        }
   255      };
   256  
   257    // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer):
   258    if (window.addEventListener) {
   259      window.addEventListener('scroll', scroller, false);
   260      window.addEventListener('resize', resizer, false);
   261    } else if (window.attachEvent) {
   262      window.attachEvent('onscroll', scroller);
   263      window.attachEvent('onresize', resizer);
   264    }
   265  
   266    $.fn.sticky = function(method) {
   267      if (methods[method]) {
   268        return methods[method].apply(this, slice.call(arguments, 1));
   269      } else if (typeof method === 'object' || !method ) {
   270        return methods.init.apply( this, arguments );
   271      } else {
   272        $.error('Method ' + method + ' does not exist on jQuery.sticky');
   273      }
   274    };
   275  
   276    $.fn.unstick = function(method) {
   277      if (methods[method]) {
   278        return methods[method].apply(this, slice.call(arguments, 1));
   279      } else if (typeof method === 'object' || !method ) {
   280        return methods.unstick.apply( this, arguments );
   281      } else {
   282        $.error('Method ' + method + ' does not exist on jQuery.sticky');
   283      }
   284    };
   285    $(function() {
   286      setTimeout(scroller, 0);
   287    });
   288  }));