inobounce.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*! iNoBounce - v0.2.0
  2. * https://github.com/lazd/iNoBounce/
  3. * Copyright (c) 2013 Larry Davis <lazdnet@gmail.com>; Licensed BSD */
  4. (function(global) {
  5. // Stores the Y position where the touch started
  6. var startY = 0;
  7. // Store enabled status
  8. var enabled = false;
  9. var supportsPassiveOption = false;
  10. try {
  11. var opts = Object.defineProperty({}, 'passive', {
  12. get: function() {
  13. supportsPassiveOption = true;
  14. }
  15. });
  16. window.addEventListener('test', null, opts);
  17. } catch (e) {}
  18. var handleTouchmove = function(evt) {
  19. // Get the element that was scrolled upon
  20. var el = evt.target;
  21. // Allow zooming
  22. var zoom = window.innerWidth / window.document.documentElement.clientWidth;
  23. if (evt.touches.length > 1 || zoom !== 1) {
  24. return;
  25. }
  26. // Check all parent elements for scrollability
  27. while (el !== document.body && el !== document) {
  28. // Get some style properties
  29. var style = window.getComputedStyle(el);
  30. if (!style) {
  31. // If we've encountered an element we can't compute the style for, get out
  32. break;
  33. }
  34. // Ignore range input element
  35. if (el.nodeName === 'INPUT' && el.getAttribute('type') === 'range') {
  36. return;
  37. }
  38. var scrolling = style.getPropertyValue('-webkit-overflow-scrolling');
  39. var overflowY = style.getPropertyValue('overflow-y');
  40. var height = parseInt(style.getPropertyValue('height'), 10);
  41. // Determine if the element should scroll
  42. var isScrollable = scrolling === 'touch' && (overflowY === 'auto' || overflowY === 'scroll');
  43. var canScroll = el.scrollHeight > el.offsetHeight;
  44. if (isScrollable && canScroll) {
  45. // Get the current Y position of the touch
  46. var curY = evt.touches ? evt.touches[0].screenY : evt.screenY;
  47. // Determine if the user is trying to scroll past the top or bottom
  48. // In this case, the window will bounce, so we have to prevent scrolling completely
  49. var isAtTop = (startY <= curY && el.scrollTop === 0);
  50. var isAtBottom = (startY >= curY && el.scrollHeight - el.scrollTop === height);
  51. // Stop a bounce bug when at the bottom or top of the scrollable element
  52. if (isAtTop || isAtBottom) {
  53. evt.preventDefault();
  54. }
  55. // No need to continue up the DOM, we've done our job
  56. return;
  57. }
  58. // Test the next parent
  59. el = el.parentNode;
  60. }
  61. // Stop the bouncing -- no parents are scrollable
  62. evt.preventDefault();
  63. };
  64. var handleTouchstart = function(evt) {
  65. // Store the first Y position of the touch
  66. startY = evt.touches ? evt.touches[0].screenY : evt.screenY;
  67. };
  68. var enable = function() {
  69. // Listen to a couple key touch events
  70. window.addEventListener('touchstart', handleTouchstart, supportsPassiveOption ? { passive : false } : false);
  71. window.addEventListener('touchmove', handleTouchmove, supportsPassiveOption ? { passive : false } : false);
  72. enabled = true;
  73. };
  74. var disable = function() {
  75. // Stop listening
  76. window.removeEventListener('touchstart', handleTouchstart, false);
  77. window.removeEventListener('touchmove', handleTouchmove, false);
  78. enabled = false;
  79. };
  80. var isEnabled = function() {
  81. return enabled;
  82. };
  83. // Enable by default if the browser supports -webkit-overflow-scrolling
  84. // Test this by setting the property with JavaScript on an element that exists in the DOM
  85. // Then, see if the property is reflected in the computed style
  86. var testDiv = document.createElement('div');
  87. document.documentElement.appendChild(testDiv);
  88. testDiv.style.WebkitOverflowScrolling = 'touch';
  89. var scrollSupport = 'getComputedStyle' in window && window.getComputedStyle(testDiv)['-webkit-overflow-scrolling'] === 'touch';
  90. document.documentElement.removeChild(testDiv);
  91. if (scrollSupport) {
  92. enable();
  93. }
  94. // A module to support enabling/disabling iNoBounce
  95. var iNoBounce = {
  96. enable: enable,
  97. disable: disable,
  98. isEnabled: isEnabled
  99. };
  100. if (typeof module !== 'undefined' && module.exports) {
  101. // Node.js Support
  102. module.exports = iNoBounce;
  103. }
  104. if (typeof global.define === 'function') {
  105. // AMD Support
  106. (function(define) {
  107. define('iNoBounce', [], function() { return iNoBounce; });
  108. }(global.define));
  109. }
  110. else {
  111. // Browser support
  112. global.iNoBounce = iNoBounce;
  113. }
  114. }(this));