-0.009006 2011-05-20
- - Add DESTROY method to fix test failures / warnings in perl >= 5.13.1
-
0.009005 2011-05-12
- Perforce escaping of meta-characters in selectors and test (rafl)
my $sel = $self->select($selector);
my $meth = our $AUTOLOAD;
$meth =~ s/.*:://;
- if(my $cr = $sel->_zconfig->filter_builder->can($meth)) {
+ if (ref($selector) eq 'HASH') {
+ my $ret = $self;
+ $ret = $ret->_do($_, $meth, @{$selector->{$_}}) for keys %$selector;
+ $ret;
+ } else {
+ $self->_do($selector, $meth, @args);
+ }
+}
+
+sub _do {
+ my ($self, $selector, $meth, @args) = @_;
+ my $sel = $self->select($selector);
+ if( my $cr = $sel->_zconfig->filter_builder->can($meth)) {
return $sel->$meth(@args);
} else {
die "We can't do $meth on ->select('$selector')";
$_->select('.name')->replace_content('Matt')
->select('.age')->replace_content('26')
},
+ # alternate form
sub {
- $_->select('.name')->replace_content('Mark')
- ->select('.age')->replace_content('0x29')
+ $_->replace_content({'.name' => ['Mark'],'.age' => ['0x29'] })
},
+ #alternate alternate form
sub {
- $_->select('.name')->replace_content('Epitaph')
- ->select('.age')->replace_content('<redacted>')
+ $_->replace_content('.name' => 'Epitaph')
+ ->replace_content('.age' => '<redacted>')
},
],
{ repeat_between => '.between' }
->add_to_attribute( for => $field->{id} )
->then
->replace_content( $field->{label} )
-
- ->select('input')
- ->add_to_attribute( name => $field->{name} )
- ->then
- ->add_to_attribute( type => $field->{type} )
- ->then
- ->add_to_attribute( value => $field->{value} )
-
+ ->add_to_attribute(
+ input => {
+ name => $field->{name},
+ type => $field->{type},
+ value => $field->{value}
+ })
} } @fields
]);
Jakub Nareski
-Simon Elliot
+Simon Elliott
Joe Highton
sub set_attribute {
my $self = shift;
- my ($name, $value) = $self->_parse_attribute_args(@_);
+ my $attr = $self->_parse_attribute_args(@_);
sub {
my $a = (my $evt = $_[0])->{attrs};
- my $e = exists $a->{$name};
+ my @kadd = grep {!exists $a->{$_}} keys %$attr;
+{ %$evt, raw => undef, raw_attrs => undef,
- attrs => { %$a, $name => $value },
- ($e # add to name list if not present
- ? ()
- : (attr_names => [ @{$evt->{attr_names}}, $name ]))
+ attrs => { %$a, %$attr },
+ @kadd ? (attr_names => [ @{$evt->{attr_names}}, @kadd ]) : ()
}
};
}
sub _parse_attribute_args {
my $self = shift;
- # allow ->add_to_attribute(name => 'value')
- # or ->add_to_attribute({ name => 'name', value => 'value' })
- die "WARNING: Long form arg (name => 'class', value => 'x') is deprecated"
+ warn "WARNING: Long form arg (name => 'class', value => 'x') is deprecated. This may not do what you originally intended..."
if(@_ == 1 && $_[0]->{'name'} && $_[0]->{'value'});
- my ($name, $value) = @_ > 1 ? @_ : @{$_[0]}{qw(name value)};
- return ($name, $self->_zconfig->parser->html_escape($value));
+
+ my $opts = ref($_[0]) eq 'HASH' ? $_[0] : {$_[0] => $_[1]};
+ for (values %{$opts}) { $self->_zconfig->parser->html_escape($_); }
+ return $opts;
}
sub add_attribute {
sub add_class { shift->add_to_attribute('class',@_) }
-sub remove_class { shift->remove_attribute('class',@_) }
+sub remove_class { shift->remove_from_attribute('class',@_) }
sub set_class { shift->set_attribute('class',@_) }
sub add_to_attribute {
my $self = shift;
- my ($name, $value) = $self->_parse_attribute_args(@_);
+ my $attr = $self->_parse_attribute_args(@_);
+ sub {
+ my $a = (my $evt = $_[0])->{attrs};
+ my @kadd = grep {!exists $a->{$_}} keys %$attr;
+ +{ %$evt, raw => undef, raw_attrs => undef,
+ attrs => {
+ %$a,
+ map {$_ => join(' ', (exists $a->{$_} ? $a->{$_} : ()), $attr->{$_}) }
+ keys %$attr
+ },
+ @kadd ? (attr_names => [ @{$evt->{attr_names}}, @kadd ]) : ()
+ }
+ };
+}
+
+sub remove_from_attribute {
+ my $self = shift;
+ my $attr = $self->_parse_attribute_args(@_);
sub {
my $a = (my $evt = $_[0])->{attrs};
- my $e = exists $a->{$name};
+{ %$evt, raw => undef, raw_attrs => undef,
attrs => {
%$a,
- $name => join(' ', ($e ? $a->{$name} : ()), $value)
+ #TODO needs to support multiple removes
+ map { my $tar = $_; $_ => join ' ',
+ map {$attr->{$tar} ne $_} split ' ', $a->{$_} }
+ grep {exists $a->{$_}} keys %$attr
},
- ($e # add to name list if not present
- ? ()
- : (attr_names => [ @{$evt->{attr_names}}, $name ]))
}
};
}
->select('p')
->set_attribute(class=>'paragraph')
->select('div')
- ->set_attribute({name=>'class', value=>'divider'});
-
+ ->set_attribute({class=>'paragraph', name=>'divider'});
Overrides existing values, if such exist. When multiple L</set_attribute>
calls are made against the same or overlapping selection sets, the final
Adds a value to an existing attribute, or creates one if the attribute does not
yet exist. You may call this method with either an Array or HashRef of Args.
-Here's the 'long form' HashRef:
-
$html_zoom
->select('p')
- ->set_attribute(class=>'paragraph')
- ->then
- ->add_to_attribute({name=>'class', value=>'divider'});
-
-And the exact same effect using the 'short form' Array:
-
- $html_zoom
- ->select('p')
- ->set_attribute(class=>'paragraph')
+ ->set_attribute({class => 'paragraph', name => 'test'})
->then
->add_to_attribute(class=>'divider');
->then
->remove_attribute('class');
+=head2 remove_from_attribute
+
+Removes a value from existing attribute
+
+ $html_zoom
+ ->select('p')
+ ->set_attribute(class=>'paragraph lead')
+ ->then
+ ->remove_from_attribute('class' => 'lead');
+
Removes attributes from the original stream or events already added.
+=head2 add_class
+
+Add to a class attribute
+
+=head2 remove_class
+
+Remove from a class attribute
+
=head2 transform_attribute
Transforms (or creates or deletes) an attribute by running the passed
sub AUTOLOAD {
my ($self, $selector, @args) = @_;
+ my $sel = $self->select($selector);
my $meth = our $AUTOLOAD;
$meth =~ s/.*:://;
- return $self = $self->select($selector)->$meth(@args);
+ if (ref($selector) eq 'HASH') {
+ my $ret = $self;
+ $ret = $ret->_do($_, $meth, @{$selector->{$_}}) for keys %$selector;
+ $ret;
+ } else {
+ $self->_do($selector, $meth, @args);
+ }
+}
+
+sub _do {
+ my ($self, $selector, $meth, @args) = @_;
+ return $self->select($selector)->$meth(@args);
}
sub DESTROY {}
-
+
1;
my $tmpl = <<END;
<body>
- <div class="main">
+ <div name="cow" class="main">
<span class="hilight name">Bob</span>
<span class="career">Builder</span>
<hr />
'set attribute on existing attribute'
);
+($expect = $tmpl) =~ s/name="cow" class="main"/name="bar" class="foo"/;
+
+is(
+ run_for { $_->set_attr({ 'class' => 'foo', 'name' => 'bar'}) },
+ $expect,
+ 'set attributes using hashref form (shorthand)'
+);
+
($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
is(
'add attribute on existing attribute'
);
+($expect = $tmpl) =~ s/class="main"/class="main foo"/;
+
+is(
+ run_for { $_->add_class('foo') },
+ $expect,
+ 'add attribute on existing attribute (shorthand)'
+);
+
+($expect = $tmpl) =~ s/class="main"/class="main" id="foo"/;
+
+is(
+ run_for { $_->set_id('foo') },
+ $expect,
+ 'set_id (shorthand)'
+);
+
($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
is(
'remove attribute on non existing attribute'
);
+($expect = $tmpl) =~ s/class="main"/class=""/;
+
+is(
+ run_for { $_->remove_from_attribute({ class => 'main' }) },
+ $expect,
+ 'remove name from attribute'
+);
+
+is(
+ run_for { $_->remove_from_attribute({ madeup => 'main' }) },
+ $tmpl,
+ 'remove name from non existing attribute (ignored)'
+);
+
+($expect = $tmpl) =~ s/class="main"/class=""/;
+
+is(
+ run_for { $_->remove_class( 'main' ) },
+ $expect,
+ 'remove_class'
+);
+
($expect = $tmpl) =~ s/ class="main"//;
is(
is(
HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
- '<div class="main">
+ '<div name="cow" class="main">
<span class="hilight name">Bob</span>
<span class="career">Builder</span>
<hr />
is(
run_for { $_->collect({ into => \@ev, content => 1 }) },
'<body>
- <div class="main"></div>
+ <div name="cow" class="main"></div>
</body>
',
'collect w/content removes correctly'
is(
run_for { $_->replace($ohai, { content => 1 }) },
'<body>
- <div class="main">O HAI</div>
+ <div name="cow" class="main">O HAI</div>
</body>
',
'replace w/content'
)
},
q{<body>
- <div class="main">
+ <div name="cow" class="main">
<span class="hilight name">mst</span>
<span class="career">Chainsaw Wielder</span>
<hr />
- </div><div class="main">
+ </div><div name="cow" class="main">
<span class="hilight name">mdk</span>
<span class="career">Adminion</span>
<hr />
)
},
q{<body>
- <div class="main">
+ <div name="cow" class="main">
<span class="hilight name">mst</span>
<span class="career">Chainsaw Wielder</span>
<hr />
)
},
q{<body>
- <div class="main">
+ <div name="cow" class="main">
<span class="hilight name">mst</span>
<span class="career">Chainsaw Wielder</span>
<hr />
)
},
q{<body>
- <div class="main">
+ <div name="cow" class="main">
<span class="hilight name">mst</span>
<span class="career">Chainsaw Wielder</span>
<hr />
'Got correct from repeat_content';
}
+{
+ ok my $dwim = HTML::Zoom
+ ->from_html(q[<ul><li class="foo"></li><li class="bar"></li></ul>])
+ ->replace_content({
+ 'li.foo' => ['foo'],
+ 'li.bar' => ['bar'],
+ })->to_html;
+ is $dwim, '<ul><li class="foo">foo</li><li class="bar">bar</li></ul>',
+ 'Hashref selectors (via replace_content)';
+}
+
+{
+ ok my $dwim = HTML::Zoom
+ ->from_html(q[<ul><li class="foo"></li><li class="bar"></li></ul>])
+ ->set_attribute({
+ 'li.foo' => [ class => 'baz' ],
+ 'li.bar' => [ class => 'qux' ],
+ })->to_html;
+ is $dwim, '<ul><li class="baz"></li><li class="qux"></li></ul>',
+ 'Hashref selectors (via set_attribute)';
+}
+
+{
+ ok my $dwim = HTML::Zoom
+ ->from_html(q[<ul><li class="foo"></li><li class="bar"></li></ul>])
+ ->select('ul')->collect({
+ passthrough => 1,
+ filter => sub {
+ $_->set_attribute({
+ 'li.foo' => [ class => 'baz' ],
+ 'li.bar' => [ class => 'qux' ],
+ });
+ }
+ })->to_html;
+ is $dwim, '<ul><li class="baz"></li><li class="qux"></li></ul>',
+ 'Hashref selectors on codestream';
+}
+
+{
+ ok my $dwim = HTML::Zoom
+ ->from_html(q[<ul><li class="foo" name="bar"></li><li class="bar"></li></ul>])
+ ->select('ul')->collect({
+ passthrough => 1,
+ filter => sub {
+ $_->set_attribute({
+ 'li.foo' => [{ class => 'baz', name => 'moo', }],
+ 'li.bar' => [ class => 'qux' ],
+ });
+ }
+ })->to_html;
+ is $dwim, '<ul><li class="baz" name="moo"></li><li class="qux"></li></ul>',
+ 'Hashref selectors with hashref attributes on codestream';
+}
+
done_testing;