File Coverage

lib/HTML/Object/DOM/Element/TableRow.pm
Criterion Covered Total %
statement 81 117 69.2
branch 19 50 38.0
condition 11 30 36.6
subroutine 19 27 70.3
pod 14 14 100.0
total 144 238 60.5


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## HTML Object - ~/lib/HTML/Object/DOM/Element/TableRow.pm
3             ## Version v0.2.0
4             ## Copyright(c) 2022 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <jack@deguest.jp>
6             ## Created 2022/01/07
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::TableRow;
15             BEGIN
16             {
17 2     2   2181 use strict;
  2         4  
  2         72  
18 2     2   10 use warnings;
  2         5  
  2         76  
19 2     2   10 use parent qw( HTML::Object::DOM::Element );
  2         4  
  2         15  
20 2     2   195 use vars qw( $VERSION );
  2         3  
  2         103  
21 2     2   15 use HTML::Object::DOM::Element::Shared qw( :tablerow );
  2         6  
  2         295  
22 2     2   55 our $VERSION = 'v0.2.0';
23             };
24              
25 2     2   15 use strict;
  2         4  
  2         57  
26 2     2   11 use warnings;
  2         9  
  2         3145  
27              
28             sub init
29             {
30 6     6 1 596 my $self = shift( @_ );
31 6         189 $self->{_init_strict_use_sub} = 1;
32 6 50       41 $self->SUPER::init( @_ ) || return( $self->pass_error );
33 6 100 66     54 $self->{tag} = 'tr' if( !defined( $self->{tag} ) || !CORE::length( "$self->{tag}" ) );
34 6         103 $self->{_row_reset} = 1;
35             my $callback = sub
36             {
37 12     12   2059 my $def = shift( @_ );
38             # Our children were modified from outside our package.
39             # We need to check if it affects our rows and reset the cache accordingly
40 12 100 66     139 unless( $def->{caller}->[0] eq ref( $self ) ||
41             $def->{caller}->[0] eq 'HTML::Object::DOM::Element::Table' )
42             {
43 11         47 $self->reset(1);
44             }
45 12         106 return(1);
46 6         52 };
47 6         31 $self->children->callback( add => $callback );
48 6         981 $self->children->callback( remove => $callback );
49 6         600 return( $self );
50             }
51              
52             # Note: deprecated property align is inherited
53              
54             # Note: deprecated property bgColor
55 0     0 1 0 sub bgColor : lvalue { return( shift->_set_get_property( 'bgcolor', @_ ) ); }
56              
57 0     0 1 0 sub bgcolor : lvalue { return( shift->bgColor( @_ ) ); }
58              
59             # Note: property cells read-only
60             sub cells
61             {
62 65     65 1 44492 my $self = shift( @_ );
63 65 100 100     324 return( $self->{_row_cells} ) if( $self->{_row_cells} && !$self->_is_row_reset );
64 62     34   226 my $list = $self->children->grep(sub{ $self->_is_a( $_ => 'HTML::Object::DOM::Element::TableCell' ) });
  34         2551  
65             # The content of the collection is refreshed, but the collection object itself does not change, so the user can poll it
66 62 100       9974 unless( $self->{_row_cells} )
67             {
68 6 50       49 $self->_load_class( 'HTML::Object::DOM::Collection' ) || return( $self->pass_error );
69 6   50     352 $self->{_row_cells} = HTML::Object::DOM::Collection->new ||
70             return( $self->pass_error( HTML::Object::DOM::Collection->error ) );
71             }
72 62         322 $self->{_row_cells}->set( $list );
73 62         894 $self->_remove_row_reset;
74 62         231 return( $self->{_row_cells} );
75             }
76              
77             # Note: deprecated property ch
78 0     0 1 0 sub ch : lvalue { return( shift->_set_get_property( 'ch', @_ ) ); }
79              
80             # Note: deprecated property chOff
81 0     0 1 0 sub chOff : lvalue { return( shift->_set_get_property( 'choff', @_ ) ); }
82              
83 0     0 1 0 sub choff : lvalue { return( shift->chOff( @_ ) ); }
84              
85             sub deleteCell
86             {
87 0     0 1 0 my $self = shift( @_ );
88 0         0 my $pos = shift( @_ );
89 0 0 0     0 return( $self->error({
      0        
90             message => "Value provided (" . overload::StrVal( $pos // '' ) . ") is not an integer.",
91             class => 'HTML::Object::IndexSizeError',
92             }) ) if( !defined( $pos ) || !$self->_is_integer( $pos ) );
93 0         0 my $cells = $self->cells;
94 0         0 my $size = $cells->cells;
95 0 0       0 return( $self->error({
96             message => "Value provided ($pos) is greater than the zero-based number of cells available (${size}).",
97             class => 'HTML::Object::IndexSizeError',
98             }) ) if( $pos > $size );
99 0 0 0     0 return( $self->error({
100             message => "Value provided ($pos) is lower than the zero-based number of cells available (${size}). If you want to specify a negative index, it must be between -1 and -${size}",
101             class => 'HTML::Object::IndexSizeError',
102             }) ) if( $pos < 0 && abs( $pos ) > $size );
103 0 0       0 $pos = ( $cells->length + $pos ) if( $pos < 0 );
104 0         0 my $elem = $cells->index( $pos );
105 0         0 my $children = $self->children;
106 0         0 my $kid_pos = $children->pos( $elem );
107 0 0       0 return( $self->error({
108             message => "Unable to find the cell element among this row children!",
109             class => 'HTML::Object::HierarchyRequestError',
110             }) ) if( !defined( $kid_pos ) );
111 0         0 $children->splice( $kid_pos, 1 );
112 0         0 $elem->parent( undef );
113 0         0 $self->reset(1);
114 0         0 return( $elem );
115             }
116              
117             sub insertCell
118             {
119 1     1 1 42679 my $self = shift( @_ );
120 1         3 my $pos = shift( @_ );
121 1         5 my $cells = $self->cells;
122 1         6 my $size = $cells->size;
123 1 50       40410 if( defined( $pos ) )
124             {
125 0 0 0     0 return( $self->error({
126             message => "Value provided (" . overload::StrVal( $pos // '' ) . ") is not an integer.",
127             class => 'HTML::Object::IndexSizeError',
128             }) ) if( !$self->_is_integer( $pos ) );
129 0 0       0 return( $self->error({
130             message => "Value provided ($pos) is greater than the zero-based number of cells available (${size}).",
131             class => 'HTML::Object::IndexSizeError',
132             }) ) if( $pos > $size );
133 0 0 0     0 return( $self->error({
134             message => "Value provided ($pos) is lower than the zero-based number of cells available (${size}). If you want to specify a negative index, it must be between -1 and -${size}",
135             class => 'HTML::Object::IndexSizeError',
136             }) ) if( $pos < 0 && abs( $pos ) > $size );
137 0 0       0 $pos = ( $cells->length + $pos ) if( $pos < 0 );
138             }
139 1 50       16 $self->_load_class( 'HTML::Object::DOM::Element::TableCell' ) || return( $self->pass_error );
140 1         67 my $children = $self->children;
141 1   50     105 my $cell = HTML::Object::DOM::Element::TableCell->new( @_ ) ||
142             return( $self->pass_error( HTML::Object::DOM::Element::TableCell->error ) );
143 1         19 $cell->close;
144             # A position was provided
145 1 50       6 if( defined( $pos ) )
146             {
147             # ..., but there are no cells yet
148 0 0       0 if( $cells->is_empty )
149             {
150 0         0 $children->push( $cell );
151             }
152             else
153             {
154 0         0 my $elem = $cells->index( $pos );
155 0 0       0 return( $self->error({
156             message => "No element could be found at row index $pos",
157             class => 'HTML::Object::HierarchyRequestError',
158             }) ) if( !defined( $elem ) );
159 0         0 my $kid_pos = $children->pos( $elem );
160 0 0       0 if( !defined( $kid_pos ) )
161             {
162 0         0 return( $self->error({
163             message => "Could not find a value at offset $pos (translated to $kid_pos among the row children) amazingly enough.",
164             class => 'HTML::Object::HierarchyRequestError',
165             }) );
166             }
167 0         0 $children->splice( $kid_pos, 0, $cell );
168             }
169             }
170             # otherwise, there are already other cells directly under <tr> and the new cell is just added at the end of the row.
171             else
172             {
173 1         7 $children->push( $cell );
174             }
175 1         18 $cell->parent( $self );
176 1         41 $self->reset(1);
177 1         6 return( $cell );
178             }
179              
180             sub reset
181             {
182 230     230 1 726 my $self = shift( @_ );
183 230 100       603 if( scalar( @_ ) )
184             {
185 62         265 $self->_reset_row;
186 62         276 return( $self->SUPER::reset( @_ ) );
187             }
188 168         673 return( $self );
189             }
190              
191             # Note: property rowIndex read-only
192             sub rowIndex
193             {
194 1     1 1 677 my $self = shift( @_ );
195 1   50     5 my $parent = $self->parent || return;
196 1         31 my $siblings = $parent->children;
197 1         86 my $pos = $siblings->pos( $self );
198 1         56 return( $pos );
199             }
200              
201             # Note: property sectionRowIndex read-only
202             sub sectionRowIndex
203             {
204 1     1 1 3 my $self = shift( @_ );
205 1   50     4 my $parent = $self->parent || return;
206 1 50       27 if( $self->_is_a( $parent => 'HTML::Object::DOM::Element::TableSection' ) )
207             {
208 1         44 return( $parent->children->pos( $self ) );
209             }
210 0         0 return;
211             }
212              
213             # Note: deprecated property vAlign
214 0     0 1 0 sub vAlign : lvalue { return( shift->_set_get_property( 'valign', @_ ) ); }
215              
216 0     0 1 0 sub valign : lvalue { return( shift->vAlign( @_ ) ); }
217              
218 59     59   376 sub _is_row_reset { return( CORE::length( shift->{_row_reset} ) ); }
219              
220 62     62   180 sub _remove_row_reset { return( CORE::delete( shift->{_row_reset} ) ); }
221              
222             sub _reset_row
223             {
224 62     62   133 my $self = shift( @_ );
225 62         167 $self->{_row_reset}++;
226             # Force it to recompute
227 62         242 $self->cells;
228 62 100       682 if( my $parent = $self->parent )
229             {
230 48 50       1387 $parent->_reset_section if( $parent->can( '_reset_section' ) );
231             }
232 62         418 return( $self );
233             }
234              
235             1;
236             # NOTE: POD
237             __END__
238              
239             =encoding utf-8
240              
241             =head1 NAME
242              
243             HTML::Object::DOM::Element::TableRow - HTML Object DOM TableRow Class
244              
245             =head1 SYNOPSIS
246              
247             use HTML::Object::DOM::Element::TableRow;
248             my $tablerow = HTML::Object::DOM::Element::TableRow->new ||
249             die( HTML::Object::DOM::Element::TableRow->error, "\n" );
250              
251             =head1 VERSION
252              
253             v0.2.0
254              
255             =head1 DESCRIPTION
256              
257             This interface provides special properties and methods (beyond the L<HTML::Object::DOM::Element> interface it also has available to it by inheritance) for manipulating the layout and presentation of rows (i.e. C<tr>) in an HTML table.
258              
259             =head1 INHERITANCE
260              
261             +-----------------------+ +---------------------------+ +-------------------------+ +----------------------------+ +--------------------------------------+
262             | HTML::Object::Element | --> | HTML::Object::EventTarget | --> | HTML::Object::DOM::Node | --> | HTML::Object::DOM::Element | --> | HTML::Object::DOM::Element::TableRow |
263             +-----------------------+ +---------------------------+ +-------------------------+ +----------------------------+ +--------------------------------------+
264              
265             =head1 PROPERTIES
266              
267             Inherits properties from its parent L<HTML::Object::DOM::Element>
268              
269             =head2 cells
270              
271             Read-only.
272              
273             Returns a L<collection|HTML::Object::DOM::Collection> containing the cells in the row, but only the ones directly under the row element.
274              
275             Note that for performance improvement, the collection is cached until changes are made that would affect the results.
276              
277             Example:
278              
279             <table id="myTable1">
280             <tr>
281             <td>
282             <table id="myTable2">
283             <tr><td></td></tr>
284             </table>
285             </td>
286             <td></td>
287             </tr>
288             </table>
289              
290             say getElementById('myTable1')->rows->[0]->cells->length; # 2
291             say getElementById('myTable2')->rows->[0]->cells->length; # 1
292              
293             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/cells>
294              
295             =head2 rowIndex
296              
297             Read-only.
298              
299             Returns a long value which gives the logical position of the row within the entire table. If the row is not part of a table, returns C<undef> (C<-1> under JavaScript).
300              
301             Example:
302              
303             <table>
304             <thead>
305             <tr><th>Item</th> <th>Price</th></tr>
306             </thead>
307             <tbody>
308             <tr><td>Bananas</td> <td>$2</td></tr>
309             <tr><td>Oranges</td> <td>$8</td></tr>
310             <tr><td>Top Sirloin</td> <td>$20</td></tr>
311             </tbody>
312             <tfoot>
313             <tr><td>Total</td> <td>$30</td></tr>
314             </tfoot>
315             </table>
316              
317             Another example:
318              
319             my $rows = $doc->querySelectorAll('tr');
320              
321             $rows->forEach(sub
322             {
323             my $row = shift( @_ );
324             my $z = $doc->createElement('td');
325             $z->textContent = "(row #" . $row->rowIndex . ")";
326             row->appendChild($z);
327             });
328              
329             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/rowIndex>
330              
331             =head2 sectionRowIndex
332              
333             Read-only.
334              
335             Returns a long value which gives the logical position of the row within the table section it belongs to. If the row is not part of a section, returns C<undef> (C<-1> under JavaScript).
336              
337             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/sectionRowIndex>
338              
339             =head1 METHODS
340              
341             Inherits methods from its parent L<HTML::Object::DOM::Element>
342              
343             =head2 deleteCell
344              
345             Removes the cell corresponding to the C<index> given in parameter. If the C<index> value is C<-1> the last cell is removed; if it smaller than C<-1> or greater than the amount of cells in the collection, an C<HTML::Object::IndexSizeError> is returned.
346              
347             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/deleteCell>
348              
349             =head2 insertCell
350              
351             Returns an L<HTML::Object::DOM::Element::TableCell> representing a new cell of the table. It inserts it in the L<cells collection|/cells> immediately before a C<td> or C<th> element at the given C<index> position, if any was provided.
352              
353             If the C<index> is not given or is C<-1>, the new cell is appended to the collection. If the C<index> is smaller than C<-1>, it will start that far back from the end of the collection array. If C<index> is greater than the number of cells in the collection, an C<HTML::Object::IndexSizeError> error is returned.
354              
355             Example:
356              
357             <table id="my-table">
358             <tr><td>Row 1</td></tr>
359             <tr><td>Row 2</td></tr>
360             <tr><td>Row 3</td></tr>
361             </table>
362              
363             sub addRow
364             {
365             my $tableID = shift( @_ );
366             # Get a reference to the table
367             my $tableRef = $doc->getElementById( $tableID );
368              
369             # Insert a row at the end of the table
370             my $newRow = $tableRef->insertRow( -1 );
371              
372             # Insert a cell in the row at index 0
373             my $newCell = $newRow->insertCell( 0 );
374              
375             # Append a text node to the cell
376             my $newText = $doc->createTextNode('New bottom row');
377             $newCell->appendChild( $newText );
378             }
379              
380             # Call addRow() with the table's ID
381             addRow( 'my-table' );
382              
383             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/insertCell>
384              
385             =head1 DEPRECATED PROPERTIES
386              
387             =head2 align
388              
389             Is a string containing an enumerated value reflecting the align attribute. It indicates the alignment of the element's contents with respect to the surrounding context. The possible values are "left", "right", and "center".
390              
391             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/align>
392              
393             =head2 bgColor
394              
395             Is a string containing the background color of the cells. It reflects the obsolete bgcolor attribute.
396              
397             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/bgColor>
398              
399             =head2 bgcolor
400              
401             Alias for L</bgColor>
402              
403             =head2 ch
404              
405             Is a string containing one single character. This character is the one to align all the cell of a column on. It reflects the char and default to the decimal points associated with the language, e.g. '.' for English, or ',' for French. This property was optional and was not very well supported.
406              
407             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/ch>
408              
409             =head2 chOff
410              
411             Is a string containing a integer indicating how many characters must be left at the right (for left-to-right scripts; or at the left for right-to-left scripts) of the character defined by L<HTML::Object::DOM::Element::C<TableRow>>.ch. This property was optional and was not very well supported.
412              
413             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/chOff>
414              
415             =head2 choff
416              
417             Alias for L</chOff>
418              
419             =head2 reset
420              
421             When called, this will set a boolean value indicating the cached data must be recomputed. This allow the saving of computational power,
422              
423             =head2 vAlign
424              
425             Is a string representing an enumerated value indicating how the content of the cell must be vertically aligned. It reflects the valign attribute and can have one of the following values: "top", "middle", "bottom", or "baseline".
426              
427             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/vAlign>
428              
429             =head2 valign
430              
431             Alias for L</vAlign>
432              
433             =head1 AUTHOR
434              
435             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
436              
437             =head1 SEE ALSO
438              
439             L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement>, L<Mozilla documentation on tablerow element|https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tablerow>
440              
441             =head1 COPYRIGHT & LICENSE
442              
443             Copyright(c) 2022 DEGUEST Pte. Ltd.
444              
445             All rights reserved
446              
447             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
448              
449             =cut