PageSourceSearch

https://ambivation.com/wp-content/themes/Konekto-theme/js/scroll-helper.js?ver=7.1

js ambivation.com collected 2026-09-29 22:35:30 UTC 6,955 bytes, 260 lines download raw bytes

1//minimum pixel threshhold before considering the gesture dragging
2const DX = 5;
3let isDragging = false;
4let isMouseDown = false;
5let currentDraggedElement = null;
6let scrollMultiplier = 1;
7let startX, scrollLeft;
8let lastX, lastTime, velocity;
9let isCarousel = false;
10let carouselInitialPage = 0;
11let target = null;
12let pointerId = null;
13
14const onPointerDown = (e) => {
15  currentDraggedElement = e.currentTarget;
16  target = e.target;
17
18  isCarousel = currentDraggedElement.getAttribute("carousel") !== null;
19  if (isCarousel) {
20    carouselInitialPage = Math.round(
21      currentDraggedElement.scrollLeft / getCarouselStride(currentDraggedElement)
22    );
23  }
24
25  const scrollMultiplierValue = Number.parseFloat(
26    currentDraggedElement.getAttribute("scroll-multiplier")
27  );
28  scrollMultiplier = scrollMultiplierValue || 1;
29
30  startX = e.pageX - currentDraggedElement.offsetLeft;
31  scrollLeft = currentDraggedElement.scrollLeft;
32
33  currentDraggedElement.onpointermove = move;
34  currentDraggedElement.setPointerCapture(e.pointerId);
35  pointerId = e.pointerId;
36
37  lastX = e.clientX;
38  lastTime = Date.now();
39  isMouseDown = true;
40};
41
42const onMouseUp = (e) => {
43  if (!currentDraggedElement) {
44    return;
45  }
46
47  if (!isDragging) {
48    target?.dispatchEvent(new PointerEvent("click", e));
49    reset();
50    return;
51  }
52
53  currentDraggedElement.classList.remove("isDragging");
54
55  if (!isCarousel) {
56    applyMomentumScroll(currentDraggedElement, velocity);
57    reset();
58    return;
59  }
60  const page = Math.round(
61    currentDraggedElement.scrollLeft / getCarouselStride(currentDraggedElement)
62  );
63
64  const reachedXThreshhold = page !== carouselInitialPage;
65  const reachedVThreshhold = Math.abs(velocity) > 0.12;
66  if (reachedXThreshhold) {
67    scrollToCarouselPage(currentDraggedElement, () => page);
68  } else if (reachedVThreshhold) {
69    const delta = velocity < 0 ? 1 : -1;
70    scrollToCarouselPage(currentDraggedElement, () => page + delta);
71  } else {
72    scrollToCarouselPage(currentDraggedElement, () => carouselInitialPage);
73  }
74
75  reset();
76};
77
78const friction = 0.95;
79const minVelocity = 2;
80function applyMomentumScroll(container, initialVelocity) {
81  let velocity = initialVelocity * 20;
82  function step(cont) {
83    if (Math.abs(velocity) > minVelocity) {
84      requestAnimationFrame(() => {
85        step(cont);
86        container.scrollTo({
87          left: cont.scrollLeft - velocity,
88          behavior: "instant",
89        });
90        velocity *= friction;
91      });
92    }
93  }
94
95  requestAnimationFrame(() => step(container));
96}
97
98function reset() {
99  currentDraggedElement.onpointermove = null;
100  currentDraggedElement.releasePointerCapture(pointerId);
101  isMouseDown = false;
102  currentDragId = null;
103  currentDraggedElement = null;
104  carouselInitialPage = 0;
105  target = null;
106  pointerId = null;
107}
108
109function onClick(e) {
110  if (isDragging) {
111    e.preventDefault();
112    e.stopImmediatePropagation();
113  }
114  isDragging = false;
115}
116
117const move = (e) => {
118  if (!isMouseDown) {
119    return;
120  }
121
122  if (!isDragging) {
123    isDragging = Math.abs(startX - e.clientX) > DX;
124  }
125
126  currentDraggedElement.classList.add("isDragging");
127
128  const x = e.pageX - currentDraggedElement.offsetLeft;
129  const scroll = x - startX;
130
131  const now = Date.now();
132  velocity = (e.clientX - lastX) / (now - lastTime);
133
134  lastX = e.clientX;
135  lastTime = now;
136
137  scrollable = currentDraggedElement;
138  requestAnimationFrame(() => {
139    scrollable.scroll({
140      left: scrollLeft - scroll * scrollMultiplier,
141      behavior: "instant",
142    });
143  });
144};
145
146document.addEventListener("DOMContentLoaded", () => {
147  const isPC = window.matchMedia("(pointer: fine)").matches;
148  document.querySelectorAll("[scroll-container]").forEach((container) => {
149    if (container.hasAttribute("init") && container.scrollLeft !== 0) {
150      container.scrollTo({
151        left: 0,
152        behavior: "instant",
153      });
154    }
155
156    if (container.hasAttribute("carousel")) {
157      initialiazeCarousel(container);
158    }
159
160    if (isPC) {
161      container.addEventListener("pointerdown", onPointerDown);
162      container.addEventListener("click", onClick);
163    } else {
164      container.addEventListener("scroll", updateIndicatorOnPointerScroll);
165    }
166  });
167
168  if (isPC) {
169    document.addEventListener("mouseup", onMouseUp);
170  }
171});
172
173//distance between the left edges of two neighbouring cards (card 
173width + gap)
174function getCarouselStride(container) {
175  const items = container.querySelectorAll("[scrollable]");
176  if (items.length > 1) {
177    return (
178      items[1].getBoundingClientRect().left -
179      items[0].getBoundingClientRect().left
180    );
181  }
182  return container.getBoundingClientRect().width;
183}
184
185function scrollToCarouselPage(scrollContainer, getPage = () => 0) {
186  const indicatorContainer = scrollContainer.parentElement.querySelector(
187    "[carousel-indicator-container]"
188  );
189  const stride = getCarouselStride(scrollContainer);
190
191  const currentPage = Math.round(scrollContainer.scrollLeft / stride);
192  const pageCount = Math.round(scrollContainer.scrollWidth / stride);
193  const nextPage = getPage(currentPage);
194  if (nextPage < 0 || nextPage >= pageCount) {
195    return;
196  }
197
198  requestAnimationFrame(() => {
199    scrollContainer.scroll({
200      left: nextPage * stride,
201      behavior: "smooth",
202    });
203  });
204  setIndicatorState(indicatorContainer, nextPage);
205}
206
207function updateIndicatorOnPointerScroll(e) {
208  const container = e.currentTarget;
209  const indicatorContainer = container.parentElement.querySelector(
210    "[carousel-indicator-container]"
211  );
212  const stride = getCarouselStride(container);
213  const page = container.scrollLeft / stride;
214  const pageToReach = Math.round(container.scrollLeft / stride);
215  if (Math.abs(page - pageToReach) < 0.05) {
216    setIndicatorState(indicatorContainer, pageToReach);
217  }
218}
219
220function setIndicatorState(indicatorContainer, activePage) {
221  [...indicatorContainer.children].forEach((indicator, i) => {
222    if (activePage === i) {
223      indicator.classList.add("active");
224    } else {
225      indicator.classList.remove("active");
226    }
227  });
228}
229
230function initialiazeCarousel(container) {
231  const indicatorContainer = container.parentElement.querySelector(
232    "[carousel-indicator-container]"
233  );
234  const currentPage = Math.round(
235    container.scrollLeft / getCarouselStride(container)
236  );
237  indicatorContainer.children.item(currentPage).classList.add("active");
238
239  const prev = container.parentElement.querySelector("[carousel-prev]");
240  prev.onclick = () => {
241    scrollToCarouselPage(
242      container,
243      (getPage = (currentPage) => currentPage - 1)
244    );
245  };
246
247  const next = container.parentElement.querySelector("[carousel-next]");
248  next.onclick = () => {
249    scrollToCarouselPage(
250      container,
251      (getPage = (currentPage) => currentPage + 1)
252    );
253  };
254
255  [...indicatorContainer.children].forEach((indicator, i) => {
256    indicator.onclick = () => {
257      scrollToCarouselPage(container, (getPage = (currentPage) => i));
258    };
259  });
260}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.