diff options
| -rw-r--r-- | src/app.js | 49 | ||||
| -rw-r--r-- | src/style.css | 2 | ||||
| -rw-r--r-- | tools/feed-momentum-test.js | 48 |
3 files changed, 10 insertions, 89 deletions
@@ -6612,9 +6612,8 @@ if (INTENT_URI) { // The feed scrolls like a phone on a desktop. A mouse wheel's notch gives // it a push that coasts and slows, so a few turns travel a few posts and // quick turns stack up; a trackpad (which already coasts) is left alone. -// And a mouse can grab the feed and flick it: drag up or down, let go while -// moving and it keeps going. A drag that starts sideways is still a text -// selection, and a drag that moved isn't a click on what it started on. +// (A mouse drag used to grab the feed and flick it; it selects text again — +// Adam, 2026-10-18: "i'd rather be able to select text normally".) (() => { if (typeof window === 'undefined' || matchMedia('(prefers-reduced-motion: reduce)').matches) return; // The wheel coasts whenever a feed or a thread is the page being scrolled @@ -6736,49 +6735,7 @@ if (INTENT_URI) { // anything else that moves the page takes over from a coast window.addEventListener('keydown', (e) => { if (/^(Arrow|Page|Home|End| )/.test(e.key)) stop(); }); window.addEventListener('touchstart', stop, { passive: true }); - // ---- grab and flick - let drag = null; - document.addEventListener('pointerdown', (e) => { - if (raf) stop(); // a click catches a coasting page, like a finger does - if (e.pointerType !== 'mouse' || e.button !== 0 || !inScope(e.target)) return; - drag = { x: e.clientX, y: e.clientY, ly: e.clientY, on: false, pts: [] }; - }); - document.addEventListener('dragstart', (e) => { if (drag) e.preventDefault(); }, true); // images/links: scroll, don't drag them out - 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; - // 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 {} - } - window.scrollBy({ top: drag.ly - e.clientY, behavior: 'instant' }); - drag.ly = e.clientY; - drag.pts.push([e.timeStamp, e.clientY]); - while (drag.pts.length > 2 && e.timeStamp - drag.pts[0][0] > 100) drag.pts.shift(); - }); - const end = (e) => { - if (!drag) return; - const d = drag; drag = null; - 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]) * 2.4); - } - // 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 }), 300); - }; - document.addEventListener('pointerup', end); - document.addEventListener('pointercancel', () => { if (drag?.on) document.documentElement.classList.remove('grab-scrolling'); drag = null; }); + document.addEventListener('pointerdown', () => { if (raf) stop(); }); // a click catches a coasting page, like a finger does })(); window.addEventListener('load', () => { diff --git a/src/style.css b/src/style.css index af12d49..70745cd 100644 --- a/src/style.css +++ b/src/style.css @@ -741,8 +741,6 @@ html:has(#app .chat-card), body:has(#app .chat-card) { overflow: hidden; } .feed-chips { gap: 6px; flex-wrap: nowrap; overflow-x: auto; margin: 0 -14px; padding: 2px 14px; scrollbar-width: none; -webkit-overflow-scrolling: touch; } .feed-chips::-webkit-scrollbar { display: none; } /* with a mouse: a thin bar says the strip scrolls, and it drags (app.js) */ -/* grabbing the feed to scroll it (app.js) */ -.grab-scrolling, .grab-scrolling * { cursor: grabbing !important; user-select: none !important; } @media (hover: hover) and (pointer: fine) { .feed-chips { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; padding-bottom: 6px; cursor: grab; } .feed-chips::-webkit-scrollbar { display: block; height: 6px; } diff --git a/tools/feed-momentum-test.js b/tools/feed-momentum-test.js index 29e4934..3debd8a 100644 --- a/tools/feed-momentum-test.js +++ b/tools/feed-momentum-test.js @@ -1,8 +1,7 @@ // Desktop feed scrolling feels like a phone: a mouse-wheel notch coasts // farther than the browser's own step, quick notches stack, a reverse turn // brakes; a trackpad's smooth deltas are left to the browser; a mouse drag -// scrolls and a release while moving throws it; a drag that moved doesn't -// click; a sideways drag is left alone (text selection). +// selects text, as on any page. // Uses a tall stand-in feed so no relays are needed. // Run: bun tools/feed-momentum-test.js import puppeteer from './puppeteer.js'; @@ -76,50 +75,17 @@ try { check('...and a notch right after them too (still a trackpad)', !(await notch(1))); await sleep(500); - console.log('[grab and flick]'); + console.log('[a mouse drag selects text]'); await top(); + const b = await (await page.$('#tgt')).boundingBox(); + await page.evaluate(() => { window.__clicks = 0; getSelection().removeAllRanges(); }); await page.mouse.move(300, 700); await page.mouse.down(); for (let i = 1; i <= 10; i++) { await page.mouse.move(300, 700 - i * 40); await sleep(8); } - const during = await y(); await page.mouse.up(); - check('dragging up scrolls with the mouse', during >= 380 && during <= 420, during + 'px'); - const flung = await settle(); - check('letting go while moving throws it', flung > during + 400, flung + 'px'); - await top(); - await page.mouse.move(300, 700); await page.mouse.down(); - for (let i = 1; i <= 10; i++) { await page.mouse.move(300, 700 - i * 30); await sleep(8); } - await sleep(250); // hold still - const held = await y(); - await page.mouse.up(); - check('held still before letting go: it stays put', (await settle()) - held < 5, held + ' → ' + await y()); - await top(); - const b = await (await page.$('#tgt')).boundingBox(); - await page.evaluate(() => { window.__clicks = 0; }); - await page.mouse.move(b.x + 50, b.y + 150); await page.mouse.down(); - 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); + check('dragging up doesn\'t scroll the feed', (await settle()) === 0, await y() + 'px'); + check('...it selects text', await page.evaluate(() => getSelection().toString().length > 0)); await page.click('#tgt'); await sleep(50); - check('...but a plain click still does', await page.evaluate(() => window.__clicks) === 1); - await top(); - await page.mouse.move(100, 500); await page.mouse.down(); - for (let i = 1; i <= 10; i++) await page.mouse.move(100 + i * 30, 505); - await page.mouse.up(); - check('a sideways drag doesn\'t scroll (it selects text)', (await settle()) === 0); + check('a plain click still clicks', await page.evaluate(() => window.__clicks) === 1); check('no page errors', errs.length === 0, errs.join('; ').slice(0, 300)); } catch (e) { console.error(e); ok = false; } finally { await browser.close(); server.stop(); } console.log(ok ? 'PASS' : 'FAIL'); |
