relatively-sticky

A jQuery plugin for creating smart sticky elements
git clone https://git.ce9e.org/relatively-sticky.git

commit
923575d2c6536b370551b3004c0e86881ac279f9
parent
59b27dd6f544a113abc1c82e3f31953fe2bb0f6f
Author
Tobias Bengfort <tobias.bengfort@gmx.net>
Date
2015-02-28 11:54
bump version to 2.0.0

Diffstat

M bower.json 2 +-
M jquery.relatively-sticky.coffee 2 +-
M jquery.relatively-sticky.js 250 ++++++++++++++++++++-----------------------------------------
M jquery.relatively-sticky.min.js 14 +++++---------
M relatively-sticky.jquery.json 2 +-

5 files changed, 88 insertions, 182 deletions


diff --git a/bower.json b/bower.json

@@ -1,6 +1,6 @@
    1     1 {
    2     2   "name": "relatively-sticky",
    3    -1   "version": "1.1.1",
   -1     3   "version": "2.0.0",
    4     4   "homepage": "http://leafo.net/sticky-kit/",
    5     5   "authors": [
    6     6     "tobias bengfort <tobias.bengfort@poste.de>"

diff --git a/jquery.relatively-sticky.coffee b/jquery.relatively-sticky.coffee

@@ -1,5 +1,5 @@
    1     1 ###*
    2    -1 @license Relatively-Sticky v1.1.1 | WTFPL | Tobias Bengfort 2015
   -1     2 @license Relatively-Sticky v2.0.0 | WTFPL | Tobias Bengfort 2015
    3     3 ###
    4     4 
    5     5 $ = @jQuery or window.jQuery

diff --git a/jquery.relatively-sticky.js b/jquery.relatively-sticky.js

@@ -1,43 +1,61 @@
    1    -1 // Generated by CoffeeScript 1.8.0
   -1     1 // Generated by CoffeeScript 1.9.1
    2     2 
    3     3 /**
    4    -1 @license Sticky-kit v1.1.1 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
   -1     4 @license Relatively-Sticky v2.0.0 | WTFPL | Tobias Bengfort 2015
    5     5  */
    6     6 
    7     7 (function() {
    8    -1   var $, win;
   -1     8   var $, top, win;
    9     9 
   10    10   $ = this.jQuery || window.jQuery;
   11    11 
   12    12   win = $(window);
   13    13 
   -1    14   top = function(element, context) {
   -1    15     if (context === document) {
   -1    16       if (element === document) {
   -1    17         return 0;
   -1    18       } else if (element === win) {
   -1    19         return win.scrollTop();
   -1    20       } else {
   -1    21         return element.offset().top;
   -1    22       }
   -1    23     } else {
   -1    24       return top(element, document) - top(context, document);
   -1    25     }
   -1    26   };
   -1    27 
   14    28   $.fn.stick_in_parent = function(opts) {
   15    -1     var elm, enable_bottoming, inner_scrolling, manual_spacer, offset_top, parent_selector, recalc_every, sticky_class, _fn, _i, _len;
   -1    29     var elm, enable_bottoming, fn, i, len, offset_top, parent_selector, scrollable_selector, sticky_class;
   16    30     if (opts == null) {
   17    31       opts = {};
   18    32     }
   19    -1     sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming;
   -1    33     sticky_class = opts.sticky_class, parent_selector = opts.parent, scrollable_selector = opts.scrollable, offset_top = opts.offset_top, enable_bottoming = opts.bottoming;
   20    34     if (offset_top == null) {
   21    35       offset_top = 0;
   22    36     }
   23    37     if (parent_selector == null) {
   24    38       parent_selector = void 0;
   25    39     }
   26    -1     if (inner_scrolling == null) {
   27    -1       inner_scrolling = true;
   28    -1     }
   29    40     if (sticky_class == null) {
   30    41       sticky_class = "is_stuck";
   31    42     }
   32    43     if (enable_bottoming == null) {
   33    44       enable_bottoming = true;
   34    45     }
   35    -1     _fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
   36    -1       var bottomed, detach, fixed, last_pos, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
   -1    46     fn = function(elm, detached, fixed, bottomed) {
   -1    47       var _top, detach, get_max, parent, scrollable, tick;
   37    48       if (elm.data("sticky_kit")) {
   38    49         return;
   39    50       }
   40    51       elm.data("sticky_kit", true);
   -1    52       scrollable = win;
   -1    53       if (scrollable_selector != null) {
   -1    54         scrollable = elm.parent().closest(scrollable_selector);
   -1    55       }
   -1    56       if (!scrollable.length) {
   -1    57         throw "failed to find stick scrollable";
   -1    58       }
   41    59       parent = elm.parent();
   42    60       if (parent_selector != null) {
   43    61         parent = parent.closest(parent_selector);
@@ -45,196 +63,88 @@
   45    63       if (!parent.length) {
   46    64         throw "failed to find stick parent";
   47    65       }
   48    -1       fixed = false;
   49    -1       bottomed = false;
   50    -1       spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
   51    -1       if (spacer) {
   52    -1         spacer.css('position', elm.css('position'));
   53    -1       }
   54    -1       recalc = function() {
   55    -1         var border_top, padding_top, restore;
   56    -1         if (detached) {
   57    -1           return;
   58    -1         }
   59    -1         border_top = parseInt(parent.css("border-top-width"), 10);
   60    -1         padding_top = parseInt(parent.css("padding-top"), 10);
   -1    66       _top = 0;
   -1    67       elm.css("position", "relative");
   -1    68       get_max = function() {
   -1    69         var border_bottom, margin_top, padding_bottom;
   61    70         padding_bottom = parseInt(parent.css("padding-bottom"), 10);
   62    -1         parent_top = parent.offset().top + border_top + padding_top;
   63    -1         parent_height = parent.height();
   64    -1         if (fixed) {
   65    -1           fixed = false;
   66    -1           bottomed = false;
   67    -1           if (manual_spacer == null) {
   68    -1             elm.insertAfter(spacer);
   69    -1             spacer.detach();
   70    -1           }
   71    -1           elm.css({
   72    -1             position: "",
   73    -1             top: "",
   74    -1             width: "",
   75    -1             bottom: ""
   76    -1           }).removeClass(sticky_class);
   77    -1           restore = true;
   78    -1         }
   79    -1         top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
   80    -1         height = elm.outerHeight(true);
   81    -1         el_float = elm.css("float");
   82    -1         if (spacer) {
   83    -1           spacer.css({
   84    -1             width: elm.outerWidth(true),
   85    -1             height: height,
   86    -1             display: elm.css("display"),
   87    -1             "vertical-align": elm.css("vertical-align"),
   88    -1             "float": el_float
   89    -1           });
   90    -1         }
   91    -1         if (restore) {
   92    -1           return tick();
   93    -1         }
   -1    71         border_bottom = parseInt(parent.css("border-bottom-width"), 10);
   -1    72         margin_top = parseInt(elm.css("margin-top"), 10);
   -1    73         return parent.outerHeight() - (elm.outerHeight(true) - margin_top) - padding_bottom - border_bottom;
   94    74       };
   95    -1       recalc();
   96    -1       if (height === parent_height) {
   97    -1         return;
   98    -1       }
   99    -1       last_pos = void 0;
  100    -1       offset = offset_top;
  101    -1       recalc_counter = recalc_every;
  102    75       tick = function() {
  103    -1         var css, delta, scroll, will_bottom, win_height;
   -1    76         var bottomed_old, fixed_old, margin_top, max, original_top;
  104    77         if (detached) {
  105    78           return;
  106    79         }
  107    -1         if (recalc_counter != null) {
  108    -1           recalc_counter -= 1;
  109    -1           if (recalc_counter <= 0) {
  110    -1             recalc_counter = recalc_every;
  111    -1             recalc();
   -1    80         fixed_old = fixed;
   -1    81         bottomed_old = bottomed;
   -1    82         margin_top = parseInt(elm.css("margin-top"), 10);
   -1    83         original_top = top(elm, parent) - _top;
   -1    84         _top = top(scrollable, parent) + offset_top + margin_top;
   -1    85         if (enable_bottoming) {
   -1    86           max = get_max();
   -1    87           if (bottomed = _top >= max) {
   -1    88             _top = max;
  112    89           }
  113    90         }
  114    -1         scroll = win.scrollTop();
  115    -1         if (last_pos != null) {
  116    -1           delta = scroll - last_pos;
  117    -1         }
  118    -1         last_pos = scroll;
  119    -1         if (fixed) {
  120    -1           if (enable_bottoming) {
  121    -1             will_bottom = scroll + height + offset > parent_height + parent_top;
  122    -1             if (bottomed && !will_bottom) {
  123    -1               bottomed = false;
  124    -1               elm.css({
  125    -1                 position: "fixed",
  126    -1                 bottom: "",
  127    -1                 top: offset
  128    -1               }).trigger("sticky_kit:unbottom");
  129    -1             }
  130    -1           }
  131    -1           if (scroll < top) {
  132    -1             fixed = false;
  133    -1             offset = offset_top;
  134    -1             if (manual_spacer == null) {
  135    -1               if (el_float === "left" || el_float === "right") {
  136    -1                 elm.insertAfter(spacer);
  137    -1               }
  138    -1               spacer.detach();
  139    -1             }
  140    -1             css = {
  141    -1               position: "",
  142    -1               width: "",
  143    -1               top: ""
  144    -1             };
  145    -1             elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
  146    -1           }
  147    -1           if (inner_scrolling) {
  148    -1             win_height = win.height();
  149    -1             if (height + offset_top > win_height) {
  150    -1               if (!bottomed) {
  151    -1                 offset -= delta;
  152    -1                 offset = Math.max(win_height - height, offset);
  153    -1                 offset = Math.min(offset_top, offset);
  154    -1                 if (fixed) {
  155    -1                   elm.css({
  156    -1                     top: offset + "px"
  157    -1                   });
  158    -1                 }
  159    -1               }
  160    -1             }
  161    -1           }
   -1    91         _top = Math.max(_top - original_top, 0);
   -1    92         elm.css("top", _top);
   -1    93         if ((fixed = _top !== 0)) {
   -1    94           elm.addClass(sticky_class);
  162    95         } else {
  163    -1           if (scroll > top) {
  164    -1             fixed = true;
  165    -1             css = {
  166    -1               position: "fixed",
  167    -1               top: offset
  168    -1             };
  169    -1             css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
  170    -1             elm.css(css).addClass(sticky_class);
  171    -1             if (manual_spacer == null) {
  172    -1               elm.after(spacer);
  173    -1               if (el_float === "left" || el_float === "right") {
  174    -1                 spacer.append(elm);
  175    -1               }
  176    -1             }
  177    -1             elm.trigger("sticky_kit:stick");
  178    -1           }
   -1    96           elm.removeClass(sticky_class);
  179    97         }
  180    -1         if (fixed && enable_bottoming) {
  181    -1           if (will_bottom == null) {
  182    -1             will_bottom = scroll + height + offset > parent_height + parent_top;
  183    -1           }
  184    -1           if (!bottomed && will_bottom) {
  185    -1             bottomed = true;
  186    -1             if (parent.css("position") === "static") {
  187    -1               parent.css({
  188    -1                 position: "relative"
  189    -1               });
  190    -1             }
  191    -1             return elm.css({
  192    -1               position: "absolute",
  193    -1               bottom: padding_bottom,
  194    -1               top: "auto"
  195    -1             }).trigger("sticky_kit:bottom");
  196    -1           }
   -1    98         if (!fixed && fixed_old) {
   -1    99           elm.trigger("sticky_kit:unstick");
   -1   100         }
   -1   101         if (!bottomed && bottomed_old) {
   -1   102           elm.trigger("sticky_kit:unbottom");
   -1   103         }
   -1   104         if (fixed && !fixed_old) {
   -1   105           return elm.trigger("sticky_kit:stick");
   -1   106         } else if (bottomed && !bottomed_old) {
   -1   107           return elm.trigger("sticky_kit:bottom");
  197   108         }
  198    -1       };
  199    -1       recalc_and_tick = function() {
  200    -1         recalc();
  201    -1         return tick();
  202   109       };
  203   110       detach = function() {
  204   111         detached = true;
  205   112         win.off("touchmove", tick);
  206   113         win.off("scroll", tick);
  207    -1         win.off("resize", recalc_and_tick);
  208    -1         $(document.body).off("sticky_kit:recalc", recalc_and_tick);
   -1   114         win.off("resize", tick);
   -1   115         if (scrollable_selector) {
   -1   116           scrollable.off("touchmove", tick);
   -1   117           scrollable.off("scroll", tick);
   -1   118           elm.parentsUntil(scrollable).off("touchmove", tick);
   -1   119           elm.parentsUntil(scrollable).off("scroll", tick);
   -1   120         }
   -1   121         $(document.body).off("sticky_kit:recalc", tick);
  209   122         elm.off("sticky_kit:detach", detach);
  210   123         elm.removeData("sticky_kit");
  211   124         elm.css({
  212   125           position: "",
  213    -1           bottom: "",
  214    -1           top: "",
  215    -1           width: ""
   -1   126           top: ""
  216   127         });
  217    -1         parent.position("position", "");
  218   128         if (fixed) {
  219    -1           if (manual_spacer == null) {
  220    -1             if (el_float === "left" || el_float === "right") {
  221    -1               elm.insertAfter(spacer);
  222    -1             }
  223    -1             spacer.remove();
  224    -1           }
  225   129           return elm.removeClass(sticky_class);
  226   130         }
  227   131       };
  228   132       win.on("touchmove", tick);
  229   133       win.on("scroll", tick);
  230    -1       win.on("resize", recalc_and_tick);
  231    -1       $(document.body).on("sticky_kit:recalc", recalc_and_tick);
   -1   134       win.on("resize", tick);
   -1   135       if (scrollable_selector) {
   -1   136         scrollable.on("touchmove", tick);
   -1   137         scrollable.on("scroll", tick);
   -1   138         elm.parentsUntil(scrollable).on("touchmove", tick);
   -1   139         elm.parentsUntil(scrollable).on("scroll", tick);
   -1   140       }
   -1   141       $(document.body).on("sticky_kit:recalc", tick);
  232   142       elm.on("sticky_kit:detach", detach);
  233   143       return setTimeout(tick, 0);
  234   144     };
  235    -1     for (_i = 0, _len = this.length; _i < _len; _i++) {
  236    -1       elm = this[_i];
  237    -1       _fn($(elm));
   -1   145     for (i = 0, len = this.length; i < len; i++) {
   -1   146       elm = this[i];
   -1   147       fn($(elm));
  238   148     }
  239   149     return this;
  240   150   };

diff --git a/jquery.relatively-sticky.min.js b/jquery.relatively-sticky.min.js

@@ -1,9 +1,4 @@
    1    -1 /*
    2    -1  Sticky-kit v1.1.1 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
    3    -1 */
    4    -1 (function(){var k,e;k=this.jQuery||window.jQuery;e=k(window);k.fn.stick_in_parent=function(d){var v,y,n,p,h,C,s,G,q,H;null==d&&(d={});s=d.sticky_class;y=d.inner_scrolling;C=d.recalc_every;h=d.parent;p=d.offset_top;n=d.spacer;v=d.bottoming;null==p&&(p=0);null==h&&(h=void 0);null==y&&(y=!0);null==s&&(s="is_stuck");null==v&&(v=!0);G=function(a,d,q,z,D,t,r,E){var u,F,m,A,c,f,B,w,x,g,b;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);f=a.parent();null!=h&&(f=f.closest(h));if(!f.length)throw"failed to find stick parent";
    5    -1 u=m=!1;(g=null!=n?n&&a.closest(n):k("<div />"))&&g.css("position",a.css("position"));B=function(){var c,e,l;if(!E&&(c=parseInt(f.css("border-top-width"),10),e=parseInt(f.css("padding-top"),10),d=parseInt(f.css("padding-bottom"),10),q=f.offset().top+c+e,z=f.height(),m&&(u=m=!1,null==n&&(a.insertAfter(g),g.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(s),l=!0),D=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-p,t=a.outerHeight(!0),r=a.css("float"),g&&g.css({width:a.outerWidth(!0),
    6    -1 height:t,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),l))return b()};B();if(t!==z)return A=void 0,c=p,x=C,b=function(){var b,k,l,h;if(!E&&(null!=x&&(--x,0>=x&&(x=C,B())),l=e.scrollTop(),null!=A&&(k=l-A),A=l,m?(v&&(h=l+t+c>z+q,u&&!h&&(u=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),l<D&&(m=!1,c=p,null==n&&("left"!==r&&"right"!==r||a.insertAfter(g),g.detach()),b={position:"",width:"",top:""},a.css(b).removeClass(s).trigger("sticky_kit:unstick")),
    7    -1 y&&(b=e.height(),t+p>b&&!u&&(c-=k,c=Math.max(b-t,c),c=Math.min(p,c),m&&a.css({top:c+"px"})))):l>D&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(s),null==n&&(a.after(g),"left"!==r&&"right"!==r||g.append(a)),a.trigger("sticky_kit:stick")),m&&v&&(null==h&&(h=l+t+c>z+q),!u&&h)))return u=!0,"static"===f.css("position")&&f.css({position:"relative"}),a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},
    8    -1 w=function(){B();return b()},F=function(){E=!0;e.off("touchmove",b);e.off("scroll",b);e.off("resize",w);k(document.body).off("sticky_kit:recalc",w);a.off("sticky_kit:detach",F);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});f.position("position","");if(m)return null==n&&("left"!==r&&"right"!==r||a.insertAfter(g),g.remove()),a.removeClass(s)},e.on("touchmove",b),e.on("scroll",b),e.on("resize",w),k(document.body).on("sticky_kit:recalc",w),a.on("sticky_kit:detach",F),setTimeout(b,
    9    -1 0)}};q=0;for(H=this.length;q<H;q++)d=this[q],G(k(d));return this}}).call(this);
   -1     1 /**
   -1     2 @license Relatively-Sticky v2.0.0 | WTFPL | Tobias Bengfort 2015
   -1     3  */
   -1     4 (function(){var $,top,win;$=this.jQuery||window.jQuery;win=$(window);top=function(element,context){if(context===document){if(element===document){return 0}else if(element===win){return win.scrollTop()}else{return element.offset().top}}else{return top(element,document)-top(context,document)}};$.fn.stick_in_parent=function(opts){var elm,enable_bottoming,fn,i,len,offset_top,parent_selector,scrollable_selector,sticky_class;if(opts==null){opts={}}sticky_class=opts.sticky_class,parent_selector=opts.parent,scrollable_selector=opts.scrollable,offset_top=opts.offset_top,enable_bottoming=opts.bottoming;if(offset_top==null){offset_top=0}if(parent_selector==null){parent_selector=void 0}if(sticky_class==null){sticky_class="is_stuck"}if(enable_bottoming==null){enable_bottoming=true}fn=function(elm,detached,fixed,bottomed){var _top,detach,get_max,parent,scrollable,tick;if(elm.data("sticky_kit")){return}elm.data("sticky_kit",true);scrollable=win;if(scrollable_selector!=null){scrollable=elm.parent().closest(scrollable_selector)}if(!scrollable.length){throw"failed to find stick scrollable"}parent=elm.parent();if(parent_selector!=null){parent=parent.closest(parent_selector)}if(!parent.length){throw"failed to find stick parent"}_top=0;elm.css("position","relative");get_max=function(){var border_bottom,margin_top,padding_bottom;padding_bottom=parseInt(parent.css("padding-bottom"),10);border_bottom=parseInt(parent.css("border-bottom-width"),10);margin_top=parseInt(elm.css("margin-top"),10);return parent.outerHeight()-(elm.outerHeight(true)-margin_top)-padding_bottom-border_bottom};tick=function(){var bottomed_old,fixed_old,margin_top,max,original_top;if(detached){return}fixed_old=fixed;bottomed_old=bottomed;margin_top=parseInt(elm.css("margin-top"),10);original_top=top(elm,parent)-_top;_top=top(scrollable,parent)+offset_top+margin_top;if(enable_bottoming){max=get_max();if(bottomed=_top>=max){_top=max}}_top=Math.max(_top-original_top,0);elm.css("top",_top);if(fixed=_top!==0){elm.addClass(sticky_class)}else{elm.removeClass(sticky_class)}if(!fixed&&fixed_old){elm.trigger("sticky_kit:unstick")}if(!bottomed&&bottomed_old){elm.trigger("sticky_kit:unbottom")}if(fixed&&!fixed_old){return elm.trigger("sticky_kit:stick")}else if(bottomed&&!bottomed_old){return elm.trigger("sticky_kit:bottom")}};detach=function(){detached=true;win.off("touchmove",tick);win.off("scroll",tick);win.off("resize",tick);if(scrollable_selector){scrollable.off("touchmove",tick);scrollable.off("scroll",tick);elm.parentsUntil(scrollable).off("touchmove",tick);elm.parentsUntil(scrollable).off("scroll",tick)}$(document.body).off("sticky_kit:recalc",tick);elm.off("sticky_kit:detach",detach);elm.removeData("sticky_kit");elm.css({position:"",top:""});if(fixed){return elm.removeClass(sticky_class)}};win.on("touchmove",tick);win.on("scroll",tick);win.on("resize",tick);if(scrollable_selector){scrollable.on("touchmove",tick);scrollable.on("scroll",tick);elm.parentsUntil(scrollable).on("touchmove",tick);elm.parentsUntil(scrollable).on("scroll",tick)}$(document.body).on("sticky_kit:recalc",tick);elm.on("sticky_kit:detach",detach);return setTimeout(tick,0)};for(i=0,len=this.length;i<len;i++){elm=this[i];fn($(elm))}return this}}).call(this)
   -1     4 
\ No newline at end of file

diff --git a/relatively-sticky.jquery.json b/relatively-sticky.jquery.json

@@ -1,6 +1,6 @@
    1     1 {
    2     2   "name": "relatively-sticky",
    3    -1   "version": "1.1.1",
   -1     3   "version": "2.0.0",
    4     4 
    5     5   "title": "Relatively-Sticky",
    6     6   "homepage": "https://github.com/xi/relatively-sticky",