From f6970a3be5eb1019675debe47b0eedd77892a933 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 10 Nov 2026 07:21:18 -0700 Subject: A YouTube clip under a mouse takes its own clicks, and YouTube's full-screen button leaves our full screen. "The fullscreen icon on this youtube video worked to make the video fullscreen but not toggle it off … clicking the central pause button didn't pause, it fullscreened. it should just pause" (Adam, 2026-11-10). YouTube's newer player puts its pause button in the middle and its full-screen button above the bottom bar, both under the layer that takes a tap on the picture to full screen: so either press took the box full screen, and once there (the layer aside) the same button asked for full screen again from inside the frame, which shows nothing and leaves no way out. Now the layer is off while a mouse is over the box (by-mouse, set from the pointer's type; a finger gets it back), so the player's buttons do what they say, and a mouse click on the still plays it where it is. A touch's tap still goes full screen with sound; there, when the frame becomes the full-screen element in place of its box (the page sees that much), it's read as "out" and both steps are left. youtube-tap-test covers the touch runs with a finger, the button leaving full screen, and a mouse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.2 --- src/features/messages.js | 28 ++++++++++++++++++++++++++-- src/style.css | 3 +++ 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/features/messages.js b/src/features/messages.js index 4ba4bfb..b491a5c 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -8436,8 +8436,21 @@ export function messagesFeature(ctx) { Promise.resolve(go.call(v)).catch(() => {}); return true; } + // A YouTube box we took full screen still shows YouTube's own full-screen + // button, and a press on it asks for full screen again from inside the + // frame — nothing to see, and no way out ("worked to make the video + // fullscreen but not toggle it off"). The page does see that happen: the + // frame becomes the full-screen element in place of its box. The press + // meant "out", so out it goes, both steps. + let ytFs = null, ytLeaving = false; if (typeof document !== 'undefined') document.addEventListener('fullscreenchange', () => { const el = fsElement(); + const leave = () => Promise.resolve((document.exitFullscreen || document.webkitExitFullscreen || (() => {})).call(document)).catch(() => {}); + if (!el) { ytFs = null; ytLeaving = false; } + else if (el.classList && el.classList.contains('yt-embed')) { + if (ytLeaving) { ytLeaving = false; ytFs = null; leave(); return; } + ytFs = el; + } else if (el.tagName === 'IFRAME' && ytFs && ytFs.contains(el)) { ytLeaving = true; leave(); return; } // The player's own full-screen button on a feed clip: the pager, not // Chrome's full screen (no next clip there). The button stays on the bar // (left off, Chrome greys it out) and is taken over here. @@ -8643,15 +8656,26 @@ export function messagesFeature(ctx) { if (!go) return; Promise.resolve(go.call(box, { navigationUI: 'hide' })).catch(() => {}); }; + // With a mouse the player's own buttons are all in reach, so its clicks + // are its own: the shield is off while a mouse is over the box (by-mouse; + // a finger on the same screen gets it back) and the middle button pauses, the + // corner one goes full screen and back (Adam, 2026-11-10: the pause button + // "didn't pause, it fullscreened. it should just pause"). A click on the + // still plays it where it is. const tapped = (e) => { if (e.target.closest('.yt-open, .vid-sound, iframe')) return; e.stopPropagation(); e.preventDefault(); const box = e.currentTarget; if (!box.dataset.playing) load(box, false); // a tap means sound else { post(box, 'unMute'); post(box, 'playVideo'); if (box._soundOn) box._soundOn(); } - full(box); + if (e.pointerType !== 'mouse') full(box); }; - const frame = h('div', { class: 'yt-embed', onClick: tapped }, + const byMouse = (e) => { e.currentTarget.classList.toggle('by-mouse', e.pointerType === 'mouse'); }; + const frame = h('div', { + class: 'yt-embed', onClick: tapped, + onPointerEnter: byMouse, onPointerMove: byMouse, onPointerDown: byMouse, + onPointerLeave: (e) => { e.currentTarget.classList.remove('by-mouse'); }, + }, h('img', { class: 'yt-poster', loading: 'lazy', alt: '', src: !feedPaint || feedMedia('https://i.ytimg.com/vi/' + vid + '/hqdefault.jpg') diff --git a/src/style.css b/src/style.css index d753604..9c6974b 100644 --- a/src/style.css +++ b/src/style.css @@ -1121,6 +1121,9 @@ html.no-scroll { overflow: hidden; scrollbar-gutter: auto; } /* over a playing clip: a tap takes it full screen; YouTube's control bar along the bottom is left uncovered, and full screen it all is */ .yt-shield { position: absolute; left: 0; right: 0; top: 0; bottom: 52px; z-index: 1; cursor: pointer; } +/* a mouse reaches the player's own buttons (pause in the middle, full screen + in the corner): while one is over the box its clicks go to the player */ +.yt-embed.by-mouse .yt-shield { display: none; } .yt-embed:fullscreen { border-radius: 0; aspect-ratio: auto; width: 100%; height: 100%; } .yt-embed:fullscreen .yt-shield { display: none; } .yt-embed:fullscreen iframe { object-fit: contain; } -- cgit v1.2.3