ASP4x-Linker

 view release on metacpan or  search on metacpan

META.yml  view on Meta::CPAN

--- #YAML:1.0
name:               ASP4x-Linker
version:            1.003
abstract:           In-page persistence of widget-specific variables.
author:
    - John Drago <jdrago_999@yahoo.com>
license:            perl
distribution_type:  module
test_requires:
    Test::More:       0
requires:
    Carp:             0
    ASP4:             1.044
    Router::Generic:  0.016
recommends:
    Apache2::RequestRec: 0
no_index:
    directory:

inc/Module/Install/Metadata.pm  view on Meta::CPAN

	$ISCORE  = 1;
	@ISA     = qw{Module::Install::Base};
}

my @scalar_keys = qw{
	name
	module_name
	abstract
	author
	version
	distribution_type
	tests
	installdirs
};

my @tuple_keys = qw{
	configure_requires
	build_requires
	requires
	recommends
	bundles

inc/Module/Install/Metadata.pm  view on Meta::CPAN

	while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) {
		$self->feature( $name, @$mods );
	}
	return $self->{values}{features}
		? @{ $self->{values}{features} }
		: ();
}

sub no_index {
	my $self = shift;
	my $type = shift;
	push @{ $self->{values}{no_index}{$type} }, @_ if $type;
	return $self->{values}{no_index};
}

sub read {
	my $self = shift;
	$self->include_deps( 'YAML::Tiny', 0 );

	require YAML::Tiny;
	my $data = YAML::Tiny::LoadFile('META.yml');

lib/ASP4x/Linker.pm  view on Meta::CPAN

{
  my ($s, $args) = @_;
  
  my $vars = $s->vars( $args, 1 );
  
  no warnings 'uninitialized';
  my ($uri) = split /\?/, $s->base_href;
  my $context = ASP4::HTTPContext->current;
  my $server = $context->server;

  my @inputs = map {qq(<input type="hidden" name="@{[ $server->URLEncode( $_ ) ]}" value="@{[ $server->URLEncode( $vars->{$_} ) ]}" />)}
                 keys %$vars;
  return join "\n", @inputs;
}# end hidden_fields()


sub vars
{
  my ($s, $args) = @_;
  
  my @parts = ( );

lib/ASP4x/Linker.pm  view on Meta::CPAN

=item * The incoming form data from the original request

=item * Individually-set values for each widget in the collection.

=item * Any properties provided as an argument to C<uri()>.

=back

=head2 hidden_fields( [$properties] )

Returns a string of XHTML hidden input fields (<input type="hidden" name="$name" value="$value" />).

Useful if your persistence logic involves repeated form submissions rather than hyperlinks.

The C<$properties> argument is the same as in the C<uri()> method.

=head2 vars( [$properties] )

Returns a hashref representing the intersect of all widgets' names and attributes.

Supposing you setup your linker like this:

t/010-basic/020-basic.t  view on Meta::CPAN

        "widgetB" => {
           "page_size"    => undef,
           "sort_col"     => undef,
           "sort_dir"     => undef,
           "page_number"  => undef
        }
     },
     {
        "widgetC" => {
           "color"  => undef,
           "type"   => undef,
           "size"   => undef
        }
     },
     {
        "widgetD" => {
           "color"  => undef,
           "type"   => undef,
           "size"   => undef
        }
     }
  ], "Data structure looks right";
};

T1: {
  ok( my $res = $api->ua->get('/?widgetA.page_size=1&widgetB.page_size=2&widgetC.color=red&widgetD.size=large'), "GET /" );
  ok( my $info = decode_json($res->content), "JSON is good" );
  is_deeply $info, [

t/010-basic/020-basic.t  view on Meta::CPAN

        "widgetB" => {
           "page_size" => 2,
           "sort_col" => undef,
           "sort_dir" => undef,
           "page_number" => undef
        }
     },
     {
        "widgetC" => {
           "color" => 'red',
           "type" => undef,
           "size" => undef
        }
     },
     {
        "widgetD" => {
           "color" => undef,
           "type" => undef,
           "size" => 'large'
        }
     }
  ], "Data structure looks right";
};

