]> iEval git - html-element-library.git/blobdiff - lib/HTML/Element/Library.pm
doc fix (thanks Gary)
[html-element-library.git] / lib / HTML / Element / Library.pm
index 60c7a4a19b91218ce357d8851a36a17284882e74..cf49bfcb793ca29399d94dca4759ca81575d9454 100644 (file)
@@ -37,6 +37,21 @@ sub HTML::Element::siblings {
   $p->content_list;
 }
 
   $p->content_list;
 }
 
+sub HTML::Element::defmap {
+    my($tree,$attr,$hashref,$debug)=@_;
+
+    while (my ($k, $v) = (each %$hashref)) {
+       warn "defmap looks for ($attr => $k)" if $debug;
+       my $found = $tree->look_down($attr => $k);
+       if ($found) {
+           warn "($attr => $k) was found.. replacing with '$v'" if $debug;
+           $found->replace_content( $v );
+       }
+    }
+
+}
+
+
 sub HTML::Element::hash_map {
     my $container = shift;
 
 sub HTML::Element::hash_map {
     my $container = shift;
 
@@ -49,7 +64,7 @@ sub HTML::Element::hash_map {
 
     warn 'The container tag is ', $container->tag if $p{debug} ;
     warn 'hash' . Dumper($p{hash}) if $p{debug} ;
 
     warn 'The container tag is ', $container->tag if $p{debug} ;
     warn 'hash' . Dumper($p{hash}) if $p{debug} ;
-    warn 'at_under' . Dumper(\@_);
+    warn 'at_under' . Dumper(\@_) if $p{debug} ;
 
     my @same_as = $container->look_down( $p{to_attr} => qr/.+/ ) ;
 
 
     my @same_as = $container->look_down( $p{to_attr} => qr/.+/ ) ;
 
@@ -68,14 +83,26 @@ sub HTML::Element::hash_map {
 
 }
 
 
 }
 
+sub HTML::Element::hashmap {
+    my ($container, $attr_name, $hashref, $excluding, $debug) = @_;
+
+    $excluding ||= [] ;
+
+    $container->hash_map(hash => $hashref, 
+                          to_attr => $attr_name,
+                          excluding => $excluding,
+                          debug => $debug);
+
+}
+
 
 sub HTML::Element::passover {
 
 sub HTML::Element::passover {
-  my ($tree, $child_id) = @_;
+  my ($tree, @to_preserve) = @_;
   
   
-  warn "ARGS:   my ($tree, $child_id)" if $DEBUG;
+  warn "ARGS:   my ($tree, @to_preserve)" if $DEBUG;
   warn $tree->as_HTML(undef, ' ') if $DEBUG;
 
   warn $tree->as_HTML(undef, ' ') if $DEBUG;
 
-  my $exodus = $tree->look_down(id => $child_id);
+  my $exodus = $tree->look_down(id => $to_preserve[0]);
 
   warn "E: $exodus" if $DEBUG;
 
 
   warn "E: $exodus" if $DEBUG;
 
@@ -83,7 +110,7 @@ sub HTML::Element::passover {
 
   for my $s (@s) {
     next unless ref $s;
 
   for my $s (@s) {
     next unless ref $s;
-    if ($s->attr('id') eq $child_id) {
+    if (first { $s->attr('id') eq $_ } @to_preserve) {
       ;
     } else {
       $s->delete;
       ;
     } else {
       $s->delete;
@@ -175,7 +202,6 @@ sub HTML::Element::iter {
   my @item = map {
     my $new_item = clone $p;
     $new_item->replace_content($_);
   my @item = map {
     my $new_item = clone $p;
     $new_item->replace_content($_);
-    #    $new_item->attr('id', $id_incr->( $p->attr('id') ));
     $new_item;
   } @data;
 
     $new_item;
   } @data;
 
@@ -656,24 +682,33 @@ sub HTML::Element::unroll_select {
 
   my $select = {};
 
 
   my $select = {};
 
+  warn "Select Hash: " . Dumper(\%select) if $select{debug};
+
   my $select_node = $s->look_down(id => $select{select_label});
   my $select_node = $s->look_down(id => $select{select_label});
+  warn "Select Node: " . $select_node if $select{debug};
 
 
-  my $option = $select_node->look_down('_tag' => 'option');
+  unless ($select{append}) {
+      for my $option ($select_node->look_down('_tag' => 'option')) {
+         $option->delete;
+      }
+  }
 
 
-#  warn $option;
 
 
+  my $option = HTML::Element->new('option');
+  warn "Option Node: " . $option if $select{debug};
 
   $option->detach;
 
   while (my $row = $select{data_iter}->($select{data}))
     {
 
   $option->detach;
 
   while (my $row = $select{data_iter}->($select{data}))
     {
-#      warn Dumper($row);
-      my $o = $option->clone;
-      $o->attr('value', $select{option_value}->($row));
-      $o->attr('SELECTED', 1) if ($select{option_selected}->($row)) ;
-
-      $o->replace_content($select{option_content}->($row));
-      $select_node->push_content($o);
+       warn "Data Row:" . Dumper($row) if $select{debug};
+       my $o = $option->clone;
+       $o->attr('value', $select{option_value}->($row));
+       $o->attr('SELECTED', 1) if (exists $select{option_selected} and $select{option_selected}->($row)) ;
+
+       $o->replace_content($select{option_content}->($row));
+       $select_node->push_content($o);
+       warn $o->as_HTML if $select{debug};
     }
 
 
     }
 
 
@@ -762,30 +797,115 @@ One of these days, I'll around to writing a nice C<EXPORT> section.
 
 =head2 Tree Rewriting Methods
 
 
 =head2 Tree Rewriting Methods
 
-=head3 $elem->hash_map(hash => \%h, to_attr => $attr, excluding => \@excluded)
+=head3 Mapping a hashref to HTML elements
+
+It is very common to get a hashref of data from some external source - flat file, database, XML, etc.
+Therefore, it is important to have a convenient way of mapping this data to HTML.
+
+As it turns out, there are 3 ways to do this in HTML::Element::Library. 
+The most strict and structured way to do this is with 
+C<content_handler>. Two other methods, C<hashmap> and C<datamap> require less manual mapping and may prove
+even more easy to use in certain cases.
+
+As is usual with Perl, a practical example is always best. So let's take some sample HTML:
+
+  <h1>user data</h1>
+  <span id="name">?</span> 
+  <span id="email">?</span> 
+  <span id="gender">?</span> 
+
+Now, let's say our data structure is this:
+
+  $ref = { email => 'jim@beam.com', gender => 'lots' } ;
+
+And let's start with the most strict way to get what you want:
+
+ $tree->content_handler(email => $ref->{email} , gender => $ref->{gender}) ;
+
+
+In this case, you manually state the mapping between id tags and hashref keys and
+then C<content_handler> retrieves the hashref data and pops it in the specified place.
+
+Now let's look at the two (actually 2 and a half) other hash-mapping methods. 
+
+ $tree->hashmap(id => $ref);
+
+Now, what this function does is super-destructive. It finds every element in the tree
+with an attribute named id (since 'id' is a parameter, it could find every element with
+some other attribute also) and replaces the content of  those elements with the hashref 
+value.
+
+So, in the case above, the 
+
+   <span id="name">?</span> 
+
+would come out as
+
+  <span id="name"></span> 
+
+(it would be blank) - because there is nothing in the hash with that value, so it substituted
+
+  $ref->{name} 
+
+which was blank and emptied the contents.
+
+Now, let's assume we want to protect name from being auto-assigned. Here is what you do:
+
+ $tree->hashmap(id => $ref, ['name']);
+
+That last array ref is an exclusion list. 
+
+But wouldnt it be nice if you could do a hashmap, but only assigned things which are defined
+in the hashref? C<< defmap() >> to the rescue:
+
+ $tree->defmap(id => $ref);
+
+does just that, so 
+
+   <span id="name">?</span> 
+
+would be left alone.
+
+
+=head4 $elem->hashmap($attr_name, \%hashref, \@excluded, $debug)
 
 This method is designed to take a hashref and populate a series of elements. For example:
 
 
   <table>
     <tr sclass="tr" class="alt" align="left" valign="top">
 
 This method is designed to take a hashref and populate a series of elements. For example:
 
 
   <table>
     <tr sclass="tr" class="alt" align="left" valign="top">
-      <td sid="people_id">1</td>
-      <td sid="phone">(877) 255-3239</td>
-      <td sid="password">*********</td>
+      <td smap="people_id">1</td>
+      <td smap="phone">(877) 255-3239</td>
+      <td smap="password">*********</td>
     </tr>
   </table>
 
     </tr>
   </table>
 
-In the table above, there are several attributes named C<sid>. If we have a hashref whose keys are the same:
+In the table above, there are several attributes named C<< smap >>. If we have a hashref whose keys are the same:
 
   my %data = (people_id => 888, phone => '444-4444', password => 'dont-you-dare-render');
 
 Then a single API call allows us to populate the HTML while excluding those ones we dont:
 
 
   my %data = (people_id => 888, phone => '444-4444', password => 'dont-you-dare-render');
 
 Then a single API call allows us to populate the HTML while excluding those ones we dont:
 
-  $tree->hash_map(hash => \%data, to_attr => 'sid', excluding => ['password']);
+  $tree->hashmap(smap => \%data, ['password']);
 
 
-Of course, the other way to prevent rendering some of the hash mapping is to not give that element the attr
+
+Note: the other way to prevent rendering some of the hash mapping is to not give that element the attr
 you plan to use for hash mapping.
 
 you plan to use for hash mapping.
 
+Also note: the function C<< hashmap >> has a simple easy-to-type API. Interally, it calls C<< hash_map >>
+(which has a more verbose keyword calling API). Thus, the above call to C<hashmap()> results in this call:
+
+  $tree->hash_map(hash => \%data, to_attr => 'sid', excluding => ['password']);
+
+=head4 $elem->defmap($attr_name, \%hashref, $debug)
+
+C<defmap> was described above.
+
+
+=head4 $elem->content_handler(%hashref)
+
+C<content_handler> is described below.
+
 
 =head3 $elem->replace_content(@new_elem)
 
 
 =head3 $elem->replace_content(@new_elem)
 
@@ -820,7 +940,7 @@ Instead of typing:
 
   $elem->set_child_content(sid => 'fixme', 'new text') 
 
 
   $elem->set_child_content(sid => 'fixme', 'new text') 
 
-PLEASE NOTE: you can pass a hash whose keys are C<id>s and whose values are the content you want there and it will perform the replacement on each hash member:
+ALSO NOTE: you can pass a hash whose keys are C<id>s and whose values are the content you want there and it will perform the replacement on each hash member:
 
   my %id_content = (name => "Terrence Brannon",      
                     email => 'tbrannon@in.com',
 
   my %id_content = (name => "Terrence Brannon",      
                     email => 'tbrannon@in.com',
@@ -874,14 +994,16 @@ id C<under10> remains. For age less than 18, the node with id C<under18>
 remains.
 Otherwise our "else" condition fires and the child with id C<welcome> remains.
 
 remains.
 Otherwise our "else" condition fires and the child with id C<welcome> remains.
 
-=head3 $tree->passover($id_of_element)
+=head3 $tree->passover(@id_of_element)
 
 
-In some cases, you know exactly which element should survive. In this case,
-you can simply call C<passover> to remove it's siblings. For the HTML
+In some cases, you know exactly which element(s) should survive. In this case,
+you can simply call C<passover> to remove it's (their) siblings. For the HTML
 above, you could delete C<under10> and C<welcome> by simply calling:
 
   $tree->passover('under18');
 
 above, you could delete C<under10> and C<welcome> by simply calling:
 
   $tree->passover('under18');
 
+Because passover takes an array, you can specify several children to preserve.
+
 =head3 $tree->highlander2($tree, $conditionals, @conditionals_args)
 
 Right around the same time that C<table2()> came into being, Seamstress
 =head3 $tree->highlander2($tree, $conditionals, @conditionals_args)
 
 Right around the same time that C<table2()> came into being, Seamstress
@@ -1059,6 +1181,17 @@ To produce this:
   </body>
  </html>
 
   </body>
  </html>
 
+Now, you might be wondering why the API call is:
+  $tree->iter($li => @items)
+
+instead of:
+
+  $li->iter(@items)
+
+and there is no good answer. The latter would be more concise and it is what I 
+should have done.
+
 =head3 Unrolling an array via n sample elements (<dl> container)
 
 C<iter()> was fine for awhile, but some things
 =head3 Unrolling an array via n sample elements (<dl> container)
 
 C<iter()> was fine for awhile, but some things
@@ -1229,6 +1362,8 @@ The C<unroll_select> method has this API:
       option_selected => $closure, # boolean to decide if SELECTED
       data         => $data        # the data to be put into the SELECT
       data_iter    => $closure     # the thing that will get a row of data
       option_selected => $closure, # boolean to decide if SELECTED
       data         => $data        # the data to be put into the SELECT
       data_iter    => $closure     # the thing that will get a row of data
+      debug  => $boolean,
+      append => $boolean,   # remove the sample <OPTION> data or append?
     );
 
 Here's an example:
     );
 
 Here's an example:
@@ -1239,8 +1374,10 @@ Here's an example:
    option_content   => sub { my $row = shift; $row->clan_name },
    option_selected  => sub { my $row = shift; $row->selected },
    data             => \@query_results, 
    option_content   => sub { my $row = shift; $row->clan_name },
    option_selected  => sub { my $row = shift; $row->selected },
    data             => \@query_results, 
-   data_iter        => sub { my $data = shift; $data->next }
- )
+   data_iter        => sub { my $data = shift; $data->next },
+   append => 0,
+   debug => 0
+ );
 
 
 
 
 
 
@@ -1714,12 +1851,14 @@ down instead:
 
 L<HTML::Seamstress>
 
 
 L<HTML::Seamstress>
 
-=head1 AUTHOR
+=head1 AUTHOR / SOURCE
 
 Terrence Brannon, E<lt>tbone@cpan.orgE<gt>
 
 Many thanks to BARBIE for his RT bug report.
 
 
 Terrence Brannon, E<lt>tbone@cpan.orgE<gt>
 
 Many thanks to BARBIE for his RT bug report.
 
+The source is at L<http://github.com/metaperl/html-element-library/tree/master>
+
 =head1 COPYRIGHT AND LICENSE
 
 Copyright (C) 2004 by Terrence Brannon
 =head1 COPYRIGHT AND LICENSE
 
 Copyright (C) 2004 by Terrence Brannon
This page took 0.037385 seconds and 4 git commands to generate.