File Coverage

lib/HTML/Object/DOM/List.pm
Criterion Covered Total %
statement 25 80 31.2
branch 0 34 0.0
condition 0 41 0.0
subroutine 9 17 52.9
pod 5 5 100.0
total 39 177 22.0


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## HTML Object - ~/lib/HTML/Object/DOM/List.pm
3             ## Version v0.2.1
4             ## Copyright(c) 2022 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <jack@deguest.jp>
6             ## Created 2021/12/28
7             ## Modified 2022/11/11
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::List;
15             BEGIN
16             {
17 1     1   978 use strict;
  1         3  
  1         44  
18 1     1   6 use warnings;
  1         2  
  1         30  
19 1     1   5 use parent qw( HTML::Object::EventTarget );
  1         2  
  1         5  
20 1     1   66 use vars qw( $VERSION );
  1         2  
  1         37  
21 1     1   6 use HTML::Object::Event;
  1         2  
  1         13  
22 1     1   284 use Want;
  1         3  
  1         56  
23 1     1   30 our $VERSION = 'v0.2.1';
24             };
25              
26 1     1   6 use strict;
  1         2  
  1         19  
27 1     1   5 use warnings;
  1         2  
  1         1069  
28              
29             sub init
30             {
31 0     0 1   my $self = shift( @_ );
32 0           $self->{children} = [];
33 0           $self->{_init_strict_use_sub} = 1;
34 0 0         $self->SUPER::init( @_ ) || return( $self->pass_error );
35 0           return( $self );
36             }
37              
38             # This method is called from the package inheriting from us
39             # $def is a dictionary hash reference providing specifics in a crisp way about the types of events and related properties concerned
40             # Example:
41             # {
42             # addtrack => {
43             # add => { property => 'children', type => 'add', event => 'addtrack' },
44             # },
45             # change => {
46             # add => { property => 'selected', type => 'add', event => 'change' },
47             # remove => { property => 'selected', type => 'remove', event => 'change' },
48             # },
49             # removetrack => {
50             # remove => { property => 'children', type => 'remove', event => 'removetrack' },
51             # },
52             # }
53             sub addEventListener
54             {
55 0     0 1   my $self = shift( @_ );
56 0 0         return( $self->error( "I was expecting 3 arguments, but got only ", scalar( @_ ), "." ) ) if( scalar( @_ ) < 3 );
57 0           my $def = shift( @_ );
58 0           my $type = shift( @_ );
59 0           my $code = shift( @_ );
60 0 0 0       return( $self->error( "Dictionary provided is not an hash reference." ) ) if( !defined( $def ) || ref( $def ) ne 'HASH' );
61 0 0 0       return( $self->error( "Event type provided contains illegal characters." ) ) if( !defined( $type ) || $type !~ /^\w+#/ );
62 0 0 0       return( $self->error( "Callback is not a code reference." ) ) if( !defined( $code ) || !length( "$code" ) || ref( $code ) ne 'CODE' );
      0        
63             # Before we enable the event listener we must make sure we are listening on events on relevant array or scalar
64 0 0         if( CORE::exists( $def->{ $type } ) )
65             {
66 0           my $ref = $def->{ $type };
67             # add or remove
68 0           OP: foreach my $op ( keys( %$ref ) )
69             {
70 0           my $this = $ref->{ $op };
71 0           for( qw( property type ) )
72             {
73 0 0 0       if( !CORE::exists( $this->{ $_ } ) || !defined( $this->{ $_ } ) || !CORE::length( $this->{ $_ } ) )
    0 0        
74             {
75 0 0         warnings::warn( "Dictionary property \"$_\" is missing or empty.\n" ) if( warnings::enabled( 'HTML::Object' ) );
76 0           next OP;
77             }
78             elsif( $_ ne 'add' && $_ ne 'remove' )
79             {
80 0           warnings::warn( "Unknown data listener type \"$_\"\n" );
81 0           next OP;
82             }
83             }
84            
85 0           my $subref = $self->can( $this->{property} );
86 0 0         if( !defined( $subref ) )
87             {
88 0 0 0       warnings::warn( "This object class \"" . ( ref( $self ) || $self ) . "\" does not support method \"" . $this->{property} . "\".\n" ) if( warnings::enabled( 'HTML::Object' ) );
89 0           next;
90             }
91 0           my $data = $subref->( $self );
92 0 0 0       if( !$self->_is_object( $data ) || !$data->can( 'callback' ) )
93             {
94 0 0 0       warnings::warn( "Object from class \"" . ( ref( $data ) || $data ) . "\" does not have a \"callback\" method.\n" ) if( warnings::enabled( 'HTML::Object' ) );
95 0           next;
96             }
97 0           my $cb = $data->callback( $this->{type} );
98             # Callback already exists
99 0 0 0       next if( defined( $cb ) && ref( $cb ) );
100             $data->callback( $this->{type} => sub
101             {
102 0     0     my $hash = shift( @_ );
103 0           my $event = $self->_make_event( $type );
104 0 0 0       if( CORE::exists( $this->{callback} ) && ref( $this->{callback} ) eq 'CODE' )
105             {
106 0           $this->{callback}->( $self, { event => $event, added => $hash->{added}, removed => $hash->{removed}, type => $hash->{type} });
107             }
108 0           $self->dispatchEvent( $event );
109 0           });
110             }
111             }
112 0           return( $self->SUPER::addEventListener( $type => $code ) );
113             }
114              
115 0     0 1   sub forEach { return( shift->children->foreach( @_ ) ); }
116              
117 0     0 1   sub length { return( shift->children->length ); }
118              
119 0     0 1   sub push { return( shift->children->push( @_ ) ); }
120              
121             sub _make_event
122             {
123 0     0     my $self = shift( @_ );
124 0           my $type = shift( @_ );
125 0   0       my $event = HTML::Object::Event->new( $type,
126             bubbles => 0,
127             cancellable => 0,
128             target => $self,
129             ) || return( $self->pass_error );
130 0           return( $event );
131             }
132              
133             sub AUTOLOAD
134             {
135 0     0     my( $name ) = our $AUTOLOAD =~ /([^:]+)$/;
136 0           my $self = shift( @_ );
137 0           my $children = $self->children;
138 0 0 0       die( "No method \"\$name\" in class \"", ( ref( $self ) || $self ), "\".\n" ) if( !$children );
139 0           my $code = $children->can( $name );
140 0 0 0       die( "No method \"\$name\" in class \"", ( ref( $children ) || $children ), "\".\n" ) if( !$code );
141 0           eval( "sub $name { return( shift->children->$name( \@_ ) ); }\n\n" );
142 0           return( $code->( $children, @_ ) );
143             }
144              
145             1;
146             # NOTE: POD
147             __END__
148              
149             =encoding utf-8
150              
151             =head1 NAME
152              
153             HTML::Object::DOM::List - HTML Object DOM List Abstract Class
154              
155             =head1 SYNOPSIS
156              
157             package HTML::Object::DOM::VideoTrackList;
158             use parent qw( HTML::Object::DOM::List );
159            
160             my $list = HTML::Object::DOM::VideoTrackList->new || d
161             ie( HTML::Object::DOM::VideoTrackList->error, "\n" );
162              
163             =head1 VERSION
164              
165             v0.2.1
166              
167             =head1 DESCRIPTION
168              
169             This is an abstract class designed to be inherited by L<HTML::Object::DOM::TextTrackCueList>, L<HTML::Object::DOM::TextTrackList> and L<HTML::Object::DOM::VideoTrackList>
170              
171             It inherits from L<HTML::Object::EventTarget>
172              
173             =head1 INHERITANCE
174              
175             +-----------------------+ +---------------------------+ +-------------------------+
176             | HTML::Object::Element | --> | HTML::Object::EventTarget | --> | HTML::Object::DOM::List |
177             +-----------------------+ +---------------------------+ +-------------------------+
178              
179             =head1 METHODS
180              
181             =head2 addEventListener
182              
183             This is a variant from the usual C<addEventListener> from L<HTML::Object::EventTarget>. This method takes 3 arguments:
184              
185             =over 4
186              
187             =item 1. A dictionary hash reference
188              
189             This dictionary contains a key for each event name and another hash reference as their value. That hash reference contains the following properties:
190              
191             =over 8
192              
193             =item callback
194              
195             Optional property whose value is a code reference to be called after creating the event and before dispatching it with L<HTML::Object::EventTarget/dispatchEvent>. The purpose is to give it a chance to add some property value to the event like C<track> for L<HTML::Object::DOM::TrackEvent> fired by L<HTML::Object::DOM::TextTrackCueList>, L<HTML::Object::DOM::TextTrackList> and L<HTML::Object::DOM::VideoTrackList>
196              
197             =item event
198              
199             The event name.
200              
201             =item property
202              
203             The module property or method name.
204              
205             =item type
206              
207             The type of callback to set for this property. Possible values are: C<add> or C<remove>
208              
209             =back
210              
211             =item 2. An event type
212              
213             =item 3. An event handler callback
214              
215             =back
216              
217             When C<addEventListener> is called, it will check if, for the given even type passed, there is an entry in the dictionary, and if there is it will enable an internal callback on the associated module property when there is any change to its underlying value.
218              
219             This relies on L<Module::Generic::Array/callback> and L<Module::Generic::Scalar/callback>
220              
221             That internal callback will be called when a change occurs, and will create an L<event|HTML::Object::Event> of type C<type> and call L<HTML::Object::EventTarget/dispatchEvent> passing it the newly created event.
222              
223             If a C<callback> was specified in the dictionary for this event type, the callback code will be executed, and the whatever value added or removed will be passed to the callback as an hash reference and an hash property C<added> or C<removed> depending if the operation was to add or remove a value.
224              
225             After having set this internal callback to monitor change, if any, this will call its parent L<addEventListener> to register the event listener.
226              
227             =head2 forEach
228              
229             Calls C<foreach> on the array object returned by L<HTML::Object::Element/children> method.
230              
231             =head2 length
232              
233             Returns the size of the list, starting from C<1>.
234              
235             =head2 push
236              
237             Provided with some data and they will be appended to this list object.
238              
239             =head1 AUTHOR
240              
241             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
242              
243             =head1 SEE ALSO
244              
245             L<HTML::Object::EventTarget>, L<HTML::Object::Event>, L<HTML::Object::DOM::TextTrackCueList>, L<HTML::Object::DOM::TextTrackCueList>, L<HTML::Object::DOM::VideoTrackList>
246              
247             =head1 COPYRIGHT & LICENSE
248              
249             Copyright(c) 2021 DEGUEST Pte. Ltd.
250              
251             All rights reserved
252              
253             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
254              
255             =cut