jquery.inview.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /**
  2. * author Christopher Blum
  3. * - based on the idea of Remy Sharp, http://remysharp.com/2009/01/26/element-in-view-event-plugin/
  4. * - forked from http://github.com/zuk/jquery.inview/
  5. */
  6. (function ($) {
  7. var inviewObjects = {}, viewportSize, viewportOffset,
  8. d = document, w = window, documentElement = d.documentElement, expando = $.expando, isFiring = false, $elements = {};
  9. $.event.special.inview = {
  10. add: function(data) {
  11. var inviewObject = { data: data, $element: $(this) }
  12. inviewObjects[data.guid + "-" + this[expando]] = inviewObject;
  13. var selector = inviewObject.data.selector,
  14. $element = inviewObject.$element;
  15. var hash = parseInt(getHash( data.guid + this[expando]));
  16. $elements[hash] = selector ? $element.find(selector) : $element;
  17. },
  18. remove: function(data) {
  19. try { delete inviewObjects[data.guid + "-" + this[expando]]; } catch(e) {}
  20. try {
  21. var hash = parseInt(getHash(data.guid + this[expando]));
  22. delete($elements[hash]);
  23. } catch (e){}
  24. }
  25. };
  26. function getHash(str){
  27. str = str+'';
  28. var hash = 0;
  29. if (str.length == 0) return hash;
  30. for (i = 0; i < str.length; i++) {
  31. char = str.charCodeAt(i);
  32. hash = ((hash<<5)-hash)+char;
  33. hash = hash & hash; // Convert to 32bit integer
  34. }
  35. return Math.abs(hash);
  36. }
  37. function getViewportSize() {
  38. var mode, domObject, size = { height: w.innerHeight, width: w.innerWidth };
  39. // if this is correct then return it. iPad has compat Mode, so will
  40. // go into check clientHeight/clientWidth (which has the wrong value).
  41. if (!size.height) {
  42. mode = d.compatMode;
  43. if (mode || !$.support.boxModel) { // IE, Gecko
  44. domObject = mode === 'CSS1Compat' ?
  45. documentElement : // Standards
  46. d.body; // Quirks
  47. size = {
  48. height: domObject.clientHeight,
  49. width: domObject.clientWidth
  50. };
  51. }
  52. }
  53. return size;
  54. }
  55. function getViewportOffset() {
  56. return {
  57. top: w.pageYOffset || documentElement.scrollTop || (d.body?d.body.scrollTop:0),
  58. left: w.pageXOffset || documentElement.scrollLeft || (d.body?d.body.scrollLeft:0)
  59. };
  60. }
  61. function checkInView() {
  62. if (isFiring){
  63. return;
  64. }
  65. isFiring = true;
  66. viewportSize = viewportSize || getViewportSize();
  67. viewportOffset = viewportOffset || getViewportOffset();
  68. for (var i in $elements) {
  69. if (isNaN(parseInt(i))) {
  70. continue;
  71. }
  72. var $element = $($elements[i]),
  73. elementSize = { height: $element.height(), width: $element.width() },
  74. elementOffset = $element.offset(),
  75. inView = $element.data('inview'),
  76. visiblePartX,
  77. visiblePartY,
  78. visiblePartsMerged;
  79. // Don't ask me why because I haven't figured out yet:
  80. // viewportOffset and viewportSize are sometimes suddenly null in Firefox 5.
  81. // Even though it sounds weird:
  82. // It seems that the execution of this function is interferred by the onresize/onscroll event
  83. // where viewportOffset and viewportSize are unset
  84. if (!viewportOffset || !viewportSize) {
  85. isFiring = false;
  86. return;
  87. }
  88. if (elementOffset.top + elementSize.height > viewportOffset.top &&
  89. elementOffset.top < viewportOffset.top + viewportSize.height &&
  90. elementOffset.left + elementSize.width > viewportOffset.left &&
  91. elementOffset.left < viewportOffset.left + viewportSize.width) {
  92. visiblePartX = (viewportOffset.left > elementOffset.left ?
  93. 'right' : (viewportOffset.left + viewportSize.width) < (elementOffset.left + elementSize.width) ?
  94. 'left' : 'both');
  95. visiblePartY = (viewportOffset.top > elementOffset.top ?
  96. 'bottom' : (viewportOffset.top + viewportSize.height) < (elementOffset.top + elementSize.height) ?
  97. 'top' : 'both');
  98. visiblePartsMerged = visiblePartX + "-" + visiblePartY;
  99. if (!inView || inView !== visiblePartsMerged) {
  100. $element.data('inview', visiblePartsMerged).trigger('inview', [true, visiblePartX, visiblePartY]);
  101. }
  102. } else if (inView) {
  103. $element.data('inview', false).trigger('inview', [false]);
  104. }
  105. }
  106. isFiring = false;
  107. }
  108. $(w).bind("scroll resize", function() {
  109. viewportSize = viewportOffset = null;
  110. });
  111. // Use setInterval in order to also make sure this captures elements within
  112. // "overflow:scroll" elements or elements that appeared in the dom tree due to
  113. // dom manipulation and reflow
  114. // old: $(window).scroll(checkInView);
  115. //
  116. // By the way, iOS (iPad, iPhone, ...) seems to not execute, or at least delays
  117. // intervals while the user scrolls. Therefore the inview event might fire a bit late there
  118. setInterval(checkInView, 250);
  119. })(jQuery);