aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-09 00:37:13 -0700
committerAdam Soltys <[email protected]>2026-10-09 00:37:13 -0700
commitff3bc36f3bc33974b453f114fe8f29ebc0615370 (patch)
tree794abebfe55f6543c3dd2259281ee7b68b73a2d9
parent62edcc721bf762cddad73ade54d8b580913051c7 (diff)
downloadcoinosv3-ff3bc36f3bc33974b453f114fe8f29ebc0615370.tar.gz
coinosv3-ff3bc36f3bc33974b453f114fe8f29ebc0615370.zip
Grab-and-flick no longer opens the post: a flick that starts a little sideways still scrolls (only a clearly sideways drag selects text), and any press that moved eats the click Chrome still fires. A wheel push at the very top of the page no longer dies on its first frame (a frame stamp older than the push read as a step up)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--src/app.js21
-rw-r--r--tools/feed-momentum-test.js17
2 files changed, 29 insertions, 9 deletions
diff --git a/src/app.js b/src/app.js
index 0b05913..537ba0d 100644
--- a/src/app.js
+++ b/src/app.js
@@ -6402,7 +6402,7 @@ if (INTENT_URI) {
let v = 0, acc = 0, raf = 0, last = 0;
const stop = () => { v = 0; acc = 0; if (raf) cancelAnimationFrame(raf); raf = 0; };
const tick = (now) => {
- const dt = Math.min(40, now - last); last = now;
+ const dt = Math.max(0, Math.min(40, now - last)); last = Math.max(last, now); // a frame stamp can predate the push
acc += v * dt;
const step = Math.trunc(acc);
if (step) {
@@ -6446,10 +6446,12 @@ if (INTENT_URI) {
document.addEventListener('pointermove', (e) => {
if (!drag) return;
if (!(e.buttons & 1)) { drag = null; return; }
+ if (drag.sel) return;
if (!drag.on) {
const dx = Math.abs(e.clientX - drag.x), dy = Math.abs(e.clientY - drag.y);
if (dx < 6 && dy < 6) return;
- if (dx > dy) { drag = null; return; } // sideways: selecting text
+ // clearly sideways: selecting text (and still not a click on the post)
+ if (dx > 2 * dy) { drag.sel = true; return; }
drag.on = true;
document.documentElement.classList.add('grab-scrolling');
try { getSelection().removeAllRanges(); } catch {}
@@ -6462,14 +6464,17 @@ if (INTENT_URI) {
const end = (e) => {
if (!drag) return;
const d = drag; drag = null;
- if (!d.on) return;
- document.documentElement.classList.remove('grab-scrolling');
- const p = d.pts, a = p[0], b = p[p.length - 1];
- // released while moving: throw it; held still first: just let go
- if (a && b && b[0] > a[0] && e.timeStamp - b[0] < 60) coast((a[1] - b[1]) / (b[0] - a[0]) * 1.2);
+ if (!d.on && !d.sel) return;
+ if (d.on) {
+ document.documentElement.classList.remove('grab-scrolling');
+ const p = d.pts, a = p[0], b = p[p.length - 1];
+ // released while moving: throw it; held still first: just let go
+ if (a && b && b[0] > a[0] && e.timeStamp - b[0] < 60) coast((a[1] - b[1]) / (b[0] - a[0]) * 1.2);
+ }
+ // the press moved: what it started on isn't opened (Chrome still clicks it)
const eat = (ev) => { ev.stopPropagation(); ev.preventDefault(); };
document.addEventListener('click', eat, { capture: true, once: true });
- setTimeout(() => document.removeEventListener('click', eat, { capture: true }), 0);
+ setTimeout(() => document.removeEventListener('click', eat, { capture: true }), 300);
};
document.addEventListener('pointerup', end);
document.addEventListener('pointercancel', () => { if (drag?.on) document.documentElement.classList.remove('grab-scrolling'); drag = null; });
diff --git a/tools/feed-momentum-test.js b/tools/feed-momentum-test.js
index 5b218d3..0ce2102 100644
--- a/tools/feed-momentum-test.js
+++ b/tools/feed-momentum-test.js
@@ -42,6 +42,7 @@ try {
f.prepend(b);
document.body.prepend(f);
});
+ await sleep(1500); await top(); // the app's own first paints settle before the wheel
console.log('[wheel]');
check('a notch is taken over', await notch(1));
@@ -50,7 +51,7 @@ try {
await top();
for (let i = 0; i < 5; i++) { await notch(1); await sleep(40); }
const five = await settle();
- check('five quick notches travel much farther', five > one * 4, five + 'px');
+ check('five quick notches travel much farther', five > one * 2.5, five + 'px');
await top();
for (let i = 0; i < 3; i++) { await notch(1); await sleep(40); }
await sleep(60); await notch(-1);
@@ -84,6 +85,20 @@ try {
for (let i = 1; i <= 6; i++) await page.mouse.move(b.x + 50, b.y + 150 - i * 15);
await page.mouse.up(); await sleep(50);
check('a drag that started on a button doesn\'t click it', await page.evaluate(() => window.__clicks) === 0);
+ // a hand's flick often starts a little sideways
+ await top();
+ await page.mouse.move(b.x + 50, b.y + 150); await page.mouse.down();
+ await page.mouse.move(b.x + 58, b.y + 145);
+ for (let i = 1; i <= 6; i++) await page.mouse.move(b.x + 60, b.y + 145 - i * 15);
+ await page.mouse.up(); await sleep(50);
+ check('a flick that starts a bit sideways still scrolls', (await settle()) > 50, await y() + 'px');
+ check('...and doesn\'t click', await page.evaluate(() => window.__clicks) === 0);
+ await top();
+ await page.mouse.move(b.x + 20, b.y + 150); await page.mouse.down();
+ for (let i = 1; i <= 8; i++) await page.mouse.move(b.x + 20 + i * 30, b.y + 152);
+ await page.mouse.up(); await sleep(50);
+ check('a sideways drag (selecting) doesn\'t click either', await page.evaluate(() => window.__clicks) === 0);
+ await sleep(350);
await page.click('#tgt'); await sleep(50);
check('...but a plain click still does', await page.evaluate(() => window.__clicks) === 1);
await top();