NAME

HTML::Native::Attribute - An HTML element attribute

SYNOPSIS

use HTML::Native;

my $elem = HTML::Native->new (
  a => { class => "active", href => "/home" },
  "Home"
);
my $attr = $elem->{class};
$attr->{default} = 1;
print $attr;
# prints "active default"


use HTML::Native::Attribute;

my $attr = HTML::Native::Attribute->new ( [ qw ( active default ) ] );
$attr->{default} = 0;
print $attr;
# prints "active"

DESCRIPTION

An HTML::Native::Attribute object represents an HTML element attribute belonging to an HTML::Native object. It will be created automatically by HTML::Native as necessary; you probably do not ever need to manually create an HTML::Native::Attribute object.

You can treat an HTML::Native::Attribute object as a magic variable that provides access to the attribute value as either a string:

"active default"

or as an array:

[ "active", "default" ]

or as a hash

{ active => 1, default => 1 }

This allows you to always use the most natural way of accessing the attribute value.

The underlying stored value for the attribute will be converted between a scalar, a hash and an array as required.

GENERATED HTML (STRINGIFICATION)

You can treat the HTML::Native::Attribute object as a string in order to obtain the generated HTML. For example:

my $elem = HTML::Native->new (
  a => { class => [ qw ( active default ) ], href => "/home" },
  "Home"
);
my $attr = $elem->{class};
print $attr;
# prints "active default"

FROM A SCALAR

If the attribute is currently stored as a scalar, then it will be used verbatim as the stringified value.

FROM AN ARRAY

If the attribute is currently stored as an array, then the stringified value will be the space-separated members of the array. For example, if the attribute is currently stored as

[ active default ]

then the stringified value will be

"active default"

FROM A HASH

If the attribute is currently stored as a hash, then the stringified value will be the sorted, space-separated keys of the hash corresponding to true values. For example, if the attribute is currently stored as

{ active => 1, default => 1, error => 0 }

then the stringified value will be

"active default"

ACCESS AS A HASH

You can treat the HTML::Native::Attribute object as a hash in order to test or set individual values within the attribute. For example:

if ( $elem->{class}->{error} ) {
   ...
}

$elem->{class}->{fatal} = 1;

This makes sense only for attributes such as class which consist of a set of individual values. It does not make sense to treat an attribute such as href or onclick as a hash.

FROM A SCALAR

If the attribute is currently stored as a scalar, then it will be converted into a hash using the current value as the hash key. For example, if the attribute is currently stored as

"active"

then it will be converted to the hash

{ active => 1 }

FROM AN ARRAY

If the attribute is currently stored as an array, then it will be converted into a hash using the array members as the hash keys. For example, if the attribute is currently stored as

[ "active", "default" ]

then it will be converted to the hash

{ active => 1, default => 1 }

Note that this conversion is potentially destructive, since it will lose information about the order of the array members and will implicitly eliminate any duplicates. You should therefore only use hash access for attributes such as class for which the order of individual values is irrelevant.

ACCESS AS AN ARRAY

You can treat the HTML::Native::Attribute object as an array. For example:

    push @{$elem->{onclick}},
	"alert('Clicked');",
	"return false;"

    push @{$elem->{class}}, "active";

FROM A SCALAR

If the attribute is currently stored as a scalar, then it will be converted into an array using the current value as the array member. For example, if the attribute is currently stored as

"active"

then it will be converted to the array

[ "active" ]

FROM A HASH

If the attribute is currently stored as a hash, then it will be converted into an array of the sorted keys of the hash corresponding to true values. For example, if the attribute is currently stored as

{ active => 1, default => 1, error => 0 }

then it will be converted to the array

[ "active", "default" ]

NOTES

For attributes such as class that you may want to access as a hash, you should avoid directly storing the value as a space-separated string. For example, do not use:

$elem->{class} = "active default";

since that would end up being converted into the hash

{ "active default" => 1 }

rather than

{ active => 1, default => 1 }

To store multiple values, use either an array:

$elem->{class} = [ qw ( active default ) ];

or a hash

$elem->{class} = { active => 1, default => 1 };

ADVANCED

DYNAMIC GENERATION

You can use anonymous subroutines (closures) to dynamically generate attribute values. For example:

    my $url;
    my $elem = HTML::Native->new (
      a => {
	class => "active",
	href => sub { return $url; },
      },
      "Home"
    );
    $url = "/home";
    print $elem;
    # prints "<a class="active" href="/home">Home</a>"

The subroutine can return either a fully-constructed HTML::Native::Attribute object, or a value that could be passed to HTML::Native::Attribute->new(). For example:

    sub {
      return HTML::Native::Attribute::ReadOnly->new (
	[ active default ]
      );
    }

or

sub {
  return ( [ active default ] );
}

A dynamically generated attribute value can still be accessed as a hash or as an array. For example:

    my $elem = HTML::Native->new (
      a => {
	class => sub { return ( [ active default ] ) },
	href => "/home",
      },
      "Home"
    );
    print "Active" if $elem->{class}->{active};   # prints "Active"

HTML::Native::Attribute has no way to inform the anonymous subroutine that its returned value should change. For example:

my $attr = HTML::Native::Attribute->new ( sub {
  my @classes = ( qw ( active default ) );
  return [ @classes ];
} );

print $attr;  # prints "active default"
$attr->{active} = 0;  # <-- PROBLEM!

The dynamically generated attribute will therefore be marked as a read-only hash or array:

$attr->{active} = 0;  # will die with an error message

If your anonymous subroutine returns a fully-constructed HTML::Native::Attribute object, then it should probably use HTML::Native::Attribute::ReadOnly to ensure this behaviour. For example:

    sub {
      return HTML::Native::Attribute::ReadOnly->new (
	[ active default ]
      );
    }