@@ -184,6 +184,7 @@ const dispatchOphanAttentionEvent = (
184184} ;
185185
186186const getOptimisedPosterImage = ( mainImage : string ) : string => {
187+ // This only runs on the client
187188 const resolution = window . devicePixelRatio >= 2 ? 'high' : 'low' ;
188189
189190 return generateImageURL ( {
@@ -218,8 +219,9 @@ const shouldUseWebkitFullscreen = (video: HTMLVideoElement): boolean => {
218219} ;
219220
220221/**
221- * Ensure the aspect ratio of the video is within the boundary, if specified.
222- * For example, we may not want to render a square video inside a 4:5 feature card.
222+ * Ensures the aspect ratio falls between the minimum and maximum allowed aspect ratios, if specified.
223+ * For example, we may not want to render a square video inside a 4:5 feature card. In this case, the
224+ * minimum & maximum aspect ratio would be 4:5, so that the video fits the fixed-aspect ratio feature card
223225 */
224226const getAspectRatioOfVisibleVideo = (
225227 aspectRatio : number ,
@@ -236,42 +238,6 @@ const getAspectRatioOfVisibleVideo = (
236238 return aspectRatio ;
237239} ;
238240
239- type Props = {
240- sources : Source [ ] ;
241- atomId : string ;
242- uniqueId : string ;
243- videoStyle : VideoPlayerFormat ;
244- aspectRatio : number ;
245- posterImage : string ;
246- fallbackImage : CardPictureProps [ 'mainImage' ] ;
247- fallbackImageSize : CardPictureProps [ 'imageSize' ] ;
248- fallbackImageLoading : CardPictureProps [ 'loading' ] ;
249- fallbackImageAlt : CardPictureProps [ 'alt' ] ;
250- fallbackImageAspectRatio : CardPictureProps [ 'aspectRatio' ] ;
251- linkTo : string ;
252- showProgressBar ?: boolean ;
253- subtitleSource ?: string ;
254- subtitleSize : SubtitleSize ;
255- /** The position of subtitles and the audio icon. Usually at the bottom, with the exception of Feature Cards. */
256- controlsPosition ?: 'top' | 'bottom' ;
257- /**
258- * The minimum/maximum aspect ratio the video will have. The video will be cropped if this
259- * value is defined and the video aspect ratio is less/greater than this value.
260- */
261- minAspectRatio ?: number ;
262- maxAspectRatio ?: number ;
263- /**
264- * Specify this value to enforce the size of the video container on mobile/desktop.
265- * Grey bars will appear if this value is defined and differs from the video aspect ratio.
266- */
267- containerAspectRatioMobile ?: number ;
268- containerAspectRatioDesktop ?: number ;
269- caption ?: string ;
270- format ?: ArticleFormat ;
271- isMainMedia ?: boolean ;
272- role ?: RoleType ;
273- } ;
274-
275241const doesUserPermitAutoplayOnWeb = ( ) : boolean => {
276242 /**
277243 * The user indicates a preference for reduced motion: https://web.dev/articles/prefers-reduced-motion
@@ -294,7 +260,6 @@ const doesUserPermitAutoplayOnWeb = (): boolean => {
294260const doesUserPermitAutoplayOnApps = async ( ) : Promise < boolean > => {
295261 /* isAutoplayEnabled is available on the video client from 8.8.0 onwards */
296262 const isBridgetCompatible = await hasMinimumBridgetVersion ( '8.8.0' ) ;
297-
298263 if ( ! isBridgetCompatible ) return true ;
299264
300265 try {
@@ -312,6 +277,44 @@ const doesUserPermitAutoplayOnApps = async (): Promise<boolean> => {
312277 }
313278} ;
314279
280+ type Props = {
281+ sources : Source [ ] ;
282+ atomId : string ;
283+ uniqueId : string ;
284+ videoStyle : VideoPlayerFormat ;
285+ aspectRatio : number ;
286+ posterImage : string ;
287+ fallbackImage : CardPictureProps [ 'mainImage' ] ;
288+ fallbackImageSize : CardPictureProps [ 'imageSize' ] ;
289+ fallbackImageLoading : CardPictureProps [ 'loading' ] ;
290+ fallbackImageAlt : CardPictureProps [ 'alt' ] ;
291+ fallbackImageAspectRatio : CardPictureProps [ 'aspectRatio' ] ;
292+ linkTo : string ;
293+ hideProgressBar ?: boolean ;
294+ subtitleSource ?: string ;
295+ subtitleSize : SubtitleSize ;
296+ /**
297+ * The position of subtitles and the audio icon.
298+ */
299+ controlsPosition ?: 'top' | 'bottom' ;
300+ /**
301+ * The minimum/maximum aspect ratio the video will have. The video will be cropped if this
302+ * value is defined and the video aspect ratio is less/greater than this value.
303+ */
304+ minAspectRatio ?: number ;
305+ maxAspectRatio ?: number ;
306+ /**
307+ * Specify this value to enforce the size of the video container on mobile/desktop.
308+ * Grey bars will appear if this value is defined and differs from the video aspect ratio.
309+ */
310+ containerAspectRatioMobile ?: number ;
311+ containerAspectRatioDesktop ?: number ;
312+ caption ?: string ;
313+ format ?: ArticleFormat ;
314+ isMainMedia ?: boolean ;
315+ role ?: RoleType ;
316+ } ;
317+
315318export const SelfHostedVideo = ( {
316319 sources,
317320 atomId,
@@ -325,7 +328,7 @@ export const SelfHostedVideo = ({
325328 fallbackImageAlt,
326329 fallbackImageAspectRatio,
327330 linkTo,
328- showProgressBar = true ,
331+ hideProgressBar = false ,
329332 subtitleSource,
330333 subtitleSize,
331334 controlsPosition = 'bottom' ,
@@ -361,10 +364,20 @@ export const SelfHostedVideo = ({
361364 const isApps = renderingTarget === 'Apps' ;
362365
363366 /**
364- * All controls on the video are hidden: the video looks like a GIF.
367+ * In a cinemagraph, all controls are hidden: the video looks like a GIF.
365368 * This includes but may not be limited to: audio icon, play/pause icon, subtitles, progress bar.
366369 */
367370 const isCinemagraph = videoStyle === 'Cinemagraph' ;
371+ const isLoop = videoStyle === 'Loop' ;
372+ const isDefault = videoStyle === 'Default' ;
373+
374+ const canAutoplay = isLoop || isCinemagraph ;
375+
376+ const shouldAutoplay = canAutoplay && isAutoplayAllowed ;
377+
378+ const shouldLoop = isLoop || isCinemagraph ;
379+
380+ const showProgressBar = ! hideProgressBar && ! isCinemagraph ;
368381
369382 const ophanVideoStyle = videoStyle . toLowerCase ( ) as OphanVideoStyle ;
370383
@@ -603,12 +616,12 @@ export const SelfHostedVideo = ({
603616 */
604617 useEffect ( ( ) => {
605618 if (
606- isAutoplayAllowed === false ||
619+ shouldAutoplay === false ||
607620 ( isInView === false && playerState === 'NOT_STARTED' )
608621 ) {
609622 setShowPosterImage ( true ) ;
610623 }
611- } , [ isAutoplayAllowed , isInView , playerState ] ) ;
624+ } , [ shouldAutoplay , isInView , playerState ] ) ;
612625
613626 if ( adapted ) {
614627 return FallbackImageComponent ;
@@ -813,9 +826,9 @@ export const SelfHostedVideo = ({
813826 *
814827 * Stops playback when the video is scrolled out of view.
815828 */
816- if ( vidRef . current && isPlayable ) {
829+ if ( isPlayable ) {
817830 if (
818- isAutoplayAllowed &&
831+ shouldAutoplay &&
819832 isInView &&
820833 ( playerState === 'NOT_STARTED' ||
821834 playerState === 'PAUSED_BY_INTERSECTION_OBSERVER' ||
@@ -831,14 +844,15 @@ export const SelfHostedVideo = ({
831844 }
832845
833846 /**
834- * Show the play icon when the video is not playing, except for when it is scrolled
835- * out of view . In this case, the intersection observer will resume playback and
836- * having a play icon would falsely indicate a user action is required to resume playback.
847+ * Show the play icon when the video is not playing, except for when it is scrolled out of view,
848+ * i.e. paused by intersection observer . In this case, the intersection observer will resume playback
849+ * and having a play icon would falsely indicate a user action is required to resume playback.
837850 */
838851 const showPlayIcon =
839- playerState === 'PAUSED_BY_USER' ||
840- playerState === 'PAUSED_BY_BROWSER' ||
841- ( playerState === 'NOT_STARTED' && ! isAutoplayAllowed ) ;
852+ ! isCinemagraph &&
853+ ( playerState === 'PAUSED_BY_USER' ||
854+ playerState === 'PAUSED_BY_BROWSER' ||
855+ ( playerState === 'NOT_STARTED' && shouldAutoplay === false ) ) ;
842856
843857 /** The aspect ratio of the video will be clamped within the specified range */
844858 const aspectRatioOfVisibleVideo = getAspectRatioOfVisibleVideo (
@@ -864,12 +878,6 @@ export const SelfHostedVideo = ({
864878 ? getOptimisedPosterImage ( posterImage )
865879 : undefined ;
866880
867- /**
868- * We almost always want to preload some of the video data. The exception
869- * is when autoplay is off and the video is only partially in view.
870- */
871- const preloadPartialData = ! ! isAutoplayAllowed || ! ! isInView ;
872-
873881 return (
874882 < figure
875883 className = { `video-container ${ videoStyle . toLocaleLowerCase ( ) } ${
@@ -926,13 +934,18 @@ export const SelfHostedVideo = ({
926934 handleFullscreenClick = { handleFullscreenClick }
927935 onError = { onError }
928936 AudioIcon = { hasAudio ? AudioIcon : null }
929- preloadPartialData = { preloadPartialData }
937+ preloadPartialData = { ! ! shouldAutoplay }
930938 showPlayIcon = { showPlayIcon }
931939 showProgressBar = { showProgressBar }
940+ showSubtitles = { ! isCinemagraph }
932941 subtitleSource = { subtitleSource }
933942 subtitleSize = { subtitleSize }
943+ showIcons = { ! isCinemagraph }
934944 controlsPosition = { controlsPosition }
935945 activeCue = { activeCue }
946+ shouldLoop = { shouldLoop }
947+ showFullscreenIcon = { isDefault }
948+ isInteractive = { ! isCinemagraph }
936949 />
937950 </ div >
938951 </ div >
0 commit comments