Reformat docs, couple of other misc dinks
[catagits/Catalyst-View-ContentNegotiation-XHTML.git] / lib / Catalyst / View / ContentNegotiation / XHTML.pm
CommitLineData
e2e866b4 1package Catalyst::View::ContentNegotiation::XHTML;
2
3use Moose::Role;
4use MooseX::Types::Moose qw/Num Str ArrayRef/;
5use MooseX::Types::Structured qw/Tuple/;
6use HTTP::Negotiate qw/choose/;
7
8use namespace::clean -except => 'meta';
9
10# Remember to bump $VERSION in View::TT::XHTML also.
11our $VERSION = '1.100';
12
13requires 'process';
14
15has variants => (
16 is => 'ro',
17 isa => ArrayRef[Tuple[Str, Num, Str]],
18 lazy => 1,
19 builder => '_build_variants',
20);
21
22sub _build_variants {
23 return [
24 [qw| xhtml 1.000 application/xhtml+xml |],
25 [qw| html 0.900 text/html |],
26 ];
27}
28
29after process => sub {
30 my ($self, $c) = @_;
8e61c4b2 31 if ( my $accept = $self->pragmatic_accept($c) and $c->response->headers->{'content-type'} =~ m|text/html|) {
32 my $headers = $c->request->headers->clone;
33 $headers->header('Accept' => $accept);
34 if ( choose($self->variants, $headers) eq 'xhtml') {
e2e866b4 35 $c->response->headers->{'content-type'} =~ s|text/html|application/xhtml+xml|;
36 }
37 }
38};
39
40sub pragmatic_accept {
41 my ($self, $c) = @_;
8e61c4b2 42 my $accept = $c->request->header('Accept') or return;
e2e866b4 43 if ($accept =~ m|text/html|) {
44 $accept =~ s!\*/\*\s*([,]+|$)!*/*;q=0.5$1!;
8e61c4b2 45 }
46 else {
e2e866b4 47 $accept =~ s!\*/\*\s*([,]+|$)!text/html,*/*;q=0.5$1!;
48 }
8e61c4b2 49 return $accept;
e2e866b4 50}
51
521;
53
54__END__
55
56=head1 NAME
57
84e59a9b 58Catalyst::View::ContentNegotiation::XHTML - Adjusts the response Content-Type
59header to application/xhtml+xml if the browser accepts it.
e2e866b4 60
61=head1 SYNOPSIS
62
63 package Catalyst::View::TT;
64
65 use Moose;
66 use namespace::clean -except => 'meta';
67
68 extends qw/Catalyst::View::TT/;
69 with qw/Catalyst::View::ContentNegotiation::XHTML/;
70
71 1;
72
73=head1 DESCRIPTION
74
84e59a9b 75This is a simple Role which sets the response C<Content-Type> to be
76C<application/xhtml+xml> if the users browser sends an C<Accept> header
e2e866b4 77indicating that it is willing to process that MIME type.
78
84e59a9b 79Changing the C<Content-Type> to C<application/xhtml+xml> causes browsers to
80interpret the page as XML, meaning that your markup must be well formed.
d086c97e 81
82=head1 CAVEATS
e2e866b4 83
84e59a9b 84This is useful when you're developing your application, as you know that all
85pages you view are parsed as XML, so any errors caused by your markup not
86being well-formed will show up at once.
e2e866b4 87
d086c97e 88Whilst this module is has been tested against most popular browsers including
89Internet Explorer, it may cause unexpected results on browsers which do not
90properly support the C<application/xhtml+xml> MIME type.
91
e2e866b4 92=head1 METHOD MODIFIERS
93
94=head2 after process
95
84e59a9b 96Changes the response C<Content-Type> if appropriate (from the requests
97C<Accept> header).
e2e866b4 98
99=head1 METHODS
100
101=head2 pragmatic_accept
102
84e59a9b 103Some browsers (such as Internet Explorer) have a nasty way of sending Accept
104*/* and this claiming to support XHTML just as well as HTML. Saving to a file
105on disk or opening with another application does count as accepting, but it
106really should have a lower q value then text/html. This sub takes a pragmatic
107approach and corrects this mistake by modifying the Accept header before
108passing it to content negotiation.
e2e866b4 109
110=head1 ATTRIBUTES
111
112=head2 variants
113
84e59a9b 114Returns an array ref of 3 part arrays, comprising name, priority, output
e2e866b4 115mime-type, which is used for the content negotiation algorithm.
116
117=head1 PRIVATE METHODS
118
119=head2 _build_variants
120
121Returns the default variant attribute contents.
122
123=head1 SEE ALSO
124
125=over
126
127=item L<Catalyst::View::TT::XHTML> - Trivial Catalyst TT view using this role.
128
84e59a9b 129=item L<http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html> - Content
130negotiation RFC.
e2e866b4 131
132=back
133
134=head1 BUGS
135
84e59a9b 136Should be split into a base ContentNegotiation role which is consumed by
137ContentNegotiation::XHTML.
e2e866b4 138
139=head1 AUTHOR
140
84e59a9b 141Original author and maintainer - Tomas Doran (t0m)
142C<< <bobtfish@bobtfish.net> >>
e2e866b4 143
144=head1 CONTRIBUTORS
145
146=over
147
84e59a9b 148=item David Dorward - test patches and */* pragmatism to make it work for
149browsers which aren't firefox.
e2e866b4 150
84e59a9b 151=item Florian Ragwitz (rafl) C<< <rafl@debian.org> >> - Conversion into a
152Moose Role, which is what the module should have been originally.
e2e866b4 153
154=back
155
156=head1 COPYRIGHT
157
84e59a9b 158This module itself is copyright (c) 2008 Tomas Doran and is licensed under the
159same terms as Perl itself.
e2e866b4 160
161=cut