@@ -, +, @@ --- Koha/Template/Plugin/Combine.pm | 141 +++++++++++++++++++ .../intranet-tmpl/prog/en/css/staff-global.css | 3 +- .../prog/en/includes/doc-head-close.inc | 50 ++++--- koha-tmpl/opac-tmpl/prog/en/css/opac.css | 3 - .../opac-tmpl/prog/en/includes/doc-head-close.inc | 143 +++++++++++++------- koha-tmpl/opac-tmpl/prog/en/js/script.js | 1 - 6 files changed, 261 insertions(+), 80 deletions(-) create mode 100644 Koha/Template/Plugin/Combine.pm --- a/Koha/Template/Plugin/Combine.pm +++ a/Koha/Template/Plugin/Combine.pm @@ -0,0 +1,141 @@ +package Koha::Template::Plugin::Combine; +use Template::Plugin; +use base qw( Template::Plugin ); +use warnings; +use strict; + +# PLACK_DEBUG=1 always re-create files but report correct hit/miss ration + +use File::Slurp; +use Digest::MD5; +use Data::Dump qw(dump); + +use CSS::Minifier::XS; +use JavaScript::Minifier::XS; + +sub new { + my ($class, $context, @params) = @_; +#warn "## context ",dump( $context ); + bless { + _CONTEXT => $context, + js => [], # same as extension! + css => [], + inline => 1, + minify => 1, + }, $class; +} + +sub _html_params { + my $params = shift; + return join(' ', map { $_ . '="' . $params->{$_} . '"' } keys %$params ); +} + +sub javascript { + my ( $self, $params ) = @_; + warn "## combine.javascript ", dump( $params ); + $params->{type} ||= 'text/javascript'; + push @{ $self->{js} }, $params; + my $html = _html_params( $params ); + if ( $self->{inline} ) { + return "\n"; + } elsif ( my $cdata = $params->{cdata} ) { + return qq|\n|; + } else { + return "\n"; + } +} + +sub css { + my ( $self, $params ) = @_; + warn "## combine.css ",dump( $params ); + $params->{rel} ||= 'stylesheet'; + $params->{type} ||= 'text/css'; + die "no href in ",dump($params) unless exists $params->{href}; + my $html = _html_params( $params ); + + if ( exists $params->{media} ) { # FIXME not combined! + push @{ $self->{css_media} }, ""; + return ""; + } + + push @{ $self->{css} }, $params; + if ( $self->{inline}) { + return "\n"; + } else { + return "\n"; + } +} + +sub combined_files { + my ( $self, $what, $attr, $params ) = @_; +warn "## combined_files $what $attr ",dump($params); + my $key = join(' ', map { $_->{$attr} || $_->{cdata} } @{ $self->{$what} } ); + $key = Digest::MD5::md5_hex( $key ); # shorten filenames + warn "# $what $attr key = $key\n"; + my $htdocs = C4::Context->config('intrahtdocs'); + $htdocs =~ s{/intranet-tmpl/?$}{}; # FIXME DocumentRoot even for OPAC + + my ( $path, $url ); + if ( my $prefix = $params->{prefix} ) { + $path = "$htdocs/$prefix/combined/$key.$what"; + $url = "$prefix/combined/$key.$what"; + } else { + $path = "$htdocs/intranet-tmpl/combined/$key.$what"; + $url = "/intranet-tmpl/combined/$key.$what"; + } + $path =~ s{//+}{/}; # plack is picky about paths + if ( -e $path ) { + $Koha::Persistant::stats->{combine_files}->[0]++; # hit + return $url if ! $ENV{PLACK_DEBUG}; # FIXME no caching with debug + } + $Koha::Persistant::stats->{combine_files}->[1]++ if ! $ENV{PLACK_DEBUG}; # miss + + my $mix; + foreach my $include ( @{ $self->{$what} } ) { + if ( my $path = $include->{$attr} ) { + warn "combine_files $what $attr - $path"; + my $chunk = read_file("$htdocs/$path"); + die "$htdocs/$path found \@import" if $what eq 'css' && $chunk =~ m'@import'; + $mix .= "\n/* BEGIN $path */\n$chunk\n/* END $path */\n"; + } elsif ( my $cdata = $include->{cdata} ) { + warn "combine_files CDATA $cdata"; + $mix .= "\n/* BEGIN CDATA */\n$cdata\n/* END CDATA */\n"; + } + } + my $combined_size = length($mix); + if ( $self->{minify} ) { + if ( $what eq 'js' ) { + $mix = JavaScript::Minifier::XS::minify( $mix ); + } elsif ( $what eq 'css' ) { + $mix = CSS::Minifier::XS::minify( $mix ); + } else { + die "can't minify $what"; + } + my $size = length($mix); + warn sprintf "minify %s %d -> %d %.2f%%\n", $what, $combined_size, $size, $size * 100 / $combined_size; + } + write_file $path, $mix; + warn "## $path ", -s $path, "/$combined_size bytes\n"; + return $url; +} + +sub html { + my ( $self, $params ) = @_; + + if ( $self->{inline} ) { + warn "## css ",dump( $self->{css} ); + warn "## javascript ",dump( $self->{js} ); + my $mix; + my $js = $self->combined_files( 'js' => 'src', $params ); + my $css = $self->combined_files( 'css' => 'href', $params ); + return qq{ + + + + }; + } else { + return ""; + } +} + +1; --- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css +++ a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css @@ -1,5 +1,4 @@ -@import url("../lib/yui/reset-fonts-grids.css"); -@import url("../lib/yui/skin.css"); +/* import moved to koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc */ input:focus, textarea:focus { border-color:#538200; --- a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc @@ -1,44 +1,47 @@ +[% USE combine = Combine %] - - - +[% combine.css( href => themelang _ "/lib/jquery/jquery-ui.css" ) %] +[% combine.css( href => themelang _ "/lib/jquery/plugins/ui.tabs.css" ) %] +[% combine.css( media => "print" href => themelang _ "/css/print.css" ) %] [% IF ( intranetstylesheet ) %] - + [% combine.css( href => intranetstylesheet ) %] [% ELSE %] - + [% combine.css( href => yuipath _ "/reset-fonts-grids.css" ) %] + [% combine.css( href => yuipath _ "/skin.css" ) %] + [% combine.css( href => themelang _ "/css/staff-global.css" ) %] [% END %] [% IF ( IntranetUserCSS ) %][% END %] - - - - - - +[% combine.javascript( src => themelang _ "/lib/jquery/jquery.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/plugins/ui.tabs.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/jquery-ui.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/plugins/jquery.hotkeys.min.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/plugins/jquery.cookie.min.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/plugins/jquery.highlight-3.js" ) %] [% IF ( login ) %] - + [% combine.css( href => themelang _ "/css/login.css" ) %] [% END %] [% IF ( wizard ) %] - + [% combine.css( href => themelang _ "/css/wizard.css" ) %] [% END %] [% IF ( intranetcolorstylesheet ) %] - + [% combine.css( href => themelang _ "/css/" _ intranetcolorstylesheet ) %] [% END %] - - +[% combine.javascript( src => yuipath _ "/utilities/utilities.js" ) %] +[% combine.javascript( src => yuipath _ "/datasource/datasource-min.js" ) %] [% IF ( CircAutocompl ) %] - + [% combine.javascript( src => yuipath _ "/autocomplete/autocomplete-min.js" ) %] [% END %] - - - +[% combine.javascript( src => yuipath _ "/button/button-min.js" ) %] +[% combine.javascript( src => yuipath _ "/container/container_core-min.js" ) %] +[% combine.javascript( src => yuipath _ "/menu/menu-min.js" ) %] - +[% combine.javascript( src => themelang _ "/js/staff-global.js" ) %] [% IF ( intranetuserjs ) %] [% IF ( virtualshelves || intranetbookbag ) %] - + [% combine.javascript( src => themelang _ "/js/basket.js" ) %] [% END %] [% IF LocalCoverImages %] - +[% combine.javascript( src => themelang _ "/js/localcovers.js" ) %] [% END %] +[% combine.html( prefix => themelang ) %] --- a/koha-tmpl/opac-tmpl/prog/en/css/opac.css +++ a/koha-tmpl/opac-tmpl/prog/en/css/opac.css @@ -1,6 +1,3 @@ -@import url("../lib/yui/reset-fonts-grids.css"); -@import url("../lib/yui/skin.css"); - a { font-weight : bold; } --- a/koha-tmpl/opac-tmpl/prog/en/includes/doc-head-close.inc +++ a/koha-tmpl/opac-tmpl/prog/en/includes/doc-head-close.inc @@ -2,50 +2,62 @@ -[% IF ( opacstylesheet ) %][% ELSE %] -[% IF ( opaclayoutstylesheet ) %][% ELSE %][% END %][% END %] +[% USE combine = Combine %] +[% IF ( opacstylesheet ) %] + [% combine.css( href => opacstylesheet ) %] +[% ELSE %] + [% IF ( opaclayoutstylesheet ) %] + [% combine.css( href => themelang _ "/css/" _ opaclayoutstylesheet ) %] + [% ELSE %] + [% combine.css( href => themelang _ "/css/opac.css" ) %] + [% END %] +[% END %] [% IF ( opaccolorstylesheet ) %] - + [% combine.css( href => themelang _ "/css/" _ opaccolorstylesheet ) %] [% END %] [% IF ( opacexternalsheet ) %] - + [% combine.css( href => opacexternalsheet ) %] [% END %] [% IF ( opac_css_override ) %] - + [% combine.css( href => therelang _ "/css/" _ opac_css_override ) %] [% END %] - +[% combine.css( href => themelang _ "/lib/jquery/plugins/ui.tabs.css" ) %] [% IF ( OPACUserCSS ) %][% END %] - - - - - - - +[% combine.css( href => yuipath _ "/reset-fonts-grids.css" ) %] +[% combine.css( href => yuipath _ "/skin.css" ) %] +[% combine.javascript( src => yuipath _ "/utilities/utilities.js" ) %] +[% combine.javascript( src => yuipath _ "/container/container-min.js" ) %] +[% combine.javascript( src => yuipath _ "/menu/menu-min.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/jquery.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/plugins/ui.tabs.js" ) %] +[% combine.javascript( src => themelang _ "/lib/jquery/plugins/jquery.hoverIntent.minified.js" ) %] +[% combine.javascript( src => themelang _ "/js/script.js" ) %] + [% IF ( OPACAmazonCoverImages ) %] - - +[% combine.javascript( cdata => "var NO_AMAZON_IMAGE = _(\"No cover image available\");" ) %] +[% combine.javascript( src => themelang _ "/js/amazonimages.js" ) %] [% END %] [% IF ( SyndeticsCoverImages ) %] - - [% END %] +[% combine.javascript( cdata => "var NO_AMAZON_IMAGE = _(\"No cover image available\");" ) %] +[% combine.javascript( src => themelang _ "/js/amazonimages.js" ) %] +[% END %] -[% IF ( opacbookbag ) %] +[% IF ( opacbookbag ) %] + [% combine.javascript( src => themelang _ "/js/basket.js" ) %] +[% ELSIF ( virtualshelves ) %] + [% combine.javascript( src => themelang _ "/js/basket.js" ) %] +[% ELSE %] + [% combine.javascript( cdata => "var readCookie;" ) %] +[% END %] +[% combine.javascript( cdata => "var cdata_test;" ) %] -[% IF ( opacuserlogin ) %][% IF ( TagsEnabled ) %][% END %][% ELSE %][% END %] + +[% IF ( opacbookbag ) %] +[% compose.javascript( src => themelang _ "/js/basket.js" ) %] +[% ELSIF ( virtualshelves ) %] +[% compose.javascript( src => themelang _ "/js/basket.js" ) %] +[% ELSE %] + +[% END %] + +[% IF ( opacuserlogin ) %] + [% IF ( TagsEnabled ) %] + [% combine.javascript( src => themelang _ "/js/tags.js" ) %] + [% END %] +[% END %] + [% IF ( GoogleJackets ) %] - +[% combine.javascript( src => themelang _ "/js/google-jackets.js" ) %] [% END %] [% IF OpenLibraryCovers %] - +[% combine.javascript( src => themelang _ "/js/openlibrary.js" ) %] +[% combine.javascript( src => themelang _ "/js/localcovers.js" ) %] [% END %] -[% IF ( BakerTaylorEnabled ) %] +[% IF ( BakerTaylorEnabled ) %] +[% combine.javascript( src => themelang _ "/js/bakertaylorimages.js" ) %] [% END %] + +[% END %] + [% IF ( GoogleIndicTransliteration ) %] - - + + [% combine.javascript( src => themelang _ "/js/googleindictransliteration.js" ) %] [% END %] - +[% combine.html( prefix => themelang ) %] --- a/koha-tmpl/opac-tmpl/prog/en/js/script.js +++ a/koha-tmpl/opac-tmpl/prog/en/js/script.js @@ -1,4 +1,3 @@ -function _(s) { return s } // dummy function for gettext function confirmDelete(message) { return (confirm(message) ? true : false); } --