T2: {
  ok( my $res = $api->ua->get('/?widgetA.page_size=20&widgetA.page_number=40&widgetA.sort_col=name&widgetA.sort_dir=DESC&widgetB.page_size=10&widgetB.page_number=100&widgetB.sort_col=date&widgetB.sort_dir=ASC&widgetC.color=red&widgetC.type=shirt&widg...
  ok( my $info = decode_json($res->content), "JSON is good" );
  is_deeply $info, [
     {
        "widgetA" => {
           "page_size"    => 20,
           "sort_col"     => 'name',
           "sort_dir"     => 'DESC',
           "page_number"  => 40
        }
     },

t/010-basic/020-basic.t  view on Meta::CPAN

        "widgetB" => {
           "page_size"    => 10,
           "sort_col"     => 'date',
           "sort_dir"     => 'ASC',
           "page_number"  => 100
        }
     },
     {
        "widgetC" => {
           "color"  => 'red',
           "type"   => 'shirt',
           "size"   => 'small'
        }
     },
     {
        "widgetD" => {
           "color"  => 'black',
           "type"   => 'hat',
           "size"   => 'large'
        }
     }
  ], "Data structure looks right";
};


t/010-basic/030-vars.t  view on Meta::CPAN

    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetB",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetC",
    attrs => [qw/ size type color /]
  );

  $linker->add_widget(
    name  => "widgetD",
    attrs => [qw/ size type color /]
  );

  is_deeply
    $linker->vars(undef, 1), {
    'widgetB.page_number' => undef,
    'widgetC.type' => undef,
    'widgetD.size' => undef,
    'widgetA.page_size' => undef,
    'widgetB.sort_dir' => undef,
    'widgetC.size' => undef,
    'widgetD.color' => undef,
    'widgetD.type' => undef,
    'widgetA.page_number' => undef,
    'widgetA.sort_col' => undef,
    'widgetB.sort_col' => undef,
    'widgetC.color' => undef,
    'widgetA.sort_dir' => undef,
    'widgetB.page_size' => undef
  }, "Default";


  $linker->widget('widgetA')->set( page_size => 10 );
  is_deeply
    $linker->vars(undef, 1), {
    'widgetB.page_number' => undef,
    'widgetC.type' => undef,
    'widgetD.size' => undef,
    'widgetA.page_size' => 10,
    'widgetB.sort_dir' => undef,
    'widgetC.size' => undef,
    'widgetD.color' => undef,
    'widgetD.type' => undef,
    'widgetA.page_number' => undef,
    'widgetA.sort_col' => undef,
    'widgetB.sort_col' => undef,
    'widgetC.color' => undef,
    'widgetA.sort_dir' => undef,
    'widgetB.page_size' => undef
  }, "widgetA.page_size=10";
};


t/010-basic/030-vars.t  view on Meta::CPAN

    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetB",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetC",
    attrs => [qw/ size type color /]
  );

  $linker->add_widget(
    name  => "widgetD",
    attrs => [qw/ size type color /]
  );

  is_deeply
    $linker->vars(undef, 1), {
    'widgetB.page_number' => undef,
    'widgetC.type' => undef,
    'widgetD.size' => undef,
    'widgetA.page_size' => 100,
    'widgetB.sort_dir' => undef,
    'widgetC.size' => undef,
    'widgetD.color' => undef,
    'widgetD.type' => undef,
    'widgetA.page_number' => undef,
    'widgetA.sort_col' => undef,
    'widgetB.sort_col' => undef,
    'widgetC.color' => undef,
    'widgetA.sort_dir' => undef,
    'widgetB.page_size' => undef
  }, "Default";


  $linker->widget('widgetA')->set( page_size => 10 );
  is_deeply
    $linker->vars(undef, 1), {
    'widgetB.page_number' => undef,
    'widgetC.type' => undef,
    'widgetD.size' => undef,
    'widgetA.page_size' => 10,
    'widgetB.sort_dir' => undef,
    'widgetC.size' => undef,
    'widgetD.color' => undef,
    'widgetD.type' => undef,
    'widgetA.page_number' => undef,
    'widgetA.sort_col' => undef,
    'widgetB.sort_col' => undef,
    'widgetC.color' => undef,
    'widgetA.sort_dir' => undef,
    'widgetB.page_size' => undef
  }, "widgetA.page_size=10";
};


