theme/boost/amd/src/bootstrap/util/swipe.js

  1. /**
  2. * --------------------------------------------------------------------------
  3. * Bootstrap util/swipe.js
  4. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  5. * --------------------------------------------------------------------------
  6. */
  7. import EventHandler from '../dom/event-handler'
  8. import Config from './config'
  9. import { execute } from './index'
  10. /**
  11. * Constants
  12. */
  13. const NAME = 'swipe'
  14. const EVENT_KEY = '.bs.swipe'
  15. const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`
  16. const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`
  17. const EVENT_TOUCHEND = `touchend${EVENT_KEY}`
  18. const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`
  19. const EVENT_POINTERUP = `pointerup${EVENT_KEY}`
  20. const POINTER_TYPE_TOUCH = 'touch'
  21. const POINTER_TYPE_PEN = 'pen'
  22. const CLASS_NAME_POINTER_EVENT = 'pointer-event'
  23. const SWIPE_THRESHOLD = 40
  24. const Default = {
  25. endCallback: null,
  26. leftCallback: null,
  27. rightCallback: null
  28. }
  29. const DefaultType = {
  30. endCallback: '(function|null)',
  31. leftCallback: '(function|null)',
  32. rightCallback: '(function|null)'
  33. }
  34. /**
  35. * Class definition
  36. */
  37. class Swipe extends Config {
  38. constructor(element, config) {
  39. super()
  40. this._element = element
  41. if (!element || !Swipe.isSupported()) {
  42. return
  43. }
  44. this._config = this._getConfig(config)
  45. this._deltaX = 0
  46. this._supportPointerEvents = Boolean(window.PointerEvent)
  47. this._initEvents()
  48. }
  49. // Getters
  50. static get Default() {
  51. return Default
  52. }
  53. static get DefaultType() {
  54. return DefaultType
  55. }
  56. static get NAME() {
  57. return NAME
  58. }
  59. // Public
  60. dispose() {
  61. EventHandler.off(this._element, EVENT_KEY)
  62. }
  63. // Private
  64. _start(event) {
  65. if (!this._supportPointerEvents) {
  66. this._deltaX = event.touches[0].clientX
  67. return
  68. }
  69. if (this._eventIsPointerPenTouch(event)) {
  70. this._deltaX = event.clientX
  71. }
  72. }
  73. _end(event) {
  74. if (this._eventIsPointerPenTouch(event)) {
  75. this._deltaX = event.clientX - this._deltaX
  76. }
  77. this._handleSwipe()
  78. execute(this._config.endCallback)
  79. }
  80. _move(event) {
  81. this._deltaX = event.touches && event.touches.length > 1 ?
  82. 0 :
  83. event.touches[0].clientX - this._deltaX
  84. }
  85. _handleSwipe() {
  86. const absDeltaX = Math.abs(this._deltaX)
  87. if (absDeltaX <= SWIPE_THRESHOLD) {
  88. return
  89. }
  90. const direction = absDeltaX / this._deltaX
  91. this._deltaX = 0
  92. if (!direction) {
  93. return
  94. }
  95. execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)
  96. }
  97. _initEvents() {
  98. if (this._supportPointerEvents) {
  99. EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))
  100. EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))
  101. this._element.classList.add(CLASS_NAME_POINTER_EVENT)
  102. } else {
  103. EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))
  104. EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))
  105. EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))
  106. }
  107. }
  108. _eventIsPointerPenTouch(event) {
  109. return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)
  110. }
  111. // Static
  112. static isSupported() {
  113. return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
  114. }
  115. }
  116. export default Swipe