Skip Menu |

This queue is for tickets about the Catalyst-View-JSON CPAN distribution.

Report information
The Basics
Id: 34735
Status: rejected
Priority: 0/
Queue: Catalyst-View-JSON

People
Owner: Nobody in particular
Requestors: spurkis [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.24
Fixed in: (no value)



Subject: [PATCH] Handle file uploads by embedding response in <textarea>
This patch (+docs + tests) adds an 'embed response in textarea' feature to the module: =head1 WORKAROUND FOR FILE UPLOADS Unfortunately XMLHttpsRequest does not support file uploads. A common workaround is to use a hidden IFrame to process the upload, and return JSON content embedded in a C<E<lt>textareaE<gt>> element to avoid mangling HTML entities. See the 'Files' tab of L<http://malsup.com/jquery/form/#code-samples> for more details. You can enable embedding JSON in a textarea with L</allow_textarea_embed>, and control which request parameter is used with L</textarea_embed_param>. An embedded response will look like this: Content-type: text/html <html><body><textarea>{ "result": "foo" }</textarea></body></html>
Subject: Catalyst-View-JSON-0.24-textarea-embeds.patch
diff -ruN Catalyst-View-JSON-0.24.orig/lib/Catalyst/View/JSON.pm Catalyst-View-JSON-0.24/lib/Catalyst/View/JSON.pm --- Catalyst-View-JSON-0.24.orig/lib/Catalyst/View/JSON.pm 2008-03-03 09:44:14.000000000 +0000 +++ Catalyst-View-JSON-0.24/lib/Catalyst/View/JSON.pm 2008-04-07 13:02:53.000000000 +0100 @@ -8,7 +8,7 @@ use NEXT; use Catalyst::Exception; -__PACKAGE__->mk_accessors(qw( allow_callback callback_param expose_stash encoding json_dumper no_x_json_header )); +__PACKAGE__->mk_accessors(qw( allow_callback callback_param allow_textarea_embed textarea_embed_param expose_stash encoding json_dumper no_x_json_header )); sub new { my($class, $c, $arguments) = @_; @@ -80,6 +80,10 @@ my $cb = $cb_param ? $c->req->param($cb_param) : undef; $self->validate_callback_param($cb) if $cb; + my $txt_param = $self->allow_textarea_embed + ? ($self->textarea_embed_param || 'embed_in_textarea') : undef; + my $embed_in_txt = $txt_param ? $c->req->param($txt_param) : undef; + my $json = $self->json_dumper->($data, $self, $c); # weird order to be backward compat # When you set encoding option in View::JSON, this plugin DWIMs @@ -92,7 +96,9 @@ $json = Encode::encode($encoding, $json); } - if (($c->req->user_agent || '') =~ /Opera/) { + if ($embed_in_txt) { + $c->res->content_type("text/html; charset=$encoding"); + } elsif (($c->req->user_agent || '') =~ /Opera/) { $c->res->content_type("application/x-javascript; charset=$encoding"); } else { $c->res->content_type("application/json; charset=$encoding"); @@ -109,9 +115,11 @@ $output = "\xEF\xBB\xBF"; } + $output .= '<html><body><textarea>' if $embed_in_txt; $output .= "$cb(" if $cb; $output .= $json; $output .= ");" if $cb; + $output .= '</textarea></body></html>' if $embed_in_txt; $c->res->output($output); } @@ -171,6 +179,18 @@ Name of URI parameter to specify JSON callback function name. Defaults to C<callback>. Only effective when C<allow_callback> is turned on. +=item allow_textarea_embed + +Flag to allow embedding JSON responses in textareas by adding +C<embed_in_textarea=1>. Defaults to 0 (doesn't allow embedding in textareas). +See L</WORKAROUND FOR FILE UPLOADS> for details. + +=item textarea_embed_param + +Name of URI parameter to determine whether or not to embed the JSON response +in a textarea. Defaults to C<embed_in_textarea>. Only effective when +C<allow_textarea_embed> is turned on. + =item expose_stash Scalar, List or regular expression object, to specify which stash keys are @@ -311,6 +331,22 @@ L<http://ajaxian.com/archives/jsonp-json-with-padding> for more about JSONP. +=head1 WORKAROUND FOR FILE UPLOADS + +Unfortunately XMLHttpsRequest does not support file uploads. A common +workaround is to use a hidden IFrame to process the upload, and return JSON +content embedded in a C<E<lt>textareaE<gt>> element to avoid mangling HTML +entities. See the 'Files' tab of L<http://malsup.com/jquery/form/#code-samples> +for more details. + +You can enable embedding JSON in a textarea with L</allow_textarea_embed>, and +control which request parameter is used with L</textarea_embed_param>. An +embedded response will look like this: + + Content-type: text/html + + <html><body><textarea>{ "result": "foo" }</textarea></body></html> + =head1 INTEROPERABILITY JSON use is still developing and has not been standardized. This diff -ruN Catalyst-View-JSON-0.24.orig/t/01_server.t Catalyst-View-JSON-0.24/t/01_server.t --- Catalyst-View-JSON-0.24.orig/t/01_server.t 2008-03-03 09:24:13.000000000 +0000 +++ Catalyst-View-JSON-0.24/t/01_server.t 2008-04-07 12:25:26.000000000 +0100 @@ -13,7 +13,7 @@ plan skip_all => "JSON 2.04 is needed for testing"; } -plan tests => 40; +plan tests => 46; BEGIN { no warnings 'redefine'; @@ -142,4 +142,20 @@ is $data->{foo}, "fake"; } +{ + my $request = HTTP::Request->new( GET => "http://localhost/foo7?embed_in_textarea=1" ); + + ok( my $response = request($request), 'Request' ); + ok( $response->is_success, 'Response Successful 2xx' ); + is( $response->code, 200, 'Response Code' ); + is_deeply( [ $response->content_type ], [ 'text/html', 'charset=utf-8' ], 'content type' ); + + my $body = $response->content; + like( $body, qr|^<html><body><textarea>.+</textarea></body></html>$|, 'embedded in textarea' ); + + my ($d1,$json,$d2) = split(qr|</?textarea>|, $body); + + my $data = JSON::from_json($json); + is_deeply( $data, {json_foo => 'bar', json_baz => [1, 2, 3]}, 'extracted JSON data' ); +} diff -ruN Catalyst-View-JSON-0.24.orig/t/lib/TestApp.pm Catalyst-View-JSON-0.24/t/lib/TestApp.pm --- Catalyst-View-JSON-0.24.orig/t/lib/TestApp.pm 2008-03-03 09:24:13.000000000 +0000 +++ Catalyst-View-JSON-0.24/t/lib/TestApp.pm 2008-04-07 12:58:53.000000000 +0100 @@ -65,6 +65,17 @@ $c->forward('TestApp::View::JSON2'); } +sub foo7 : Global { + my( $self, $c ) = @_; + my $jc = $c->component('View::JSON'); + $jc->expose_stash(qr/^json_/); + $jc->allow_textarea_embed(1); + $jc->textarea_embed_param('embed_in_textarea'); + $c->stash->{json_foo} = "bar"; + $c->stash->{json_baz} = [ 1, 2, 3 ]; + $c->forward('TestApp::View::JSON'); +} + sub finalize_error { my $c = shift; $c->res->header('X-Error' => $c->error->[0]);
This kind of thing seems to not be some common with modern javascript toolkits and I don't think its good for core, but rather as a role or subclass for your specific need.
This kind of thing seems to not be some common with modern javascript toolkits and I don't think its good for core, but rather as a role or subclass for your specific need.