touch_handler.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. class TouchHandler {
  2. constructor() {
  3. this.reset();
  4. }
  5. reset() {
  6. this.touch = {
  7. start: { x: -1, y: -1 },
  8. move: { x: -1, y: -1 },
  9. moved: false,
  10. time: 0,
  11. element: null
  12. };
  13. }
  14. calculateDistance() {
  15. if (this.touch.start.x >= -1 && this.touch.move.x >= -1) {
  16. const horizontalDistance = Math.abs(this.touch.move.x - this.touch.start.x);
  17. const verticalDistance = Math.abs(this.touch.move.y - this.touch.start.y);
  18. if (horizontalDistance > 30 && verticalDistance < 70 || this.touch.moved) {
  19. return this.touch.move.x - this.touch.start.x;
  20. }
  21. }
  22. return 0;
  23. }
  24. static findElement(element) {
  25. if (element.classList.contains("entry-swipe")) {
  26. return element;
  27. }
  28. return element.closest(".entry-swipe");
  29. }
  30. onItemTouchStart(event) {
  31. if (event.touches === undefined || event.touches.length !== 1) {
  32. return;
  33. }
  34. this.reset();
  35. this.touch.start.x = event.touches[0].clientX;
  36. this.touch.start.y = event.touches[0].clientY;
  37. this.touch.element = TouchHandler.findElement(event.touches[0].target);
  38. this.touch.element.style.transitionDuration = "0s";
  39. }
  40. onItemTouchMove(event) {
  41. if (event.touches === undefined || event.touches.length !== 1 || this.touch.element === null) {
  42. return;
  43. }
  44. this.touch.move.x = event.touches[0].clientX;
  45. this.touch.move.y = event.touches[0].clientY;
  46. const distance = this.calculateDistance();
  47. const absDistance = Math.abs(distance);
  48. if (absDistance > 0) {
  49. this.touch.moved = true;
  50. const tx = (absDistance > 75 ? Math.sqrt(absDistance - 75) + 75 : absDistance) * Math.sign(distance);
  51. this.touch.element.style.transform = "translateX(" + tx + "px)";
  52. event.preventDefault();
  53. }
  54. }
  55. onItemTouchEnd(event) {
  56. if (event.touches === undefined) {
  57. return;
  58. }
  59. if (this.touch.element !== null) {
  60. if (Math.abs(this.calculateDistance()) > 75) {
  61. toggleEntryStatus(this.touch.element);
  62. }
  63. if (this.touch.moved) {
  64. this.touch.element.style.transitionDuration = "0.15s";
  65. this.touch.element.style.transform = "none";
  66. }
  67. }
  68. this.reset();
  69. }
  70. onContentTouchStart(event) {
  71. if (event.touches === undefined || event.touches.length !== 1) {
  72. return;
  73. }
  74. this.reset();
  75. this.touch.start.x = event.touches[0].clientX;
  76. this.touch.start.y = event.touches[0].clientY;
  77. this.touch.time = Date.now();
  78. }
  79. onContentTouchMove(event) {
  80. if (event.touches === undefined || event.touches.length !== 1 || this.element === null) {
  81. return;
  82. }
  83. this.touch.move.x = event.touches[0].clientX;
  84. this.touch.move.y = event.touches[0].clientY;
  85. }
  86. onContentTouchEnd(event) {
  87. if (event.touches === undefined) {
  88. return;
  89. }
  90. if (Date.now() - this.touch.time <= 1000) {
  91. const distance = this.calculateDistance();
  92. const absDistance = Math.abs(distance);
  93. if (absDistance > 75) {
  94. if (distance > 0) {
  95. goToPage("previous");
  96. } else {
  97. goToPage("next");
  98. }
  99. }
  100. }
  101. this.reset();
  102. }
  103. onTapEnd(event) {
  104. if (event.touches === undefined) {
  105. return;
  106. }
  107. const now = Date.now();
  108. if (this.touch.start.x !== -1 && now - this.touch.time <= 200) {
  109. const innerWidthHalf = window.innerWidth / 2;
  110. if (this.touch.start.x >= innerWidthHalf && event.changedTouches[0].clientX >= innerWidthHalf) {
  111. goToPage("next");
  112. } else if (this.touch.start.x < innerWidthHalf && event.changedTouches[0].clientX < innerWidthHalf) {
  113. goToPage("previous");
  114. }
  115. this.reset();
  116. } else {
  117. this.reset();
  118. this.touch.start.x = event.changedTouches[0].clientX;
  119. this.touch.time = now;
  120. }
  121. }
  122. listen() {
  123. const eventListenerOptions = { passive: true };
  124. document.querySelectorAll(".entry-swipe").forEach((element) => {
  125. element.addEventListener("touchstart", (e) => this.onItemTouchStart(e), eventListenerOptions);
  126. element.addEventListener("touchmove", (e) => this.onItemTouchMove(e));
  127. element.addEventListener("touchend", (e) => this.onItemTouchEnd(e), eventListenerOptions);
  128. element.addEventListener("touchcancel", this.reset, eventListenerOptions);
  129. });
  130. const element = document.querySelector(".entry-content");
  131. if (element) {
  132. if (element.classList.contains("gesture-nav-tap")) {
  133. element.addEventListener("touchend", (e) => this.onTapEnd(e), eventListenerOptions);
  134. element.addEventListener("touchmove", this.reset, eventListenerOptions);
  135. element.addEventListener("touchcancel", this.reset, eventListenerOptions);
  136. } else if (element.classList.contains("gesture-nav-swipe")) {
  137. element.addEventListener("touchstart", (e) => this.onContentTouchStart(e), eventListenerOptions);
  138. element.addEventListener("touchmove", (e) => this.onContentTouchMove(e), eventListenerOptions);
  139. element.addEventListener("touchend", (e) => this.onContentTouchEnd(e), eventListenerOptions);
  140. element.addEventListener("touchcancel", this.reset, eventListenerOptions);
  141. }
  142. }
  143. }
  144. }