t/010-basic/040-links.t  view on Meta::CPAN

    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetB",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetC",
    attrs => [qw/ size type color /]
  );

  $linker->add_widget(
    name  => "widgetD",
    attrs => [qw/ size type color /]
  );
  


  is( $linker->uri() => '/', "/" );

  is(
    $linker->uri({
      widgetA => { page_number => 2 }
    }) => '/?widgetA.page_number=2'

t/010-basic/040-links.t  view on Meta::CPAN

        sort_col    => 'name',
        sort_dir    => 'ASC'
      }
    }) => '/?widgetA.page_number=2&widgetA.page_size=20&widgetA.sort_col=name&widgetA.sort_dir=ASC'
  );
};



WITH_VARS: {
  $api->ua->get('/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat');

  my $linker = ASP4x::Linker->new();

  $linker->add_widget(
    name  => "widgetA",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetB",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetC",
    attrs => [qw/ size type color /]
  );

  $linker->add_widget(
    name  => "widgetD",
    attrs => [qw/ size type color /]
  );


  is(
    $linker->uri() => '/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat',
    '/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => { page_number => 2 }
    }) => '/?widgetA.page_number=2&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => {
        page_number => 2,
        page_size   => 20,
        sort_col    => 'name',
        sort_dir    => 'ASC'
      }
    }) => '/?widgetA.page_number=2&widgetA.page_size=20&widgetA.sort_col=name&widgetA.sort_dir=ASC&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => {
        page_number => 2,
        page_size   => 20,
        sort_col    => 'name',
        sort_dir    => 'ASC'
      },
      widgetB => {
        page_size => 10
      }
    }) => '/?widgetA.page_number=2&widgetA.page_size=20&widgetA.sort_col=name&widgetA.sort_dir=ASC&widgetB.page_size=10&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );

  is(
    $linker->uri({
      NO_EXISTO => { blah => 'blech' },
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );
};



WITH_VARS_AND_ROUTER: {

  my $router = Router::Generic->new();
  $router->add_route(
    name    => 'FooRoute',
    path    => '/foo/:bar/baz',
    target  => '/index.asp',
    method  => 'GET'
  );

  $api->ua->get('/');
  $api->context->config->web->{router} = $router;
  $api->ua->get('/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat');
  
  my $linker = ASP4x::Linker->new();

  $linker->add_widget(
    name  => "widgetA",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetB",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetC",
    attrs => [qw/ size type color /]
  );

  $linker->add_widget(
    name  => "widgetD",
    attrs => [qw/ size type color /]
  );
  
  is_deeply $linker->widget('widgetA')->vars, {
    page_number => 24,
    page_size   => undef,
    sort_col    => undef,
    sort_dir    => undef,
  }, 'widgetA.vars';


  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );
  
  is(
    $linker->uri({yay=>'woot'}) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat&yay=woot',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat&yay=woot'
  );
  

  is(
    $linker->uri({
      widgetA => { page_number => 2 }
    }) => '/foo/bar/baz/?widgetA.page_number=2&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => {
        page_number => 2,
        page_size   => 20,
        sort_col    => 'name',
        sort_dir    => 'ASC'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=2&widgetA.page_size=20&widgetA.sort_col=name&widgetA.sort_dir=ASC&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => {
        page_number => 2,
        page_size   => 20,
        sort_col    => 'name',
        sort_dir    => 'ASC'
      },
      widgetB => {
        page_size => 10
      }
    }) => '/foo/bar/baz/?widgetA.page_number=2&widgetA.page_size=20&widgetA.sort_col=name&widgetA.sort_dir=ASC&widgetB.page_size=10&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );

  is(
    $linker->uri({
      NO_EXISTO => { blah => 'blech' },
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );
  
  $linker->widget('widgetB')->set( page_size => 20 );
  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=20&widgetC.color=blue&widgetD.type=hat',
    'widgetB.page_size = 20'
  );

  is(
    $linker->uri({
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );

  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );
  
  $linker->reset();
  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );
};



