The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Template::Flute::Filter::JsonVar;

use strict;
use warnings;

use base 'Template::Flute::Filter';
use JSON;

=head1 NAME

Template::Flute::Filter::JsonVar - JSON to Javascript variable filter

=head1 DESCRIPTION

Takes a Perl structure or a JSON string and returns Javascript
which parses the JSON string with Jquery and assigns it to
the variable C<json>.

The following example shows you how to inject the JSON variable
into the template:

HTML Template:

    <script type="text/javascript" id="vars"></script>

XML Specification:

    <value name="jsvars" id="vars" filter="json_var"/>

Values for L<Template::Flute>:

    Template::Flute->new(...,
        values => {jsvars =>
          {username => 'shopper@nitesi.biz', city => 'Vienna'},
        },
    );

This results in the following JavaScript:

    <script type="text/javascript" id="vars">
    var json = $.parseJSON('{"city":"Vienna","username":"shopper@nitesi.biz"}');
    </script>

=head1 PREREQUISITES

L<JSON> module.

=head1 METHODS

=head2 init

The init method allows you to set the following options:

=over 4

=item engine

Value is either C<jquery> or C<eval>.

=back

=cut

sub init {
    my ($self, %args) = @_;

    $self->{engine} = $args{options}->{engine};
}

=head2 filter

Filters the given Perl structure to a JSON string.

=cut

sub filter {
    my ($self, $struct) = @_;
    my ($json);

    if (ref($struct)) {
        # turn into JSON first
        $json = to_json($struct, {pretty => 0});
    }
    else {
        $json = $struct;
    }

    unless ($self->{engine}) {
        die "No engine specified for json_var filter.";
    }

    if ($self->{engine} eq 'jquery') {
        return  q{
var json = $.parseJSON('}
        . _json_filter($json) . q{');};
    }

    if ($self->{engine} eq 'eval') {
        return  q{
var json = eval('(}
        . _json_filter($json) . q{)');};
    }
}

sub _json_filter {
    my $value = shift;

    return '' unless defined $value;

    # escape single quote
    $value =~ s!'!\\'!g;

    # other escapes - from Template::Plugin::JSON::Escape
    $value =~ s!&!\\u0026!g;
    $value =~ s!<!\\u003c!g;
    $value =~ s!>!\\u003e!g;
    $value =~ s!\+!\\u002b!g;
    $value =~ s!\x{2028}!\\u2028!g;
    $value =~ s!\x{2029}!\\u2029!g;
    $value;
}

1;