library-ts/browser/dom/page-features/components/MediaGallery.ts

258 lines
6.9 KiB
TypeScript
Raw Permalink Normal View History

2025-09-06 11:33:04 +00:00
import { TimePin } from "../../../animation/TimePin";
import { LinearGradient } from "../../../colors/Gradient";
import { HSLColor } from "../../../colors/HSLColor";
import { DateHelper } from "../../../date/DateHelper";
import { DateMath } from "../../../date/DateMath";
import { TimestampMessage } from "../../../messages/TimestampMessage";
import { RegExpUtility } from "../../../text/RegExpUtitlity";
import { ClassFlag } from "../../ClassFlag";
import { DOMHitTest } from "../../DOMHitTest";
import { DOMOrientation } from "../../DOMOrientation";
import { ElementAttribute } from "../../ElementAttribute";
import { ElementType } from "../../ElementType";
import { OnClick, OnMouseEnter, OnMouseMove, OnPause, OnPlay, OnTimeUpdate, OnTouchDrag, OnTouchEnd, OnTouchStart } from "../../EventListeners";
import { Fullscreen } from "../../Fullscreen";
import { Insight } from "../../Insight";
export class MediaGallery
{
static videoElements:HTMLElement[];
static activeVideoElement:HTMLElement;
static attachedGlobalListeners = false;
static insight:Insight;
static readonly mediaVideo = new ElementType( "media-video" );
static readonly mediaImage = new ElementType( "media-image" );
static readonly activeFlag = new ClassFlag( "active-video" );
static readonly itemIndex = new ElementAttribute( "item-index" );
static readonly container = new ElementType ( "media-container" );
static readonly showPlayButton = new ClassFlag( "show-play-button" );
static readonly fullScreenButton = new ElementType( "fullscreen-button" );
static readonly progressIndicator = new ElementType( "progress-indicator" );
static applyOnDocument( insight:Insight )
{
this.insight = insight;
this.attachGlobalListener();
MediaGallery.videoElements = MediaGallery.mediaVideo.queryAll( document.body ) as HTMLElement[];
MediaGallery.videoElements.forEach( v => this.applyOnVideoElement( v ) );
}
static attachGlobalListener()
{
if ( MediaGallery.attachedGlobalListeners )
{
return;
}
MediaGallery.attachedGlobalListeners = true;
// OnMouseMove.add(
// document.body,
// ( e )=>
// {
// if ( DOMOrientation.isPortrait )
// {
// return;
// }
// if ( ! MediaGallery.activeVideoElement )
// {
// return;
// }
// let isOver = DOMHitTest.isPointerOver( e, MediaGallery.activeVideoElement );
// if ( isOver )
// {
// return;
// }
// MediaGallery.updateActiveVideo( null );
// }
// )
}
static applyOnVideoElement( element:Element )
{
let videoElement = ElementType.video.query( element );
let fs = MediaGallery.fullScreenButton.query( element );
let pi = MediaGallery.progressIndicator.query( element ) as HTMLElement;
OnClick.add( pi,
( e )=>
{
let relative = DOMHitTest.getNormalizedPointerPosition( e, pi );
let position = Math.round( videoElement.duration * relative.x );
videoElement.currentTime = position;
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
}
);
let updateVideoTimeCode = ( text:string = null )=>
{
let textValue = text != null ? text : ( DateMath.formatToMinutesAndSeconds( videoElement.currentTime ) + " / " +
DateMath.formatToMinutesAndSeconds( videoElement.duration ) );
pi.innerHTML = `<span class="label">${textValue}</span>`;
let percent = text != null ? 0 : (videoElement.currentTime / videoElement.duration) * 100;
let leftColor = new HSLColor( 0, 0, 100, 0.3 );
let rightColor = new HSLColor( 0, 0, 100, 0.1 );
let linearBG = LinearGradient.createHorizontal( leftColor, rightColor, percent, 1 );
pi.style.background = linearBG + ", hsl(0,0%,0%,0.3)";
};
OnTimeUpdate.add( videoElement, () => { updateVideoTimeCode(); } );
OnClick.add( fs as HTMLElement,
()=>
{
Fullscreen.toggleFullscreen( element as HTMLElement, "auto" );
}
);
updateVideoTimeCode( "--:--" );
// OnMouseEnter.add( element as HTMLElement,
// ()=>
// {
// if ( DOMOrientation.isPortrait )
// {
// return;
// }
// MediaGallery.updateActiveVideo( element );
// }
// );
MediaGallery.showPlayButton.setAs( element, true );
OnClick.add( element as HTMLElement,
( me ) =>
{
if ( DOMOrientation.isPortrait )
{
return;
}
if ( videoElement.paused )
{
this.updateActiveVideo( element );
MediaGallery.showPlayButton.setAs( element, false );
}
else
{
videoElement.pause();
MediaGallery.showPlayButton.setAs( element, true );
}
}
);
OnTouchStart.add( element as HTMLElement,
( touchStartEvent )=>
{
if ( touchStartEvent.target == pi || DOMOrientation.isLandscape )
{
return;
}
console.log( touchStartEvent );
let startPosition = DOMHitTest.getRelativeWindowPosition( touchStartEvent );
let moved = false;
let treshold = 0.1;
let onDrag = ( dragEvent:TouchEvent )=>
{
if ( moved )
{
return;
}
let dragPosition = DOMHitTest.getRelativeWindowPosition( dragEvent );
moved = dragPosition.sub( startPosition ).length > treshold;
}
let onEnd = ()=>
{
OnTouchEnd.remove( element as HTMLElement, onEnd );
OnTouchDrag.remove( element as HTMLElement, onDrag );
if ( moved )
{
return;
}
let videoElement = ElementType.video.query( element );
if ( videoElement.paused )
{
this.updateActiveVideo( element );
MediaGallery.showPlayButton.setAs( element, false );
}
else
{
videoElement.pause();
MediaGallery.showPlayButton.setAs( element, true );
}
}
OnTouchEnd.add( element as HTMLElement, onEnd );
OnTouchDrag.add( element as HTMLElement, onDrag );
}
)
}
static updateActiveVideo( e:Element )
{
MediaGallery.activeVideoElement = e as HTMLElement;
this.videoElements.forEach(
( v )=>
{
let isActive = MediaGallery.activeVideoElement === v;
this.activeFlag.setAs( v, isActive );
let video = ElementType.video.query( v );
if ( ! video )
{
return;
}
if ( video.paused === ! isActive )
{
return;
}
if ( isActive )
{
// video.currentTime = 0;
video.play();
}
else
{
video.pause();
MediaGallery.showPlayButton.setAs( v, true );
}
}
)
}
}