use 5.006;
use strict;
use warnings;
=head1 NAME
EJS::Template::JSAdapter::JavaScript
=cut
package EJS::Template::JSAdapter::JavaScript;
use base 'EJS::Template::JSAdapter';
use EJS::Template::Util qw(clean_text_ref);
use Scalar::Util qw(reftype);
our $ENCODE_UTF8 = 1;
our $SANITIZE_UTF8 = 1;
our $FORCE_UNTAINT = 1;
=head1 Methods
=head2 new
Creates an adapter object.
=cut
sub new {
my ($class) = @_;
eval 'use JavaScript';
die $@ if $@;
my $runtime = JavaScript::Runtime->new;
my $context = $runtime->create_context;
return bless {runtime => $runtime, context => $context}, $class;
}
=head2 bind
Implements the bind method.
=cut
sub bind {
my ($self, $variables) = @_;
my $context = $self->context;
my $assign_value;
my $assign_hash;
my $assign_array;
$assign_value = sub {
my ($parent_path, $name, $source_ref, $in_array) = @_;
my $reftype = reftype $$source_ref;
my $path = $parent_path ne '' ?
($in_array ? "$parent_path\[$name]" : "$parent_path.$name") : $name;
if ($reftype) {
if ($reftype eq 'HASH') {
#$context->bind_value($path, {});
JavaScript::Context::jsc_bind_value($context, $parent_path, $name, {});
$assign_hash->($path, $$source_ref);
} elsif ($reftype eq 'ARRAY') {
#$context->bind_value($path, []);
JavaScript::Context::jsc_bind_value($context, $parent_path, $name, []);
$assign_array->($path, $$source_ref);
} elsif ($reftype eq 'CODE') {
#$context->bind_function($path, $$source_ref);
JavaScript::Context::jsc_bind_value($context, $parent_path, $name, $$source_ref);
} elsif ($reftype eq 'SCALAR') {
$assign_value->($parent_path, $name, $$source_ref, $in_array);
} else {
# ignore?
}
} else {
# NOTE: Do NOT call a subroutine that takes $self as an argument here:
# E.g.
# some_routine($self);
# $self->some_method();
# If $self is passed as above, an odd memory leak occurs, detected by
# JavaScript::Context::DESTROY
#$context->bind_value($path, $$source_ref);
my $text_ref = clean_text_ref($source_ref, $ENCODE_UTF8, $SANITIZE_UTF8, $FORCE_UNTAINT);
JavaScript::Context::jsc_bind_value($context, $parent_path, $name, $$text_ref);
}
};
$assign_hash = sub {
my ($parent_path, $source) = @_;
for my $name (keys %$source) {
$assign_value->($parent_path, $name, \$source->{$name});
}
};
$assign_array = sub {
my ($parent_path, $source) = @_;
my $len = scalar(@$source);
for (my $i = 0; $i < $len; $i++) {
$assign_value->($parent_path, $i, \$source->[$i], 1);
}
};
$assign_hash->('', $variables);
return $context;
}
sub DESTROY {
my ($self) = @_;
$self->{context}->_destroy();
$self->{runtime}->_destroy();
delete $self->{context};
delete $self->{runtime};
}
=head1 SEE ALSO
=over 4
=item * L<EJS::Template>
=item * L<EJS::Template::JSAdapter>
=item * L<JavaScript>
=back
=cut
1;