line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## HTML Object - ~/lib/HTML/Object/DOM/Element/Video.pm |
3
|
|
|
|
|
|
|
## Version v0.2.0 |
4
|
|
|
|
|
|
|
## Copyright(c) 2021 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
6
|
|
|
|
|
|
|
## Created 2021/12/23 |
7
|
|
|
|
|
|
|
## Modified 2022/09/18 |
8
|
|
|
|
|
|
|
## All rights reserved |
9
|
|
|
|
|
|
|
## |
10
|
|
|
|
|
|
|
## |
11
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
12
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
13
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
14
|
|
|
|
|
|
|
package HTML::Object::DOM::Element::Video; |
15
|
|
|
|
|
|
|
BEGIN |
16
|
|
|
|
|
|
|
{ |
17
|
1
|
|
|
1
|
|
1052
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
18
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
29
|
|
19
|
1
|
|
|
1
|
|
5
|
use parent qw( HTML::Object::DOM::Element::Media ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4
|
|
20
|
1
|
|
|
1
|
|
66
|
use vars qw( $VERSION ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
54
|
|
21
|
1
|
|
|
1
|
|
7
|
use HTML::Object::DOM::Element::Shared qw( :video ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
118
|
|
22
|
1
|
|
|
1
|
|
19
|
our $VERSION = 'v0.2.0'; |
23
|
|
|
|
|
|
|
}; |
24
|
|
|
|
|
|
|
|
25
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
31
|
|
26
|
1
|
|
|
1
|
|
7
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
336
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub init |
29
|
|
|
|
|
|
|
{ |
30
|
0
|
|
|
0
|
1
|
|
my $self = shift( @_ ); |
31
|
0
|
|
|
|
|
|
$self->{_init_strict_use_sub} = 1; |
32
|
0
|
0
|
|
|
|
|
$self->SUPER::init( @_ ) || return( $self->pass_error ); |
33
|
0
|
0
|
|
|
|
|
$self->{tag} = 'video' if( !CORE::length( "$self->{tag}" ) ); |
34
|
0
|
|
|
|
|
|
return( $self ); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# Note: property autoPictureInPicture |
38
|
0
|
|
|
0
|
1
|
|
sub autoPictureInPicture : lvalue { return( shift->_set_get_property({ attribute => 'autopictureinpicture', is_boolean => 1 }, @_ ) ); } |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# Note: property disablePictureInPicture |
41
|
0
|
|
|
0
|
1
|
|
sub disablePictureInPicture : lvalue { return( shift->_set_get_property({ attribute => 'disablepictureinpicture', is_boolean => 1 }, @_ ) ); } |
42
|
|
|
|
|
|
|
|
43
|
0
|
|
|
0
|
1
|
|
sub getVideoPlaybackQuality { return; } |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Note: property height is inherited |
46
|
|
|
|
|
|
|
|
47
|
0
|
|
|
0
|
0
|
|
sub onenterpictureinpicture : lvalue { return( shift->on( 'enterpictureinpicture', @_ ) ); } |
48
|
|
|
|
|
|
|
|
49
|
0
|
|
|
0
|
0
|
|
sub onleavepictureinpicture : lvalue { return( shift->on( 'leavepictureinpicture', @_ ) ); } |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Note: property poster |
52
|
0
|
|
|
0
|
1
|
|
sub poster : lvalue { return( shift->_set_get_property({ attribute => 'poster', is_uri => 1 }, @_ ) ); } |
53
|
|
|
|
|
|
|
|
54
|
0
|
|
|
0
|
1
|
|
sub requestPictureInPicture { return; } |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Note: property videoHeight read-only |
57
|
0
|
|
|
0
|
1
|
|
sub videoHeight : lvalue { return( shift->_set_get_number( 'videoheight', @_ ) ); } |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Note: property videoWidth read-only |
60
|
0
|
|
|
0
|
1
|
|
sub videoWidth : lvalue { return( shift->_set_get_number( 'videowidth', @_ ) ); } |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# Note: property width is inherited |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
1; |
65
|
|
|
|
|
|
|
# NOTE: POD |
66
|
|
|
|
|
|
|
__END__ |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=encoding utf-8 |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head1 NAME |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
HTML::Object::DOM::Element::Video - HTML Object DOM Video Class |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head1 SYNOPSIS |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
use HTML::Object::DOM::Element::Video; |
77
|
|
|
|
|
|
|
my $video = HTML::Object::DOM::Element::Video->new || |
78
|
|
|
|
|
|
|
die( HTML::Object::DOM::Element::Video->error, "\n" ); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head1 VERSION |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
v0.2.0 |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=head1 DESCRIPTION |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
This interface provides special properties and methods for manipulating video objects. It also inherits properties and methods of L<HTML::Object::DOM::Element::Media> and L<HTML::Object::DOM::Element>. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
<video controls width="250"> |
89
|
|
|
|
|
|
|
<source src="/some/where/video.webm" type="video/webm"> |
90
|
|
|
|
|
|
|
<source src="/some/where/video.mp4" type="video/mp4"> |
91
|
|
|
|
|
|
|
Sorry, your browser does not support embedded videos. |
92
|
|
|
|
|
|
|
</video> |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=head1 INHERITANCE |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
+-----------------------+ +---------------------------+ +-------------------------+ +----------------------------+ +-----------------------------------+ +-----------------------------------+ |
97
|
|
|
|
|
|
|
| HTML::Object::Element | --> | HTML::Object::EventTarget | --> | HTML::Object::DOM::Node | --> | HTML::Object::DOM::Element | --> | HTML::Object::DOM::Element::Media | --> | HTML::Object::DOM::Element::Video | |
98
|
|
|
|
|
|
|
+-----------------------+ +---------------------------+ +-------------------------+ +----------------------------+ +-----------------------------------+ +-----------------------------------+ |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=head1 PROPERTIES |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Inherits properties from its parent L<HTML::Object::DOM::Element::Media> |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head2 autoPictureInPicture |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
The autoPictureInPicture property reflects the HTML attribute indicating whether the video should enter or leave picture-in-picture mode automatically when the user switches tab and/or applications. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/autoPictureInPicture> |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head2 disablePictureInPicture |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The C<disablePictureInPicture> property reflects the HTML attribute indicating whether the user agent should suggest the picture-in-picture feature to users, or request it automatically. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/disablePictureInPicture> |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head2 height |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Is a string that reflects the height HTML attribute, which specifies the height of the display area, in CSS pixels. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/height> |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head2 poster |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Is a string that reflects the poster HTML attribute, which an URL for an image to be shown while the video is downloading. If this attribute is not specified, nothing is displayed until the first frame is available, then the first frame is shown as the poster frame. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/poster> |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=head2 videoHeight |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Under perl, this returns C<undef> by default, but you can set whatever number value you want. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Under JavaScript, this is read-only and returns an unsigned integer value indicating the intrinsic height of the resource in CSS pixels, or 0 if no media is available yet. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
Example: |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
my $v = $doc->getElementById("myVideo"); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
$v->addEventListener( resize => sub |
139
|
|
|
|
|
|
|
{ |
140
|
|
|
|
|
|
|
my $w = $v->videoWidth; |
141
|
|
|
|
|
|
|
my $h = $v->videoHeight; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
if( $w && $h ) |
144
|
|
|
|
|
|
|
{ |
145
|
|
|
|
|
|
|
$v->style->width = $w; |
146
|
|
|
|
|
|
|
$v->style->height = $h; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
}, { capture => 0 }); |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoHeight> |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head2 videoWidth |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Under perl, this is read-only and returns C<undef> by default, but you can set whatever number value you want. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Under JavaScript, this returns an unsigned integer value indicating the intrinsic width of the resource in CSS pixels, or 0 if no media is available yet. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoWidth> |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head2 width |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Is a string that reflects the width HTML attribute, which specifies the width of the display area, in CSS pixels. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/width> |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=head1 METHODS |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Inherits methods from its parent L<HTML::Object::DOM::Element::Media> |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head2 getVideoPlaybackQuality |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Under perl, this always returns C<undef>. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Under JavaScript, this returns a C<VideoPlaybackQuality> object that contains the current playback metrics. This information includes things like the number of dropped or corrupted frames, as well as the total number of frames. |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/getVideoPlaybackQuality> |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=head2 requestPictureInPicture |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
Under perl, this always returns C<undef> obviously. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
Under JavaScript, this requests that the user agent make video enters picture-in-picture mode |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/requestPictureInPicture> |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head1 EVENTS |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Event listeners for those events can also be found by prepending C<on> before the event type: |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
For example, C<enterpictureinpicture> event listeners can be set also with C<onenterpictureinpicture> method: |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
$e->onenterpictureinpicture(sub{ # do something }); |
193
|
|
|
|
|
|
|
# or as an lvalue method |
194
|
|
|
|
|
|
|
$e->onenterpictureinpicture = sub{ # do something }; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head2 enterpictureinpicture |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
Sent to a L<HTML::Object::DOM::Element::Video> when it enters Picture-in-Picture mode. The associated event handler is L<HTML::Object::DOM::Element::Video>.onenterpictureinpicture |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
Example: |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
my $video = $doc->querySelector('#$video'); |
203
|
|
|
|
|
|
|
my $button = $doc->querySelector('#$button'); |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub onEnterPip |
206
|
|
|
|
|
|
|
{ |
207
|
|
|
|
|
|
|
say( "Picture-in-Picture mode activated!" ); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
$video->addEventListener( enterpictureinpicture => \&onEnterPip, { capture => 0 }); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
$button->onclick = sub |
213
|
|
|
|
|
|
|
{ |
214
|
|
|
|
|
|
|
$video->requestPictureInPicture(); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
my $video = $doc->querySelector('#$video'); |
218
|
|
|
|
|
|
|
my $button = $doc->querySelector('#$button'); |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub onEnterPip |
221
|
|
|
|
|
|
|
{ |
222
|
|
|
|
|
|
|
say( "Picture-in-Picture mode activated!" ); |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
$video->onenterpictureinpicture = \&onEnterPip; |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
$button->onclick = sub |
228
|
|
|
|
|
|
|
{ |
229
|
|
|
|
|
|
|
$video->requestPictureInPicture(); |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/enterpictureinpicture_event> |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=head2 leavepictureinpicture |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Sent to a L<HTML::Object::DOM::Element::Video> when it leaves Picture-in-Picture mode. The associated event handler is L<HTML::Object::DOM::Element::Video>.onleavepictureinpicture |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
Example: |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
my $video = $doc->querySelector('#$video'); |
241
|
|
|
|
|
|
|
my $button = $doc->querySelector('#$button'); |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub onExitPip |
244
|
|
|
|
|
|
|
{ |
245
|
|
|
|
|
|
|
say( "Picture-in-Picture mode deactivated!" ); |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
$video->addEventListener( leavepictureinpicture => \&onExitPip, { capture => 0 }); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
$button->onclick = sub |
251
|
|
|
|
|
|
|
{ |
252
|
|
|
|
|
|
|
if( $doc->pictureInPictureElement ) |
253
|
|
|
|
|
|
|
{ |
254
|
|
|
|
|
|
|
$doc->exitPictureInPicture(); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
my $video = $doc->querySelector('#$video'); |
259
|
|
|
|
|
|
|
my $button = $doc->querySelector('#$button'); |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub onExitPip |
262
|
|
|
|
|
|
|
{ |
263
|
|
|
|
|
|
|
say( "Picture-in-Picture mode deactivated!" ); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
$video->onleavepictureinpicture = \&onExitPip; |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
$button->onclick = sub |
269
|
|
|
|
|
|
|
{ |
270
|
|
|
|
|
|
|
if( $doc->pictureInPictureElement ) |
271
|
|
|
|
|
|
|
{ |
272
|
|
|
|
|
|
|
$doc->exitPictureInPicture(); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/leavepictureinpicture_event> |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=head1 EXAMPLE |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
<h1>Ask a question at a given point in a video</h1> |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
<p>The question is displayed after 10 seconds, if the answer given is correct, the video continues, if not it starts again from the beginning</p> |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
<video id="myVideo" controls=""> |
285
|
|
|
|
|
|
|
<source src="https://example.org/some/where/videos/video.mp4" /> |
286
|
|
|
|
|
|
|
<source src="https://example.org/some/where/videos/video.webm" /> |
287
|
|
|
|
|
|
|
</video> |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
// This only works in a web browser, so this is intentionally in JavaScript |
290
|
|
|
|
|
|
|
// First identify the video in the DOM |
291
|
|
|
|
|
|
|
var myVideo = document.getElementById( 'myVideo' ); |
292
|
|
|
|
|
|
|
myVideo.ontimeupdate = function() |
293
|
|
|
|
|
|
|
{ |
294
|
|
|
|
|
|
|
// Remove the decimal numbers from the time |
295
|
|
|
|
|
|
|
var currentTime = Math.floor( myVideo.currentTime ); |
296
|
|
|
|
|
|
|
if( currentTime == 10 ) |
297
|
|
|
|
|
|
|
{ |
298
|
|
|
|
|
|
|
myVideo.pause (); |
299
|
|
|
|
|
|
|
// Ask the question with a promt |
300
|
|
|
|
|
|
|
var r = prompt( "What is the video about?" ); |
301
|
|
|
|
|
|
|
// check the answer |
302
|
|
|
|
|
|
|
if( r.toLowerCase() == "Example" ) |
303
|
|
|
|
|
|
|
{ |
304
|
|
|
|
|
|
|
myVideo.currentTime = 11; // Add a second otherwise the question will be displayed again; |
305
|
|
|
|
|
|
|
myVideo.play(); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
else |
308
|
|
|
|
|
|
|
{ |
309
|
|
|
|
|
|
|
myVideo.currentTime = 0; // Put the video back to 0; |
310
|
|
|
|
|
|
|
myVideo.play(); |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
Example taken from L<EduTech Wiki|https://edutechwiki.unige.ch/en/HTML5_video_and_JavaScript> |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
Picture in Picture (a.k.a. PiP) |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
The W3C states that "the specification intends to provide APIs to allow websites to create a floating video window always on top of other windows so that users may continue consuming media while they interact with other content sites, or applications on their device." |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
<video id="videoElement" controls="true" src="demo.mp4"></video> |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
<!-- button will be used to toggle the PiP mode --> |
324
|
|
|
|
|
|
|
<button id="togglePipButton">Toggle Picture-in-Picture Mode!</button> |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Call L</requestPictureInPicture> on C<click> of C<togglePipButton> button element. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
When the promise resolves, the browser will shrink the video into a mini window that the user can move around and position over other windows. |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
let video = document.getElementById('videoElement'); |
331
|
|
|
|
|
|
|
let togglePipButton = document.getElementById('togglePipButton'); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
togglePipButton.addEventListener('click', async function (event) { |
334
|
|
|
|
|
|
|
togglePipButton.disabled = true; //disable toggle button while the event occurs |
335
|
|
|
|
|
|
|
try { |
336
|
|
|
|
|
|
|
// If there is no element in Picture-in-Picture yet, request for it |
337
|
|
|
|
|
|
|
if (video !== document.pictureInPictureElement) { |
338
|
|
|
|
|
|
|
await video.requestPictureInPicture(); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
// If Picture-in-Picture already exists, exit the mode |
341
|
|
|
|
|
|
|
else { |
342
|
|
|
|
|
|
|
await document.exitPictureInPicture(); |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
} catch (error) { |
346
|
|
|
|
|
|
|
console.log(`Oh Horror! ${error}`); |
347
|
|
|
|
|
|
|
} finally { |
348
|
|
|
|
|
|
|
togglePipButton.disabled = false; //enable toggle button after the event |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
}); |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Check for Picture-in-Picture event changes |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
let video = document.getElementById('videoElement'); |
355
|
|
|
|
|
|
|
video.addEventListener('enterpictureinpicture', function (event) { |
356
|
|
|
|
|
|
|
console.log('Entered PiP'); |
357
|
|
|
|
|
|
|
pipWindow = event.pictureInPictureWindow; |
358
|
|
|
|
|
|
|
console.log(`Window size - \n Width: ${pipWindow.width} \n Height: ${pipWindow.height}`); // get the width and height of PiP window |
359
|
|
|
|
|
|
|
}); |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
video.addEventListener('leavepictureinpicture', function (event) { |
362
|
|
|
|
|
|
|
console.log('Left PiP'); |
363
|
|
|
|
|
|
|
togglePipButton.disabled = false; |
364
|
|
|
|
|
|
|
}); |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
Example taken from L<https://dev.to/ananyaneogi/implement-picture-in-picture-on-the-web-17g8> |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=head1 AUTHOR |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=head1 SEE ALSO |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement>, L<Mozilla documentation on video element|https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video>, L<W3C specifications for PiP|https://w3c.github.io/picture-in-picture/> |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
Copyright(c) 2021 DEGUEST Pte. Ltd. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
All rights reserved |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=cut |