WITH_VARS_AND_ROUTER_POSTED: {
last;
  my $router = Router::Generic->new();
  $router->add_route(
    name    => 'FooRoute',

t/010-basic/040-links.t  view on Meta::CPAN

    target  => '/index.asp',
    method  => '*'
  );

  $api->ua->get('/');
  $api->context->config->web->{router} = $router;
  $api->ua->post('/foo/bar/baz/', {
    'widgetA.page_number' => 24,
    'widgetB.page_size'   => 100,
    'widgetC.color'       => 'blue',
    'widgetD.type'        => 'hat',
  });
  
  my $linker = ASP4x::Linker->new();

  $linker->add_widget(
    name  => "widgetA",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetB",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );

  $linker->add_widget(
    name  => "widgetC",
    attrs => [qw/ size type color /]
  );

  $linker->add_widget(
    name  => "widgetD",
    attrs => [qw/ size type color /]
  );
  
  
  is_deeply $linker->widget('widgetA')->vars, {
    page_number => 24,
    page_size   => undef,
    sort_col    => undef,
    sort_dir    => undef,
  }, 'widgetA.vars';


  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => { page_number => 2 }
    }) => '/foo/bar/baz/?widgetA.page_number=2&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => {
        page_number => 2,
        page_size   => 20,
        sort_col    => 'name',
        sort_dir    => 'ASC'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=2&widgetA.page_size=20&widgetA.sort_col=name&widgetA.sort_dir=ASC&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetA => {
        page_number => 2,
        page_size   => 20,
        sort_col    => 'name',
        sort_dir    => 'ASC'
      },
      widgetB => {
        page_size => 10
      }
    }) => '/foo/bar/baz/?widgetA.page_number=2&widgetA.page_size=20&widgetA.sort_col=name&widgetA.sort_dir=ASC&widgetB.page_size=10&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );

  is(
    $linker->uri({
      NO_EXISTO => { blah => 'blech' },
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );
  
  $linker->widget('widgetB')->set( page_size => 20 );
  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=20&widgetC.color=blue&widgetD.type=hat',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=20&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red&widgetD.color=orange&widgetD.type=hat'
  );

  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );
  
  $linker->reset();
  is(
    $linker->uri() => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat',
    '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=100&widgetC.color=blue&widgetD.type=hat'
  );

  is(
    $linker->uri({
      widgetB => {
        page_size => 10
      },
      widgetC => {
        color => 'red@hot'
      },
      widgetD => {
        color => 'orange'
      }
    }) => '/foo/bar/baz/?widgetA.page_number=24&widgetB.page_size=10&widgetC.color=red%40hot&widgetD.color=orange&widgetD.type=hat'
  );
};

t/010-basic/050-hidden-fields.t  view on Meta::CPAN

  attrs => [qw( page_number page_size )]
);

$linker->add_widget(
  name  => 'albums',
  attrs => [qw( page_number page_size )]
);

is
  $linker->hidden_fields() =>
  q(<input type="hidden" name="albums.page_size" value="" />
<input type="hidden" name="artists.page_number" value="" />
<input type="hidden" name="albums.page_number" value="" />
<input type="hidden" name="artists.page_size" value="" />),
  "Hidden Fields look right";

$linker->widget('albums')->set( page_number => 1 );
is
  $linker->hidden_fields() =>
  q(<input type="hidden" name="albums.page_size" value="" />
<input type="hidden" name="artists.page_number" value="" />
<input type="hidden" name="albums.page_number" value="1" />
<input type="hidden" name="artists.page_size" value="" />),
  "Hidden Fields look right";

is
  $linker->hidden_fields() =>
  q(<input type="hidden" name="albums.page_size" value="" />
<input type="hidden" name="artists.page_number" value="" />
<input type="hidden" name="albums.page_number" value="" />
<input type="hidden" name="artists.page_size" value="" />),
  "Auto-reset works";

my $args = {
  albums => { page_size => 20, page_number => 4 },
  artists => { page_size => 5, page_number => 10 }
};
is
  $linker->hidden_fields($args) =>
  q(<input type="hidden" name="albums.page_size" value="20" />
<input type="hidden" name="artists.page_number" value="10" />
<input type="hidden" name="albums.page_number" value="4" />
<input type="hidden" name="artists.page_size" value="5" />),
  "Auto-reset works";



t/htdocs/index.asp  view on Meta::CPAN

    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );
  
  $linker->add_widget(
    name  => "widgetB",
    attrs => [qw/ page_number page_size sort_dir sort_col /]
  );
  
  $linker->add_widget(
    name  => "widgetC",
    attrs => [qw/ size type color /]
  );
  
  $linker->add_widget(
    name  => "widgetD",
    attrs => [qw/ size type color /]
  );
  
  my @result = map {
    my $widget = $_;
    my $res = {
      $widget->name => {
        map { ($_ => $widget->get( $_ )) }
        $widget->attrs
      }
    };



( run in 1.438 second using v1.01-cache-2.11-cpan-13bb782fe5a )