- commit
- 1279d6917f019d7e1584bda0e3aa9ddd1e020f67
- parent
- b76110db73cefb81107daa954efe41725f9d97e8
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2014-12-29 20:36
rewrite
Diffstat
| M | jquery.sticky-kit.coffee | 268 | ++++++++++++++++++++++--------------------------------------- |
1 files changed, 97 insertions, 171 deletions
diff --git a/jquery.sticky-kit.coffee b/jquery.sticky-kit.coffee
@@ -5,205 +5,133 @@ 5 5 $ = @jQuery or window.jQuery 6 6 7 7 win = $ window -1 8 -1 9 # get top offset relative to any other element -1 10 # -1 11 # this function has the the following properties: -1 12 # -1 13 # - top(a, b) == -top(b, a) -1 14 # - top(a, b) + top(a, c) == top(a, c) -1 15 top = (element, context) -> -1 16 if context == document -1 17 if element == document -1 18 return 0 -1 19 else if element == win -1 20 return win.scrollTop() -1 21 else -1 22 return element.offset().top -1 23 else -1 24 return top(element, document) - top(context, document) -1 25 -1 26 8 27 $.fn.stick_in_parent = (opts={}) -> 9 28 { 10 29 sticky_class11 -1 inner_scrolling12 -1 recalc_every13 30 parent: parent_selector -1 31 scrollable: scrollable_selector 14 32 offset_top15 -1 spacer: manual_spacer16 33 bottoming: enable_bottoming 17 34 } = opts 18 35 19 36 offset_top ?= 0 20 37 parent_selector ?= undefined21 -1 inner_scrolling ?= true22 38 sticky_class ?= "is_stuck" 23 39 24 40 enable_bottoming = true unless enable_bottoming? 25 41 26 42 for elm in @27 -1 ((elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) ->-1 43 ((elm, detached, fixed, bottomed) -> 28 44 return if elm.data "sticky_kit" 29 45 elm.data "sticky_kit", true 30 46 -1 47 scrollable = win -1 48 scrollable = elm.parent().closest(scrollable_selector) if scrollable_selector? -1 49 throw "failed to find stick scrollable" unless scrollable.length -1 50 31 51 parent = elm.parent() 32 52 parent = parent.closest(parent_selector) if parent_selector? 33 53 throw "failed to find stick parent" unless parent.length 34 5435 -1 fixed = false36 -1 bottomed = false37 -1 spacer = if manual_spacer?38 -1 manual_spacer && elm.closest manual_spacer39 -1 else40 -1 $("<div />")-1 55 _top = 0 41 5642 -1 spacer.css('position', elm.css('position')) if spacer-1 57 elm.css("position", "relative") 43 5844 -1 recalc = ->-1 59 tick = -> 45 60 return if detached46 -1 border_top = parseInt parent.css("border-top-width"), 1047 -1 padding_top = parseInt parent.css("padding-top"), 1048 -1 padding_bottom = parseInt parent.css("padding-bottom"), 1049 -150 -1 parent_top = parent.offset().top + border_top + padding_top51 -1 parent_height = parent.height()52 -153 -1 if fixed54 -1 fixed = false55 -1 bottomed = false56 -157 -1 unless manual_spacer?58 -1 elm.insertAfter(spacer)59 -1 spacer.detach()60 -161 -1 elm.css({62 -1 position: ""63 -1 top: ""64 -1 width: ""65 -1 bottom: ""66 -1 }).removeClass(sticky_class)67 -168 -1 restore = true69 -170 -1 top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) or 0) - offset_top71 6172 -1 height = elm.outerHeight true-1 62 # | +--------------+ -1 63 # | | border | -1 64 # original | +--------------+ -1 65 # top | | padding | -1 66 # | +--------------+ -1 67 # | | | -1 68 # v | | -1 69 # | |+------------+| -1 70 # | || original || -1 71 # top | || element || -1 72 # maximum | |+------------+| -1 73 # | | | -1 74 # | | parent | -1 75 # | | | -1 76 # v | | -1 77 # |+------------+| -1 78 # || actual || -1 79 # || element || -1 80 # |+------------+| -1 81 # +--------------+ -1 82 # | padding | -1 83 # +--------------+ -1 84 # | border | -1 85 # +--------------+ -1 86 -1 87 fixed_old = fixed -1 88 bottomed_old = bottomed 73 8974 -1 el_float = elm.css "float"75 -1 spacer.css({76 -1 width: elm.outerWidth true77 -1 height: height78 -1 display: elm.css "display"79 -1 "vertical-align": elm.css "vertical-align"80 -1 "float": el_float81 -1 }) if spacer82 -183 -1 if restore84 -1 tick()85 -186 -1 recalc()87 -1 return if height == parent_height-1 90 padding_bottom = parseInt parent.css("padding-bottom"), 10 -1 91 border_bottom = parseInt parent.css("border-bottom-width"), 10 88 9289 -1 last_pos = undefined90 -1 offset = offset_top-1 93 margin_top = parseInt elm.css("margin-top"), 10 91 9492 -1 recalc_counter = recalc_every-1 95 original_top = top(elm, parent) - _top 93 9694 -1 tick = ->95 -1 return if detached96 -1 if recalc_counter?97 -1 recalc_counter -= 198 -1 if recalc_counter <= 099 -1 recalc_counter = recalc_every100 -1 recalc()-1 97 _top = top(scrollable, parent) + offset_top + margin_top - original_top -1 98 if enable_bottoming -1 99 old = _top -1 100 _top = Math.min(_top, parent.outerHeight() - original_top - elm.outerHeight(true) + margin_top - padding_bottom - border_bottom) -1 101 bottomed = _top != old -1 102 _top = Math.max(_top, 0) 101 103102 -1 scroll = win.scrollTop()103 -1 if last_pos?104 -1 delta = scroll - last_pos105 -1 last_pos = scroll-1 104 fixed = _top != 0 106 105 107 106 if fixed108 -1 if enable_bottoming109 -1 will_bottom = scroll + height + offset > parent_height + parent_top110 -1111 -1 # unbottom112 -1 if bottomed && !will_bottom113 -1 bottomed = false114 -1 elm.css({115 -1 position: "fixed"116 -1 bottom: ""117 -1 top: offset118 -1 }).trigger("sticky_kit:unbottom")119 -1120 -1 # unfixing121 -1 if scroll < top122 -1 fixed = false123 -1 offset = offset_top124 -1125 -1 unless manual_spacer?126 -1 if el_float == "left" || el_float == "right"127 -1 elm.insertAfter spacer128 -1129 -1 spacer.detach()130 -1131 -1 css = {132 -1 position: ""133 -1 width: ""134 -1 top: ""135 -1 }136 -1 elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick")137 -1138 -1 # updated offset139 -1 if inner_scrolling140 -1 win_height = win.height()141 -1 if height + offset_top > win_height # bigger than viewport142 -1 unless bottomed143 -1 offset -= delta144 -1 offset = Math.max win_height - height, offset145 -1 offset = Math.min offset_top, offset146 -1147 -1 if fixed148 -1 elm.css {149 -1 top: offset + "px"150 -1 }151 -1-1 107 elm.addClass(sticky_class) 152 108 else153 -1 # fixing154 -1 if scroll > top155 -1 fixed = true156 -1 css = {157 -1 position: "fixed"158 -1 top: offset159 -1 }160 -1161 -1 css.width = if elm.css("box-sizing") == "border-box"162 -1 elm.outerWidth() + "px"163 -1 else164 -1 elm.width() + "px"165 -1166 -1 elm.css(css).addClass(sticky_class)167 -1168 -1 unless manual_spacer?169 -1 elm.after(spacer)170 -1171 -1 if el_float == "left" || el_float == "right"172 -1 spacer.append elm173 -1174 -1 elm.trigger("sticky_kit:stick")175 -1176 -1 # this is down here because we can fix and bottom in same step when177 -1 # scrolling huge178 -1 if fixed && enable_bottoming179 -1 will_bottom ?= scroll + height + offset > parent_height + parent_top180 -1181 -1 # bottomed182 -1 if !bottomed && will_bottom183 -1 # bottomed out184 -1 bottomed = true185 -1 if parent.css("position") == "static"186 -1 parent.css {187 -1 position: "relative"188 -1 }189 -1190 -1 elm.css({191 -1 position: "absolute"192 -1 bottom: padding_bottom193 -1 top: "auto"194 -1 }).trigger("sticky_kit:bottom")195 -1196 -1 recalc_and_tick = ->197 -1 recalc()198 -1 tick()-1 109 elm.removeClass(sticky_class) -1 110 -1 111 elm.css("top", _top) -1 112 -1 113 # trigger events -1 114 if !fixed && fixed_old -1 115 elm.trigger("sticky_kit:unstick") -1 116 if !bottomed && bottomed_old -1 117 elm.trigger("sticky_kit:unbottom") -1 118 if fixed && !fixed_old -1 119 elm.trigger("sticky_kit:stick") -1 120 else if bottomed && !bottomed_old -1 121 elm.trigger("sticky_kit:bottom") 199 122 200 123 detach = -> 201 124 detached = true 202 125 win.off "touchmove", tick 203 126 win.off "scroll", tick204 -1 win.off "resize", recalc_and_tick205 -1206 -1 $(document.body).off "sticky_kit:recalc", recalc_and_tick-1 127 win.off "resize", tick -1 128 if scrollable_selector -1 129 scrollable.off "touchmove", tick -1 130 scrollable.off "scroll", tick -1 131 elm.parentsUntil(scrollable).off "touchmove", tick -1 132 elm.parentsUntil(scrollable).off "scroll", tick -1 133 -1 134 $(document.body).off "sticky_kit:recalc", tick 207 135 elm.off "sticky_kit:detach", detach 208 136 elm.removeData "sticky_kit" 209 137 @@ -211,28 +139,26 @@ $.fn.stick_in_parent = (opts={}) -> 211 139 position: "" 212 140 bottom: "" 213 141 top: ""214 -1 width: ""215 142 } 216 143217 -1 parent.position "position", ""-1 144 parent.css "position", "" 218 145 219 146 if fixed220 -1 unless manual_spacer?221 -1 if el_float == "left" || el_float == "right"222 -1 elm.insertAfter spacer223 -1 spacer.remove()224 -1225 147 elm.removeClass sticky_class 226 148 -1 149 parent.css "position", "relative" 227 150 win.on "touchmove", tick 228 151 win.on "scroll", tick229 -1 win.on "resize", recalc_and_tick230 -1 $(document.body).on "sticky_kit:recalc", recalc_and_tick-1 152 win.on "resize", tick -1 153 if scrollable_selector -1 154 scrollable.on "touchmove", tick -1 155 scrollable.on "scroll", tick -1 156 elm.parentsUntil(scrollable).on "touchmove", tick -1 157 elm.parentsUntil(scrollable).on "scroll", tick -1 158 $(document.body).on "sticky_kit:recalc", tick 231 159 elm.on "sticky_kit:detach", detach 232 160 233 161 setTimeout tick, 0 234 162 235 163 ) $ elm 236 164 @237 -1238 -1