Template-Lace

 view release on metacpan or  search on metacpan

lib/Template/Lace/DOM.pm  view on Meta::CPAN

use strict;
use warnings;
package Template::Lace::DOM;

use base 'Mojo::DOM58';
use Storable ();
use Scalar::Util;
use Template::Tiny;

# General Helpers

my $tt = Template::Tiny->new;

sub tt {
  my ($dom, @proto) = @_;
  my %vars = ref($proto[0]) eq 'HASH' ? %{$proto[0]} : @proto;
  $tt->process( \$dom->content, \%vars, \$dom->tree->[-1][1] ); # only works in some cases
  return $dom;
}

sub ctx {
  my $self = shift;
  local $_ = $self;
  if(ref($_[0]) eq 'ARRAY') {
    push @{$_[0]}, $_[1]->($self, @_[2..$#_]);
  } else {
    $_[0]->($self, @_[1..$#_]);
  }
  return $self;
}

sub clone {
  return Storable::dclone(shift);
}

sub overlay {
  my ($self, $cb, @args) = @_;
  local $_ = $self;
  my $overlay_dom = $cb->($self, @args);
  $self->replace($overlay_dom);
}

sub wrap_with {
  my ($self, $new, $target) = @_;
  $target ||= '#content';
  $self->overlay(sub {
    $new->at($target)
      ->content($self);
    return $new;
  });
}

sub repeat {
  my ($self, $cb, @items) = @_;
  my $index = 0;
  my @nodes = map {
    my $context = $_;
    my $cloned_dom = $self->clone;
    my $returned_dom = $cb->($cloned_dom, $context, $index);
    $returned_dom;
  } @items;

  #$self->parent->content('');
  $self->_replace(
    Mojo::DOM58::_parent($self->tree), 
    $self->tree, 
    [map { $_->tree } @nodes],
  );

  #$self->replace(join '', @nodes);
  return $self;
}

sub smart_content {
  my ($self, $data) = @_;
  if($self->tag eq 'input') {
    if((ref($data)||'') eq 'HASH') {
      if(exists($data->{selected})) {
        $data->{selected} = 'on';
      }
      $self->attr($data);
    } else {
      if(($self->attr('type')||'') eq 'checkbox') {
        $self->boolean_attribute_helper('checked', $data);
      } else {
        $self->attr(value=>$data);
      }
    }
  } elsif($self->tag eq 'option') {
    if((ref($data)||'') eq 'HASH') {
      $self->attr(value=>$data->{value});
      $self->attr(selected=>'on') if $data->{selected};
      $self->content(escape_html($data->{content}));
    } else {
      $self->attr(value=>$data);
      $self->content(escape_html($data));
    }
  } elsif($self->tag eq 'optgroup' and (ref($data) eq 'HASH')) {
    $self->attr(label=>escape_html($data->{label}));
    if(my $option_dom = $self->at('option')) {
      $option_dom->fill($data->{options});
    } else {
      warn "optgroup with no options."
    }
  } else {
    $self->content(escape_html($data));

lib/Template/Lace/DOM.pm  view on Meta::CPAN

}


1;

=head1 NAME

Template::Lace::DOM - DOM searching and tranformation engine

=head1 SYNOPSIS

    sub process_dom {
      my ($self, $dom) = @_;
      $dom->body($self->body);
    }

=head1 DESCRIPTION

L<Template::Lace::DOM> is a subclass of L<Mojo::DOM58> that exists to abstract
the DOM engine used by L<Template::Lace> as well as to provide some helper methods
intended to make the most common types of transformations on your DOM easier.

The helper API described here is one of the more 'under consideration / development'
parts of L<Template::Lace> since without a lot of usage in the wild its a bit hard
to be sure exactly what type of helpers and in what form are most useful.  Take
the follower API with regard to the fact I will change things if necessary.

=head1 GENERAL HELPER METHODS

This class defines the following methods for general use

=head2 clone

Uses L<Storable> C<dclone> to clone the current DOM.

=head2 ctx

Execute a DOM under a given data context, return DOM.  Example

    my $dom = Template::Lace::DOM->new(qq[
      <section>
        <p id='story'>...</p>
      </section>
    ]);

    $dom->ctx(sub {
          my ($self, $data) = @_;
          $_->at('#story')->content($data);
        }, "Don't look down")
      ->... # more commands on $dom;

Returns:

      <section>
        <p id='story'>Don&#39;t look down'</p>
      </section>

Isolate running transformaions on a DOM to explicit data.  Makes it easier to create
reusable snips of transformations.

=head2 overlay

Overlay the current DOM with a new one.  Examples a coderef that should return the
new DOM and any additional arguments you want to pass to the coderef.  Example;

    my $dom = Template::Lace::DOM->new(qq[
      <h1 id="title">HW</h1>
      <section id="body">Hello World</section>
      </html>
    ]);

    $dom->overlay(sub {
      my ($dom, $now) = @_; # $dom is also localized to $_
      my $new_dom = Template::Lace::DOM->new(qq[
        <html>
          <head>
            <title>PAGE_TITLE</title>
          </head>
          <body>
            STUFF
          </body>
        </html>
      ]);

      $new_dom->title($dom->at('#title')->content)
        ->body($dom->at('#body'))
        ->at('head')
        ->append_content("<meta startup='$now'>");

      return $new_dom;
    }, scalar(localtime));

Returns example:

    <html>
      <head>
        <title>HW</title>
      <meta startup="Fri Apr 21 15:45:49 2017"></head>
      <body>Hello World</body>
    </html>

Useful to encapsulate a lot of the work when you want to apply a standard
layout to a web page or section there of.

=wrap_with 

Makes it easier to wrap a current DOM with a 'layout' DOM.  Layout DOM
replaces original.  Example

    my $master = Template::Lace::DOM->new(qq[
      <html>
        <head>
          <title></title>
        </head>
        <body id="content">
        </body>
      </html>
    ]);

    my $inner = Template::Lace::DOM->new(qq[
      <h1>Hi</h1>
      <p>This is a test of the emergency broadcasting networl</p>
    ]);

    $inner->wrap_with($master)
      ->title('Wrapped');

    print $inner;

Returns:

    <html>



( run in 1.225 second using v1.01-cache-2.11-cpan-ceb78f64989 )