relatively-sticky

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

commit
4c96d55eb79212a36bff5bcd83d291582209414c
parent
1fb90483fdf8f52067efec9851506b93d716e96f
Author
leaf corcoran <leafot@gmail.com>
Date
2014-11-10 22:19
add support for custom spacer

Diffstat

M jquery.sticky-kit.coffee 47 ++++++++++++++++++++++++++++++++---------------
M jquery.sticky-kit.js 55 ++++++++++++++++++++++++++++++++++++-------------------
M jquery.sticky-kit.min.js 10 +++++-----
M test/index.html 17 ++++++++++++++---

4 files changed, 87 insertions, 42 deletions


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

@@ -1,12 +1,12 @@
    1     1 ###*
    2    -1 @license Sticky-kit v1.0.4 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
   -1     2 @license Sticky-kit v1.0.5 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
    3     3 ###
    4     4 
    5     5 $ = @jQuery or window.jQuery
    6     6 
    7     7 win = $ window
    8     8 $.fn.stick_in_parent = (opts={}) ->
    9    -1   { sticky_class, inner_scrolling, parent: parent_selector, offset_top } = opts
   -1     9   { sticky_class, inner_scrolling, parent: parent_selector, offset_top, spacer: manual_spacer } = opts
   10    10   offset_top ?= 0
   11    11   parent_selector ?= undefined
   12    12   inner_scrolling ?= true
@@ -23,7 +23,11 @@ $.fn.stick_in_parent = (opts={}) ->
   23    23 
   24    24       fixed = false
   25    25       bottomed = false
   26    -1       spacer = $("<div />")
   -1    26       spacer = if manual_spacer?
   -1    27         elm.closest manual_spacer
   -1    28       else
   -1    29         $("<div />")
   -1    30 
   27    31       spacer.css('position', elm.css('position'))
   28    32 
   29    33       recalc = ->
