Unfuck merge, I should stick with adding docs when I'm shattered
[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) = @_;
31 if ($c->request->header('Accept') && $c->response->headers->{'content-type'} =~ m|text/html|) {
32 $self->pragmatic_accept($c);
33 my $var = choose($self->variants, $c->request->headers);
34 if ($var eq 'xhtml') {
35 $c->response->headers->{'content-type'} =~ s|text/html|application/xhtml+xml|;
36 }
37 }
38};
39
40sub pragmatic_accept {
41 my ($self, $c) = @_;
42 my $accept = $c->request->header('Accept');
43 if ($accept =~ m|text/html|) {
44 $accept =~ s!\*/\*\s*([,]+|$)!*/*;q=0.5$1!;
45 } else {
46 $accept =~ s!\*/\*\s*([,]+|$)!text/html,*/*;q=0.5$1!;
47 }
48 $c->request->header('Accept' => $accept);
49}
50
511;
52
53__END__
54
55=head1 NAME
56
57Catalyst::View::ContentNegotiation::XHTML - A Moose Role to apply to
58Catalyst views adjusts the response Content-Type header to
59application/xhtml+xml content if the browser accepts it.
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
75This is a very simple Role which uses a method modifier to run after the
76C<process> method, and sets the response C<Content-Type> to be
77C<application/xhtml+xml> if the users browser sends an C<Accept> header
78indicating that it is willing to process that MIME type.
79
80Changing the C<Content-Type> causes browsers to interpret the page as
81XML, meaning that the markup must be well formed.
82
83This is useful when you're developing your application, as you know that
84all pages you view are parsed as XML, so any errors caused by your markup
85not being well-formed will show up at once.
86
87=head1 METHOD MODIFIERS
88
89=head2 after process
90
91Changes the response C<Content-Type> if appropriate (from the requests C<Accept> header).
92
93=head1 METHODS
94
95=head2 pragmatic_accept
96
97Some browsers (such as Internet Explorer) have a nasty way of sending
98Accept */* and this claiming to support XHTML just as well as HTML.
99Saving to a file on disk or opening with another application does
100count as accepting, but it really should have a lower q value then
101text/html. This sub takes a pragmatic approach and corrects this mistake
102by modifying the Accept header before passing it to content negotiation.
103
104=head1 ATTRIBUTES
105
106=head2 variants
107
108Returns an array ref of 3 part arrays, comprising name, priority, output
109mime-type, which is used for the content negotiation algorithm.
110
111=head1 PRIVATE METHODS
112
113=head2 _build_variants
114
115Returns the default variant attribute contents.
116
117=head1 SEE ALSO
118
119=over
120
121=item L<Catalyst::View::TT::XHTML> - Trivial Catalyst TT view using this role.
122
123=item L<http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html> - Content negotiation RFC.
124
125=back
126
127=head1 BUGS
128
129Should be split into a base ContentNegotiation role which is consumed by ContentNegotiation::XHTML.
130
131=head1 AUTHOR
132
133Tomas Doran (t0m) C<< <bobtfish@bobtfish.net> >>
134
135=head1 CONTRIBUTORS
136
137=over
138
139=item David Dorward - test patches and */* pragmatism.
140
141=item Florian Ragwitz (rafl) C<< <rafl@debian.org> >> - Conversion into a Moose Role
142
143=back
144
145=head1 COPYRIGHT
146
147This module itself is copyright (c) 2008 Tomas Doran and is licensed under the same terms as Perl itself.
148
149=cut