PageSourceSearch

https://veefriends.com/_content/VeeFriends.Web.Www/Pages/HomeSections/NewsSection.vumv47vpmo.razor.js

js veefriends.com collected 2026-09-25 14:34:24 UTC 3,706 bytes, 135 lines download raw bytes

1/**
2 * News marquee: keep BlazorFastMarquee EnableDrag for sideways scrubbing,
3 * and open card links on tap (movement under threshold) via a sync window.open
4 * so popup blockers don't fire (Blazor @onclick / JS interop would).
5 */
6export function Component(dotnetContext, itemRef) {
7  const DRAG_THRESHOLD_PX = 8;
8
9  let startX = 0;
10  let startY = 0;
11  let startHref = null;
12  let hasMoved = false;
13  let openedOnPointerUp = false;
14  // Survives until the synthetic click after pointerup — hasMoved is cleared earlier.
15  let suppressNextClick = false;
16
17  const findNewsLink = (eventTarget, clientX, clientY) => {
18    const fromTarget =
19      eventTarget instanceof Element
20        ? eventTarget.closest("a[data-news-link]")
21        : null;
22    if (fromTarget) {
23      return fromTarget;
24    }
25
26    const under = document.elementFromPoint(clientX, clientY);
27    return under instanceof Element ? under.closest("a[data-news-link]") : null;
28  };
29
30  const onPointerDown = (e) => {
31    if (e.pointerType === "mouse" && e.button !== 0) {
32      return;
33    }
34
35    const link = findNewsLink(e.target, e.clientX, e.clientY);
36    if (!link) {
37      startHref = null;
38      return;
39    }
40
41    startHref = link.href;
42    startX = e.clientX;
43    startY = e.clientY;
44    hasMoved = false;
45    openedOnPointerUp = false;
46    suppressNextClick = false;
47  };
48
49  const onPointerMove = (e) => {
50    if (!startHref || hasMoved) {
51      return;
52    }
53
54    const dx = Math.abs(e.clientX - startX);
55    const dy = Math.abs(e.clientY - startY);
56    if (dx > DRAG_THRESHOLD_PX || dy > DRAG_THRESHOLD_PX) {
57      hasMoved = true;
58    }
59  };
60
61  const onPointerUp = (e) => {
62    if (!startHref) {
63      return;
64    }
65
66    const href = startHref;
67    const dragged = hasMoved;
68    startHref = null;
69    hasMoved = false;
70
71    if (dragged) {
72      // Click fires after pointerup with hasMoved already cleared — block it.
73      suppressNextClick = true;
74      return;
75    }
76
77    if (!href) {
78      return;
79    }
80
81    openedOnPointerUp = true;
82    window.open(href, "_blank", "noopener,noreferrer");
83  };
84
85  const onPointerCancel = () => {
86    startHref = null;
87    hasMoved = false;
88    openedOnPointerUp = false;
89    suppressNextClick = false;
90  };
91
92  // Prevent native <a> navigation (and double-open) after we handled tap on pointerup,
93  // or after a drag scrub. Marquee may also suppress click; this is belt-and-suspenders.
94  const onClick = (e) => {
95    const link = findNewsLink(e.target, e.clientX, e.clientY);
96    if (!link) {
97      openedOnPointerUp = false;
98      suppressNextClick = false;
99      return;
100    }
101
102    e.preventDefault();
103    e.stopPropagation();
104
105    if (openedOnPointerUp || suppressNextClick) {
106      openedOnPointerUp = false;
107      suppressNextClick = false;
108      return;
109    }
110
111    // Keyboard / fallback activation when pointerup path didn't run
112    if (link.href) {
113      window.open(link.href, "_blank", "noopener,noreferrer");
114    }
115
116    openedOnPointerUp = false;
117    suppressNextClick = false;
118  };
119
120  itemRef.addEventListener("pointerdown", onPointerDown, true);
121  itemRef.addEventListener("pointermove", onPointerMove, true);
122  itemRef.addEventListener("pointerup", onPointerUp, true);
123  itemRef.addEventListener("pointercancel", onPointerCancel, true);
124  itemRef.addEventListener("click", onClick, true);
125
126  return {
127    dispose() {
128      itemRef.removeEventListener("pointerdown", onPointerDown, true);
129      itemRef.removeEventListener("pointermove", onPointerMove, true);
130      itemRef.removeEventListener("pointerup", onPointerUp, true);
131      itemRef.removeEventListener("pointercancel", onPointerCancel, true);
132      itemRef.removeEventListener("click", onClick, true);
133    },
134  };
135}

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.