@@ -34,17 +38,22 @@ $.fn.stick_in_parent = (opts={}) ->
   34    38         parent_top = parent.offset().top + border_top + padding_top
   35    39         parent_height = parent.height()
   36    40 
   37    -1         restore = if fixed
   -1    41         if fixed
   38    42           fixed = false
   39    43           bottomed = false
   40    -1           elm.insertAfter(spacer).css({
   -1    44 
   -1    45           unless manual_spacer?
   -1    46             elm.insertAfter(spacer)
   -1    47             spacer.detach()
   -1    48 
   -1    49           elm.css({
   41    50             position: ""
   42    51             top: ""
   43    52             width: ""
   44    53             bottom: ""
   45    54           }).removeClass(sticky_class)
   46    -1           spacer.detach()
   47    -1           true
   -1    55 
   -1    56           restore = true
   48    57 
   49    58         top = elm.offset().top - parseInt(elm.css("margin-top"), 10) - offset_top
   50    59 
@@ -91,10 +100,12 @@ $.fn.stick_in_parent = (opts={}) ->
   91   100             fixed = false
   92   101             offset = offset_top
   93   102 
   94    -1             if el_float == "left" || el_float == "right"
   95    -1               elm.insertAfter spacer
   -1   103             unless manual_spacer?
   -1   104               if el_float == "left" || el_float == "right"
   -1   105                 elm.insertAfter spacer
   -1   106 
   -1   107               spacer.detach()
   96   108 
   97    -1             spacer.detach()
   98   109             css = {
   99   110               position: ""
  100   111               width: ""
@@ -130,10 +141,13 @@ $.fn.stick_in_parent = (opts={}) ->
  130   141             else
  131   142               elm.width() + "px"
  132   143 
  133    -1             elm.css(css).addClass(sticky_class).after(spacer)
   -1   144             elm.css(css).addClass(sticky_class)
  134   145 
  135    -1             if el_float == "left" || el_float == "right"
  136    -1               spacer.append elm
   -1   146             unless manual_spacer?
   -1   147               elm.after(spacer)
   -1   148 
   -1   149               if el_float == "left" || el_float == "right"
   -1   150                 spacer.append elm
  137   151 
  138   152             elm.trigger("sticky_kit:stick")
  139   153 
@@ -176,8 +190,11 @@ $.fn.stick_in_parent = (opts={}) ->
  176   190         parent.position "position", ""
  177   191 
  178   192         if fixed
  179    -1           elm.insertAfter(spacer).removeClass sticky_class
  180    -1           spacer.remove()
   -1   193           unless manual_spacer?
   -1   194             elm.insertAfter spacer
   -1   195             spacer.remove()
   -1   196 
   -1   197           elm.removeClass sticky_class
  181   198 
  182   199       win.on "touchmove", tick
  183   200       win.on "scroll", tick

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

@@ -1,4 +1,4 @@
    1    -1 // Generated by CoffeeScript 1.7.1
   -1     1 // Generated by CoffeeScript 1.8.0
    2     2 
    3     3 /**
    4     4 @license Sticky-kit v1.0.4 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
@@ -7,16 +7,16 @@
    7     7 (function() {
    8     8   var $, win;
    9     9 
   10    -1   $ = this.jQuery;
   -1    10   $ = this.jQuery || window.jQuery;
   11    11 
   12    12   win = $(window);
   13    13 
   14    14   $.fn.stick_in_parent = function(opts) {
   15    -1     var elm, inner_scrolling, offset_top, parent_selector, sticky_class, _fn, _i, _len;
   -1    15     var elm, inner_scrolling, manual_spacer, offset_top, parent_selector, sticky_class, _fn, _i, _len;
   16    16     if (opts == null) {
   17    17       opts = {};
   18    18     }
   19    -1     sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, parent_selector = opts.parent, offset_top = opts.offset_top;
   -1    19     sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer;
   20    20     if (offset_top == null) {
   21    21       offset_top = 0;
   22    22     }
@@ -44,7 +44,7 @@
   44    44       }
   45    45       fixed = false;
   46    46       bottomed = false;
   47    -1       spacer = $("<div />");
   -1    47       spacer = manual_spacer != null ? elm.closest(manual_spacer) : $("<div />");
   48    48       spacer.css('position', elm.css('position'));
   49    49       recalc = function() {
   50    50         var border_top, padding_top, restore;
@@ -53,12 +53,21 @@
   53    53         padding_bottom = parseInt(parent.css("padding-bottom"), 10);
   54    54         parent_top = parent.offset().top + border_top + padding_top;
   55    55         parent_height = parent.height();
   56    -1         restore = fixed ? (fixed = false, bottomed = false, elm.insertAfter(spacer).css({
   57    -1           position: "",
   58    -1           top: "",
   59    -1           width: "",
   60    -1           bottom: ""
   61    -1         }).removeClass(sticky_class), spacer.detach(), true) : void 0;
   -1    56         if (fixed) {
   -1    57           fixed = false;
   -1    58           bottomed = false;
   -1    59           if (manual_spacer == null) {
   -1    60             elm.insertAfter(spacer);
   -1    61             spacer.detach();
   -1    62           }
   -1    63           elm.css({
   -1    64             position: "",
   -1    65             top: "",
   -1    66             width: "",
   -1    67             bottom: ""
   -1    68           }).removeClass(sticky_class);
   -1    69           restore = true;
   -1    70         }
   62    71         top = elm.offset().top - parseInt(elm.css("margin-top"), 10) - offset_top;
   63    72         height = elm.outerHeight(true);
   64    73         el_float = elm.css("float");
@@ -99,10 +108,12 @@
   99   108           if (scroll < top) {
  100   109             fixed = false;
  101   110             offset = offset_top;
  102    -1             if (el_float === "left" || el_float === "right") {
  103    -1               elm.insertAfter(spacer);
   -1   111             if (manual_spacer == null) {
   -1   112               if (el_float === "left" || el_float === "right") {
   -1   113                 elm.insertAfter(spacer);
   -1   114               }
   -1   115               spacer.detach();
  104   116             }
  105    -1             spacer.detach();
  106   117             css = {
  107   118               position: "",
  108   119               width: "",
@@ -133,9 +144,12 @@
  133   144               top: offset
  134   145             };
  135   146             css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
  136    -1             elm.css(css).addClass(sticky_class).after(spacer);
  137    -1             if (el_float === "left" || el_float === "right") {
  138    -1               spacer.append(elm);
   -1   147             elm.css(css).addClass(sticky_class);
   -1   148             if (manual_spacer == null) {
   -1   149               elm.after(spacer);
   -1   150               if (el_float === "left" || el_float === "right") {
   -1   151                 spacer.append(elm);
   -1   152               }
  139   153             }
  140   154             elm.trigger("sticky_kit:stick");
  141   155           }
@@ -175,8 +189,11 @@
  175   189         });
  176   190         parent.position("position", "");
  177   191         if (fixed) {
  178    -1           elm.insertAfter(spacer).removeClass(sticky_class);
  179    -1           return spacer.remove();
   -1   192           if (manual_spacer == null) {
   -1   193             elm.insertAfter(spacer);
   -1   194             spacer.remove();
   -1   195           }
   -1   196           return elm.removeClass(sticky_class);
  180   197         }
  181   198       };
  182   199       win.on("touchmove", tick);

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

@@ -1,8 +1,8 @@
    1     1 /*
    2     2  Sticky-kit v1.0.4 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
    3     3 */
    4    -1 (function(){var b,m;b=this.jQuery;m=b(window);b.fn.stick_in_parent=function(e){var u,n,f,p,B,l,C;null==e&&(e={});p=e.sticky_class;u=e.inner_scrolling;f=e.parent;n=e.offset_top;null==n&&(n=0);null==f&&(f=void 0);null==u&&(u=!0);null==p&&(p="is_stuck");B=function(a,e,l,v,y,q,t){var r,z,k,w,c,d,A,x,g,h;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);d=a.parent();null!=f&&(d=d.closest(f));if(!d.length)throw"failed to find stick parent";r=k=!1;g=b("<div />");g.css("position",a.css("position"));A=function(){var c,
    5    -1 b;c=parseInt(d.css("border-top-width"),10);b=parseInt(d.css("padding-top"),10);e=parseInt(d.css("padding-bottom"),10);l=d.offset().top+c+b;v=d.height();c=k?(k=!1,r=!1,a.insertAfter(g).css({position:"",top:"",width:"",bottom:""}).removeClass(p),g.detach(),!0):void 0;y=a.offset().top-parseInt(a.css("margin-top"),10)-n;q=a.outerHeight(!0);t=a.css("float");g.css({width:a.outerWidth(!0),height:q,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":t});if(c)return h()};A();if(q!==v)return w=
    6    -1 void 0,c=n,h=function(){var b,h,s,f;s=m.scrollTop();null!=w&&(h=s-w);w=s;k?(f=s+q+c>v+l,r&&!f&&(r=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom")),s<y&&(k=!1,c=n,"left"!==t&&"right"!==t||a.insertAfter(g),g.detach(),b={position:"",width:"",top:""},a.css(b).removeClass(p).trigger("sticky_kit:unstick")),u&&(b=m.height(),q>b&&!r&&(c-=h,c=Math.max(b-q,c),c=Math.min(n,c),k&&a.css({top:c+"px"})))):s>y&&(k=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?
    7    -1 a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(p).after(g),"left"!==t&&"right"!==t||g.append(a),a.trigger("sticky_kit:stick"));if(k&&(null==f&&(f=s+q+c>v+l),!r&&f))return r=!0,"static"===d.css("position")&&d.css({position:"relative"}),a.css({position:"absolute",bottom:e,top:"auto"}).trigger("sticky_kit:bottom")},x=function(){A();return h()},z=function(){m.off("scroll",h);b(document.body).off("sticky_kit:recalc",x);a.off("sticky_kit:detach",z);a.removeData("sticky_kit");a.css({position:"",bottom:"",
    8    -1 top:""});d.position("position","");if(k)return a.insertAfter(g).removeClass(p),g.remove()},m.on("touchmove",h),m.on("scroll",h),m.on("resize",x),b(document.body).on("sticky_kit:recalc",x),a.on("sticky_kit:detach",z),setTimeout(h,0)}};l=0;for(C=this.length;l<C;l++)e=this[l],B(b(e));return this}}).call(this);
   -1     4 (function(){var b,n;b=this.jQuery||window.jQuery;n=b(window);b.fn.stick_in_parent=function(d){var v,p,q,f,r,C,m,D;null==d&&(d={});r=d.sticky_class;v=d.inner_scrolling;f=d.parent;q=d.offset_top;p=d.spacer;null==q&&(q=0);null==f&&(f=void 0);null==v&&(v=!0);null==r&&(r="is_stuck");C=function(a,d,m,w,z,s,u){var t,A,l,x,c,e,B,y,g,h;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);e=a.parent();null!=f&&(e=e.closest(f));if(!e.length)throw"failed to find stick parent";t=l=!1;g=null!=p?a.closest(p):b("<div />");
   -1     5 g.css("position",a.css("position"));B=function(){var c,b,k;c=parseInt(e.css("border-top-width"),10);b=parseInt(e.css("padding-top"),10);d=parseInt(e.css("padding-bottom"),10);m=e.offset().top+c+b;w=e.height();l&&(t=l=!1,null==p&&(a.insertAfter(g),g.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(r),k=!0);z=a.offset().top-parseInt(a.css("margin-top"),10)-q;s=a.outerHeight(!0);u=a.css("float");g.css({width:a.outerWidth(!0),height:s,display:a.css("display"),"vertical-align":a.css("vertical-align"),
   -1     6 "float":u});if(k)return h()};B();if(s!==w)return x=void 0,c=q,h=function(){var b,h,k,f;k=n.scrollTop();null!=x&&(h=k-x);x=k;l?(f=k+s+c>w+m,t&&!f&&(t=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom")),k<z&&(l=!1,c=q,null==p&&("left"!==u&&"right"!==u||a.insertAfter(g),g.detach()),b={position:"",width:"",top:""},a.css(b).removeClass(r).trigger("sticky_kit:unstick")),v&&(b=n.height(),s>b&&!t&&(c-=h,c=Math.max(b-s,c),c=Math.min(q,c),l&&a.css({top:c+"px"})))):k>z&&(l=!0,b={position:"fixed",
   -1     7 top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(r),null==p&&(a.after(g),"left"!==u&&"right"!==u||g.append(a)),a.trigger("sticky_kit:stick"));if(l&&(null==f&&(f=k+s+c>w+m),!t&&f))return t=!0,"static"===e.css("position")&&e.css({position:"relative"}),a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){B();return h()},A=function(){n.off("scroll",h);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",
   -1     8 A);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:""});e.position("position","");if(l)return null==p&&(a.insertAfter(g),g.remove()),a.removeClass(r)},n.on("touchmove",h),n.on("scroll",h),n.on("resize",y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",A),setTimeout(h,0)}};m=0;for(D=this.length;m<D;m++)d=this[m],C(b(d));return this}}).call(this);

diff --git a/test/index.html b/test/index.html

@@ -8,6 +8,11 @@
    8     8       border: 1px solid red;
    9     9     }
   10    10 
   -1    11     .manual_spacer {
   -1    12       background: red;
   -1    13       padding: 10px;
   -1    14     }
   -1    15 
   11    16     .item, .static {
   12    17       border: 1px solid blue;
   13    18       min-width: 200px;
@@ -167,8 +172,8 @@
  167   172 
  168   173 <h1>Custom Spacer</h1>
  169   174 <div class="container one">
  170    -1   <div class="item block">
  171    -1     <iframe src="http://leafo.net" frameborder="0"></iframe>
   -1   175   <div class="manual_spacer">
   -1   176     <div class="item block use_manual"></div>
  172   177   </div>
  173   178   <div class="full static" style="margin: 10px auto; width: 400px;"></div>
  174   179 </div>
@@ -193,7 +198,13 @@
  193   198       });
  194   199     }
  195   200 
  196    -1     $(".container .item").stick_in_parent();
   -1   201     $(".container .item:not(.use_manual)").stick_in_parent();
   -1   202 
   -1   203     $(".container .item.use_manual").stick_in_parent({
   -1   204       parent: ".container",
   -1   205       spacer: ".manual_spacer"
   -1   206     });
   -1   207 
  197   208     $("#events_container").on("sticky_kit:stick", function(e) {
  198   209       $(e.target).html("got stick event");
  199   210     });