aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/messages.js')
-rw-r--r--src/features/messages.js52
1 files changed, 49 insertions, 3 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index c82bd0e..74b7d4a 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -7949,7 +7949,7 @@ export function messagesFeature(ctx) {
// known, never taller than the screen; only a clip taller than that sits
// in a black frame, rather than in a strip at the left.
const videoBoxStyle = (d) => d && d.width && d.height
- ? `width:100%;aspect-ratio:${d.width}/${d.height};max-height:100vh;object-fit:contain`
+ ? `width:100%;aspect-ratio:${d.width}/${d.height};max-height:var(--vid-cap);object-fit:contain`
: 'width:100%;aspect-ratio:16/9;object-fit:contain';
// Over a clip that waits for a tap: what it costs, and the tap that plays
// it (with sound — the reader asked for this one). The box is left alone
@@ -8095,10 +8095,19 @@ export function messagesFeature(ctx) {
});
}
// A tap on the picture itself (not the player's own play button or its
- // control bar): inline, it goes full screen — the corner button is a
+ // control bar): inline, a mouse click pauses a playing clip; a paused one
+ // (or any touch) goes full screen — the corner button is a
// reach on a phone. Full screen, it pauses a playing clip, and a tap on a
// paused one comes back out. The player's controls are inside the video
// element, so where they sit is judged from the tap's position.
+ // The big play/pause over a feed clip is for a mouse: <html> carries
+ // .has-mouse while the last pointer was one (a touch laptop switches with
+ // the hand), and CSS shows the button on :hover (a repaint can't drop it).
+ if (typeof document !== 'undefined') {
+ const mouseIs = (on) => document.documentElement.classList.toggle('has-mouse', on);
+ document.addEventListener('pointermove', (e) => { if (e.pointerType === 'mouse') mouseIs(true); }, { passive: true });
+ document.addEventListener('pointerdown', (e) => { if (e.pointerType !== 'mouse') mouseIs(false); }, { passive: true });
+ }
const fsElement = () => (typeof document !== 'undefined' && (document.fullscreenElement || document.webkitFullscreenElement)) || null;
let videoTapAt = 0; // a touch's tap on a clip, taken at pointerup: the click after it lands on whatever opened
function videoTap(e, url) {
@@ -8120,6 +8129,18 @@ export function messagesFeature(ctx) {
else (document.exitFullscreen || document.webkitExitFullscreen || (() => {})).call(document)?.catch?.(() => {});
return true;
}
+ // a mouse click on a playing clip just pauses it (Adam: "clicking on a
+ // video that's playing should pause the video, not full screen it"); it
+ // keeps its controls and the middle button resumes it, and a click on it
+ // paused opens the pager. A touch has no middle button: its tap still opens.
+ if (!v.paused && e.pointerType === 'mouse') {
+ v.pause();
+ wokeClips.add(url);
+ const box = v.closest('.note-video-box');
+ if (box) { box.classList.remove('idle'); box._skipMorph = true; }
+ v.controls = true;
+ return true;
+ }
if (openClip(v, url)) return true;
// a clip still idle (autoplaying, no controls) becomes the reader's
wokeClips.add(url);
@@ -8187,8 +8208,33 @@ export function messagesFeature(ctx) {
if (videoTap(e, url)) el._tapAt = videoTapAt = Date.now();
});
v.muted = !loud; // the property, not just the attribute: a script-made element autoplays only muted
- const box = h('div', { class: 'note-video-box' + (idle ? ' idle' : '') }, v);
+ // a tall clip is held to the cap's height and the box narrows to its
+ // shape, instead of a full-width box of black bars (Adam, on a 1920 screen)
+ const boxCap = (w, ht) => w && ht ? `max-width:calc(var(--vid-cap) * ${w} / ${ht})` : undefined;
+ const known = feedMedia(url);
+ const box = h('div', { class: 'note-video-box' + (idle ? ' idle' : ''), style: boxCap(known && known.width, known && known.height) }, v);
+ v.addEventListener('loadedmetadata', () => { if (v.videoWidth && v.videoHeight) box.style.maxWidth = `calc(var(--vid-cap) * ${v.videoWidth} / ${v.videoHeight})`; });
if (loud) box._skipMorph = true;
+ // With a mouse: a big play/pause button in the middle while the pointer is
+ // over the clip. It plays or pauses in place, never full screen (a click
+ // elsewhere on a paused clip opens the pager). Touch keeps its taps.
+ const pp = h('button', { class: 'vid-pp', type: 'button', 'aria-label': t('videoPlay'), onClick: (e) => {
+ e.stopPropagation(); e.preventDefault();
+ const player = e.currentTarget.closest('.note-video-box')?.querySelector('video');
+ if (!player) return;
+ if (player.paused) { tappedClips.add(url); player.play().catch(() => {}); } else player.pause();
+ } }, h('span', { class: 'vid-pp-i', 'aria-hidden': 'true' }));
+ const ppState = () => {
+ const live = v.closest('.note-video-box');
+ const b = live && live.querySelector('.vid-pp');
+ if (!b) return;
+ b.classList.toggle('playing', !v.paused);
+ b.setAttribute('aria-label', t(v.paused ? 'videoPlay' : 'videoPause'));
+ };
+ v.addEventListener('play', ppState);
+ v.addEventListener('pause', ppState);
+ box.append(pp);
+
// remembered by clip, so a repaint draws the box as it now stands
const wake = () => {
wokeClips.add(url);