package WebGUI::Session::Style; =head1 LEGAL ------------------------------------------------------------------- WebGUI is Copyright 2001-2009 Plain Black Corporation. ------------------------------------------------------------------- Please read the legal notices (docs/legal.txt) and the license (docs/license.txt) that came with this distribution before using this software. ------------------------------------------------------------------- http://www.plainblack.com info@plainblack.com ------------------------------------------------------------------- =cut use strict; use Tie::CPHash; use Scalar::Util qw( weaken ); use WebGUI::International; use WebGUI::Macro; use WebGUI::Asset::Template; eval { require WebGUI; import WebGUI; }; use HTML::Entities (); =head1 NAME Package WebGUI::Session::Style =head1 DESCRIPTION This package contains utility methods for WebGUI's style system. =head1 SYNOPSIS use WebGUI::Session::Style; $style = WebGUI::Session::Style->new($session); $html = $style->generateAdditionalHeadTags(); $html = $style->process($content); $session = $style->session; $style->makePrintable(1); $style->setLink($url,\%params); $style->setMeta(\%params); $style->setRawHeadTags($html); $style->setScript($url, \%params); $style->useEmptyStyle(1); =head1 METHODS These methods are available from this class: =cut #------------------------------------------------------------------- =head2 DESTROY ( ) Deconstructor. =cut sub DESTROY { my $self = shift; undef $self; } #------------------------------------------------------------------- sub _generateAdditionalTags { my $var = shift; return sub { my $self = shift; my $tags = $self->{$var}; delete $self->{$var}; WebGUI::Macro::process($self->session,\$tags); return $tags; }; } #------------------------------------------------------------------- =head2 generateAdditionalBodyTags ( ) Creates tags that were set using setScript (if inBody was true) and setRawBodyTags. Macros are processed in the tags if processed by this method. =cut BEGIN { *generateAdditionalBodyTags = _generateAdditionalTags('_rawBody') } #------------------------------------------------------------------- =head2 generateAdditionalHeadTags ( ) Creates tags that were set using setLink, setMeta, setScript, extraHeadTags, and setRawHeadTags. Macros are processed in the tags if processed by this method. =cut BEGIN { *generateAdditionalHeadTags = _generateAdditionalTags('_raw') } #------------------------------------------------------------------- =head2 makePrintable ( boolean ) Tells the system to use the make printable style instead of the normal style. =head3 boolean If set to 1 then the printable style will be used, otherwise the regular style will be used. =cut sub makePrintable { my $self = shift; $self->{_makePrintable} = shift; } #------------------------------------------------------------------- =head2 mobileBrowser ( ) Returns true if the user's browser matches any of the mobile browsers set in the config file. =cut sub mobileBrowser { my $self = shift; my $session = $self->session; my $ua = $session->env->get('HTTP_USER_AGENT'); for my $mobileUA (@{ $session->config->get('mobileUserAgents') }) { if ($ua =~ m/$mobileUA/) { return 1; } } } #------------------------------------------------------------------- =head2 useMobileStyle Returns a true value if we are on a mobile display. =cut sub useMobileStyle { my $self = shift; my $session = $self->session; my $scratchCheck = $session->scratch->get('useMobileStyle'); if (defined $scratchCheck) { return $scratchCheck; } if (exists $self->{_useMobileStyle}) { return $self->{_useMobileStyle}; } if (! $session->setting->get('useMobileStyle')) { return $self->{_useMobileStyle} = 0; } if ($self->mobileBrowser) { return $self->{_useMobileStyle} = 1; } return $self->{_useMobileStyle} = 0; } #------------------------------------------------------------------- =head2 setMobileStyle Sets whether the mobile style should be used for this session. =cut sub setMobileStyle { my $self = shift; my $enableMobile = shift; $self->session->scratch->set('useMobileStyle', $enableMobile); return $enableMobile; } #------------------------------------------------------------------- =head2 new ( session ) Constructor. =head3 session A reference to the current session. =cut sub new { my $class = shift; my $session = shift; my $self = bless {_session=>$session}, $class; weaken( $self->{_session} ); return $self; } #------------------------------------------------------------------- =head2 process ( content, templateId ) Returns a parsed style with content based upon the current WebGUI session information. Sets the C method/flag to be true so that subsequent head data is processed right away. =head3 content The content to be parsed into the style. Usually generated by WebGUI::Page::generate(). =head3 templateId The unique identifier for the template to retrieve. If $style->useEmptyStyle has been set, then the empty style templateId will be used over templateId. If personalStyleId is set in $session->scratch, then that id will be used over the other two. Finally, if $style->makePrintable has been called, process will try to find a template for making the output printable from $style->printableStyleId, from $session->asset or from any of $session->asset's ancestors. =cut sub process { my $self = shift; my $session = $self->session; my %var; $var{'body.content'} = shift; my $templateId = shift; if ($self->{_makePrintable} && $self->session->asset) { $templateId = $self->{_printableStyleId} || $session->asset->get("printableStyleTemplateId"); my $currAsset = $session->asset; my $rootAssetId = WebGUI::Asset->getRoot($session)->getId; TEMPLATE: until ($templateId) { # some assets don't have this property. But at least one ancestor should.... $currAsset = $currAsset->getParent; $templateId = $currAsset->get("printableStyleTemplateId"); last TEMPLATE if $currAsset->getId eq $rootAssetId; } } elsif ($session->scratch->get("personalStyleId") ne "") { $templateId = $session->scratch->get("personalStyleId"); } elsif ($self->{_useEmptyStyle}) { $templateId = 'PBtmpl0000000000000132'; } $var{'head.tags'} = ' ' . $self->session->setting->get('globalHeadTags') . ' '; if ($self->session->user->isRegistered || $self->session->setting->get("preventProxyCache")) { # This "triple incantation" panders to the delicate tastes of various browsers for reliable cache suppression. $var{'head.tags'} .= ' '; $self->session->http->setCacheControl("none"); } else { $var{'head.tags'} .= '' } # Removing the newlines will probably annoy people. # Perhaps turn it off under debug mode? $var{'head.tags'} =~ s/\n//g; # head.tags = head_attachments . body_attachments # keeping head.tags for backwards compatibility $var{'head_attachments'} = $var{'head.tags'}; $var{'head.tags'} .= ($var{'body_attachments'} = ''); my $style = WebGUI::Asset::Template->new($self->session,$templateId); my $output; if (defined $style) { my $meta = {}; if ($self->session->setting->get("metaDataEnabled")) { $meta = $style->getMetaDataFields(); } foreach my $field (keys %$meta) { $var{$meta->{$field}{fieldName}} = $meta->{$field}{value}; } $output = $style->process(\%var); } else { $output = sprintf "WebGUI was unable to instantiate your style template with the id: %s.%s", $templateId, $var{'body.content'}; } WebGUI::Macro::process($self->session,\$output); $self->sent(1); my $macroHeadTags = $self->generateAdditionalHeadTags(); my $macroBodyTags = $self->generateAdditionalBodyTags(); $output =~ s/\<\!--morehead--\>/$macroHeadTags/; $output =~ s/\<\!--morebody--\>/$macroBodyTags/; return $output; } #------------------------------------------------------------------- =head2 session ( ) Returns a reference to the current session. =cut sub session { my $self = shift; return $self->{_session}; } #------------------------------------------------------------------- =head2 sent ( boolean ) Returns a boolean indicating whether the style has already been sent. This is important when trying to set things to the HTML head block. =head3 boolean Set the value. =cut sub sent { my $self = shift; my $boolean = shift; if (defined $boolean) { $self->session->stow->set("styleHeadSent",$boolean); return $boolean; } return $self->session->stow->get("styleHeadSent"); } #------------------------------------------------------------------- =head2 setLink ( url, params ) Sets a tag into the of this rendered page for this page view. This is typically used for dynamically adding references to CSS and RSS documents. Tags are normally cached until the $style->sent flag is set to be true. If this method is called after that sent is true, then the tag will be sent immediately, but will not be processed for macros. =head3 url The URL to the document you are linking. Only one link can be set per url. If a link to this URL exists, the old link will remain and this method will return undef. =head3 params A hash reference containing the other parameters to be included in the link tag, such as "rel" and "type". =cut sub setLink { my $self = shift; my $url = shift; my $params = shift; $params = {} unless (defined $params and ref $params eq 'HASH'); return undef if ($self->{_link}{$url}); my $tag = '{_link}{$url} = 1; $self->setRawHeadTags($tag); } #------------------------------------------------------------------- =head2 setPrintableStyleId ( params ) Overrides current printable style id defined in assets definition =head3 params scalar containing id of style to use =cut sub setPrintableStyleId { my $self = shift; my $styleId = shift; $self->{_printableStyleId} = $styleId; } #------------------------------------------------------------------- =head2 setMeta ( params ) Sets a tag into the of this rendered page for this page view. Tags are normally cached until the $style->sent flag is set to be true. If this method is called after that sent is true, then the tag will be sent immediately, but will not be processed =head3 params A hash reference containing the parameters of the meta tag. =cut sub setMeta { my $self = shift; my $params = shift; my $tag = 'setRawHeadTags($tag); } #------------------------------------------------------------------- sub _setRawTags { my $var = shift; return sub { my $self = shift; my $tags = shift; if ($self->sent) { $self->session->output->print($tags); } else { $self->{$var} .= $tags; } }; } #------------------------------------------------------------------- =head2 setRawBodyTags ( tags ) Does exactly the same thing as setRawHeadTags, except that the tags will be appended to a seperate variable (to be output after the body if the style template supports it) instead. =cut BEGIN { *setRawBodyTags = _setRawTags('_rawBody') } #------------------------------------------------------------------- =head2 setRawHeadTags ( tags ) Sets data to be output into the of the current rendered page for this page view. Tags are normally cached until the $style->sent flag is set to be true. If this method is called after that sent is true, then the tag will be sent immediately, but will not be processed for macros. =head3 tags A raw string containing tags. This is just a raw string so you must actually pass in the full tag to use this call. =cut BEGIN { *setRawHeadTags = _setRawTags('_raw') } #------------------------------------------------------------------- =head2 setScript ( url, params, [inBody] ) Sets a '."\n"; $self->{_javascript}{$url} = 1; if ($inBody) { $self->setRawBodyTags($tag); } else { $self->setRawHeadTags($tag); } } #------------------------------------------------------------------- =head2 useEmptyStyle ( boolean ) Tells the style system to use an empty style rather than outputing the normal style. This is useful when you want your code to dynamically generate a style. =head3 boolean If set to 1 it will use an empty style, if set to 0 it will use the regular style. Defaults to 0. =cut sub useEmptyStyle { my $self = shift; $self->{_useEmptyStyle} = shift; } #------------------------------------------------------------------- =head2 userStyle ( content ) Wrapper's the content in the user style defined in the settings. =head3 content The content to be wrappered. =cut sub userStyle { my $self = shift; my $output = shift; $self->session->http->setCacheControl("none"); if (defined $output) { return $self->process($output,$self->session->setting->get("userFunctionStyleId")); } else { return undef; } } 1;