File Coverage

lib/HTML/Object/DOM/Element/Video.pm
Criterion Covered Total %
statement 22 36 61.1
branch 0 4 0.0
condition n/a
subroutine 8 18 44.4
pod 8 10 80.0
total 38 68 55.8


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