jquery.pin.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. (function ($) {
  2. "use strict";
  3. $.fn.pin = function (options) {
  4. var scrollY = 0, elements = [], disabled = false, $window = $(window);
  5. options = options || {};
  6. var recalculateLimits = function () {
  7. for (var i=0, len=elements.length; i<len; i++) {
  8. var $this = elements[i];
  9. if (options.minWidth && $window.width() <= options.minWidth) {
  10. if ($this.parent().is(".pin-wrapper")) { $this.unwrap(); }
  11. $this.css({width: "", left: "", top: "", position: ""});
  12. if (options.activeClass) { $this.removeClass(options.activeClass); }
  13. disabled = true;
  14. continue;
  15. } else {
  16. disabled = false;
  17. }
  18. var $container = options.containerSelector ? $this.closest(options.containerSelector) : $(document.body);
  19. var offset = $this.offset();
  20. var containerOffset = $container.offset();
  21. var parentOffset = $this.offsetParent().offset();
  22. if (!$this.parent().is(".pin-wrapper")) {
  23. $this.wrap("<div class='pin-wrapper'>");
  24. }
  25. var pad = $.extend({
  26. top: 0,
  27. bottom: 0
  28. }, options.padding || {});
  29. $this.data("pin", {
  30. pad: pad,
  31. from: (options.containerSelector ? containerOffset.top : offset.top) - pad.top,
  32. to: containerOffset.top + $container.height() - $this.outerHeight() - pad.bottom,
  33. end: containerOffset.top + $container.height(),
  34. parentTop: parentOffset.top
  35. });
  36. $this.css({width: $this.outerWidth()});
  37. $this.parent().css("height", $this.outerHeight());
  38. }
  39. };
  40. var onScroll = function () {
  41. if (disabled) { return; }
  42. scrollY = $window.scrollTop();
  43. var elmts = [];
  44. for (var i=0, len=elements.length; i<len; i++) {
  45. var $this = $(elements[i]),
  46. data = $this.data("pin");
  47. if (!data) { // Removed element
  48. continue;
  49. }
  50. elmts.push($this);
  51. var from = data.from - data.pad.bottom,
  52. to = data.to - data.pad.top;
  53. if (from + $this.outerHeight() > data.end) {
  54. $this.css('position', '');
  55. continue;
  56. }
  57. if (from < scrollY && to > scrollY) {
  58. !($this.css("position") == "fixed") && $this.css({
  59. left: $this.offset().left,
  60. top: data.pad.top
  61. }).css("position", "fixed");
  62. if (options.activeClass) { $this.addClass(options.activeClass); }
  63. } else if (scrollY >= to) {
  64. $this.css({
  65. left: "",
  66. top: to - data.parentTop + data.pad.top
  67. }).css("position", "absolute");
  68. if (options.activeClass) { $this.addClass(options.activeClass); }
  69. } else {
  70. $this.css({position: "", top: "", left: ""});
  71. if (options.activeClass) { $this.removeClass(options.activeClass); }
  72. }
  73. }
  74. elements = elmts;
  75. };
  76. var update = function () { recalculateLimits(); onScroll(); };
  77. this.each(function () {
  78. var $this = $(this),
  79. data = $(this).data('pin') || {};
  80. if (data && data.update) { return; }
  81. elements.push($this);
  82. $("img", this).one("load", recalculateLimits);
  83. data.update = update;
  84. $(this).data('pin', data);
  85. });
  86. $window.scroll(onScroll);
  87. $window.resize(function () { recalculateLimits(); });
  88. recalculateLimits();
  89. $window.load(update);
  90. return this;
  91. };
  92. })(jQuery);