4
4
* https://www.hlx.live/developer/block-collection/video
5
5
*/
6
6
7
- function embedYoutube ( url , autoplay ) {
7
+ const prefersReducedMotion = window . matchMedia ( '(prefers-reduced-motion: reduce)' ) ;
8
+
9
+ function embedYoutube ( url , autoplay , background ) {
8
10
const usp = new URLSearchParams ( url . search ) ;
9
- const suffix = autoplay ? '&muted=1&autoplay=1' : '' ;
11
+ let suffix = '' ;
12
+ if ( background || autoplay ) {
13
+ const suffixParams = {
14
+ autoplay : autoplay ? '1' : '0' ,
15
+ mute : background ? '1' : '0' ,
16
+ controls : background ? '0' : '1' ,
17
+ disablekb : background ? '1' : '0' ,
18
+ loop : background ? '1' : '0' ,
19
+ playsinline : background ? '1' : '0' ,
20
+ } ;
21
+ suffix = `&${ Object . entries ( suffixParams ) . map ( ( [ k , v ] ) => `${ k } =${ encodeURIComponent ( v ) } ` ) . join ( '&' ) } ` ;
22
+ }
10
23
let vid = usp . get ( 'v' ) ? encodeURIComponent ( usp . get ( 'v' ) ) : '' ;
11
24
const embed = url . pathname ;
12
25
if ( url . origin . includes ( 'youtu.be' ) ) {
13
26
[ , vid ] = url . pathname . split ( '/' ) ;
14
27
}
15
- return `<div style="left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;">
16
- <iframe src="https://www.youtube.com${ vid ? `/embed/${ vid } ?rel=0&v=${ vid } ${ suffix } ` : embed } " style="border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;"
28
+
29
+ const temp = document . createElement ( 'div' ) ;
30
+ temp . innerHTML = `<div style="left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;">
31
+ <iframe src="https://www.youtube.com${ vid ? `/embed/${ vid } ?rel=0&v=${ vid } ${ suffix } ` : embed } " style="border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;"
17
32
allow="autoplay; fullscreen; picture-in-picture; encrypted-media; accelerometer; gyroscope; picture-in-picture" allowfullscreen="" scrolling="no" title="Content from Youtube" loading="lazy"></iframe>
18
33
</div>` ;
34
+ return temp . children . item ( 0 ) ;
19
35
}
20
36
21
- function embedVimeo ( url , autoplay ) {
37
+ function embedVimeo ( url , autoplay , background ) {
22
38
const [ , video ] = url . pathname . split ( '/' ) ;
23
- const suffix = autoplay ? '?muted=1&autoplay=1' : '' ;
24
- return `<div style="left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;">
25
- <iframe src="https://player.vimeo.com/video/${ video } ${ suffix } "
26
- style="border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;"
27
- frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen
39
+ let suffix = '' ;
40
+ if ( background || autoplay ) {
41
+ const suffixParams = {
42
+ autoplay : autoplay ? '1' : '0' ,
43
+ background : background ? '1' : '0' ,
44
+ } ;
45
+ suffix = `?${ Object . entries ( suffixParams ) . map ( ( [ k , v ] ) => `${ k } =${ encodeURIComponent ( v ) } ` ) . join ( '&' ) } ` ;
46
+ }
47
+ const temp = document . createElement ( 'div' ) ;
48
+ temp . innerHTML = `<div style="left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;">
49
+ <iframe src="https://player.vimeo.com/video/${ video } ${ suffix } "
50
+ style="border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;"
51
+ frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen
28
52
title="Content from Vimeo" loading="lazy"></iframe>
29
53
</div>` ;
54
+ return temp . children . item ( 0 ) ;
30
55
}
31
56
32
- function getVideoElement ( source , autoplay ) {
57
+ function getVideoElement ( source , autoplay , background ) {
33
58
const video = document . createElement ( 'video' ) ;
34
59
video . setAttribute ( 'controls' , '' ) ;
35
- video . dataset . loading = 'true' ;
36
- video . addEventListener ( 'loadedmetadata' , ( ) => delete video . dataset . loading ) ;
37
60
if ( autoplay ) video . setAttribute ( 'autoplay' , '' ) ;
61
+ if ( background ) {
62
+ video . setAttribute ( 'loop' , '' ) ;
63
+ video . setAttribute ( 'playsinline' , '' ) ;
64
+ video . removeAttribute ( 'controls' ) ;
65
+ video . addEventListener ( 'canplay' , ( ) => {
66
+ video . muted = true ;
67
+ if ( autoplay ) video . play ( ) ;
68
+ } ) ;
69
+ }
38
70
39
71
const sourceEl = document . createElement ( 'source' ) ;
40
72
sourceEl . setAttribute ( 'src' , source ) ;
@@ -44,49 +76,69 @@ function getVideoElement(source, autoplay) {
44
76
return video ;
45
77
}
46
78
47
- const loadVideoEmbed = ( block , link , autoplay ) => {
48
- if ( block . dataset . embedIsLoaded ) {
79
+ const loadVideoEmbed = ( block , link , autoplay , background ) => {
80
+ if ( block . dataset . embedLoaded === 'true' ) {
49
81
return ;
50
82
}
51
83
const url = new URL ( link ) ;
52
84
53
85
const isYoutube = link . includes ( 'youtube' ) || link . includes ( 'youtu.be' ) ;
54
86
const isVimeo = link . includes ( 'vimeo' ) ;
55
- const isMp4 = link . includes ( '.mp4' ) ;
56
87
57
88
if ( isYoutube ) {
58
- block . innerHTML = embedYoutube ( url , autoplay ) ;
89
+ const embedWrapper = embedYoutube ( url , autoplay , background ) ;
90
+ block . append ( embedWrapper ) ;
91
+ embedWrapper . querySelector ( 'iframe' ) . addEventListener ( 'load' , ( ) => {
92
+ block . dataset . embedLoaded = true ;
93
+ } ) ;
59
94
} else if ( isVimeo ) {
60
- block . innerHTML = embedVimeo ( url , autoplay ) ;
61
- } else if ( isMp4 ) {
62
- block . textContent = '' ;
63
- block . append ( getVideoElement ( link , autoplay ) ) ;
95
+ const embedWrapper = embedVimeo ( url , autoplay , background ) ;
96
+ block . append ( embedWrapper ) ;
97
+ embedWrapper . querySelector ( 'iframe' ) . addEventListener ( 'load' , ( ) => {
98
+ block . dataset . embedLoaded = true ;
99
+ } ) ;
100
+ } else {
101
+ const videoEl = getVideoElement ( link , autoplay , background ) ;
102
+ block . append ( videoEl ) ;
103
+ videoEl . addEventListener ( 'canplay' , ( ) => {
104
+ block . dataset . embedLoaded = true ;
105
+ } ) ;
64
106
}
65
-
66
- block . dataset . embedIsLoaded = true ;
67
107
} ;
68
108
69
109
export default async function decorate ( block ) {
110
+ console . log ( 'decorating video block' ) ;
70
111
const placeholder = block . querySelector ( 'picture' ) ;
71
112
const link = block . querySelector ( 'a' ) . href ;
72
113
block . textContent = '' ;
114
+ block . dataset . embedLoaded = false ;
73
115
116
+ const autoplay = block . classList . contains ( 'autoplay' ) ;
74
117
if ( placeholder ) {
118
+ block . classList . add ( 'placeholder' ) ;
75
119
const wrapper = document . createElement ( 'div' ) ;
76
120
wrapper . className = 'video-placeholder' ;
77
- wrapper . innerHTML = '<div class="video-placeholder-play"><button type="button" title="Play"></button></div>' ;
78
- wrapper . prepend ( placeholder ) ;
79
- wrapper . addEventListener ( 'click' , ( ) => {
80
- loadVideoEmbed ( block , link , true ) ;
81
- } ) ;
121
+ wrapper . append ( placeholder ) ;
122
+
123
+ if ( ! autoplay ) {
124
+ wrapper . insertAdjacentHTML (
125
+ 'beforeend' ,
126
+ '<div class="video-placeholder-play"><button type="button" title="Play"></button></div>' ,
127
+ ) ;
128
+ wrapper . addEventListener ( 'click' , ( ) => {
129
+ wrapper . remove ( ) ;
130
+ loadVideoEmbed ( block , link , true , false ) ;
131
+ } ) ;
132
+ }
82
133
block . append ( wrapper ) ;
83
- } else {
84
- block . classList . add ( 'lazy-loading' ) ;
134
+ }
135
+
136
+ if ( ! placeholder || autoplay ) {
85
137
const observer = new IntersectionObserver ( ( entries ) => {
86
138
if ( entries . some ( ( e ) => e . isIntersecting ) ) {
87
139
observer . disconnect ( ) ;
88
- loadVideoEmbed ( block , link , false ) ;
89
- block . classList . remove ( 'lazy-loading' ) ;
140
+ const playOnLoad = autoplay && ! prefersReducedMotion . matches ;
141
+ loadVideoEmbed ( block , link , playOnLoad , autoplay ) ;
90
142
}
91
143
} ) ;
92
144
observer . observe ( block ) ;
0 commit comments