From 30c9300f8adcd0df814c416a7b501e4dde368895 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 11 Aug 2020 18:26:01 +0200 Subject: [PATCH] Bug 26145: Allow multi covers per item In this patch we remove the limitation of 1 cover image per item Sponsored-by: Gerhard Sondermann Dialog e.K. (presseplus.de, presseshop.at, presseshop.ch) --- Koha/Item.pm | 9 +- catalogue/detail.pl | 9 +- catalogue/imageviewer.pl | 23 ++- .../prog/css/src/staff-global.scss | 9 +- .../admin/preferences/enhanced_content.pref | 2 +- .../prog/en/modules/catalogue/detail.tt | 151 ++++++++++-------- .../prog/en/modules/tools/upload-images.tt | 2 +- .../bootstrap/en/modules/opac-detail.tt | 4 +- opac/opac-detail.pl | 9 +- t/db_dependent/Koha/CoverImages.t | 9 +- tools/upload-cover-image.pl | 21 +-- 11 files changed, 130 insertions(+), 118 deletions(-) diff --git a/Koha/Item.pm b/Koha/Item.pm index a7d3f78771..f1d985176f 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -785,19 +785,18 @@ sub renewal_branchcode { return $branchcode; } -=head3 cover_image +=head3 cover_images -Return the cover image associated with this item. +Return the cover images associated with this item. =cut -sub cover_image { +sub cover_images { my ( $self ) = @_; my $cover_image_rs = $self->_result->cover_images; return unless $cover_image_rs; - # So far we allow only 1 cover image per item - return Koha::CoverImages->_new_from_dbic($cover_image_rs)->next; + return Koha::CoverImages->_new_from_dbic($cover_image_rs); } =head3 _set_found_trigger diff --git a/catalogue/detail.pl b/catalogue/detail.pl index 4e6404398e..7b7f4d2944 100755 --- a/catalogue/detail.pl +++ b/catalogue/detail.pl @@ -408,21 +408,20 @@ foreach my $item (@items) { } if ( C4::Context->preference("LocalCoverImages") == 1 ) { - my $cover_image = $item_object->cover_image; - $item->{imagenumber} = $cover_image ? $cover_image->imagenumber : undef; + $item->{cover_images} = $item_object->cover_images; } if ($currentbranch and C4::Context->preference('SeparateHoldings')) { if ($itembranchcode and $itembranchcode eq $currentbranch) { push @itemloop, $item; - $itemloop_has_images++ if $item->{imagenumber}; + $itemloop_has_images++ if $item_object->cover_images->count; } else { push @otheritemloop, $item; - $otheritemloop_has_images++ if $item->{imagenumber}; + $otheritemloop_has_images++ if $item_object->cover_images->count; } } else { push @itemloop, $item; - $itemloop_has_images++ if $item->{imagenumber}; + $itemloop_has_images++ if $item_object->cover_images->count; } } diff --git a/catalogue/imageviewer.pl b/catalogue/imageviewer.pl index 3ed64fe8cc..b71a3c2e75 100755 --- a/catalogue/imageviewer.pl +++ b/catalogue/imageviewer.pl @@ -66,24 +66,19 @@ if( $query->cookie("searchToOrder") ){ } if ( C4::Context->preference("LocalCoverImages") ) { + my $images; if ( $itemnumber ) { my $item = Koha::Items->find($itemnumber); - my $image = $item->cover_image; - $template->param( - LocalCoverImages => 1, - images => [$image], - imagenumber => ($image ? $image->imagenumber : undef), - ); - + $images = $item->cover_images->as_list; } else { - my $images = $biblio->cover_images->as_list; - - $template->param( - LocalCoverImages => 1, - images => $images, - imagenumber => (@$images ? $images->[0]->imagenumber : undef), - ); + $images = $biblio->cover_images->as_list; } + + $template->param( + LocalCoverImages => 1, + images => $images, + imagenumber => (@$images ? $images->[0]->imagenumber : undef), + ); } $template->{VARS}->{'count'} = $itemcount; $template->{VARS}->{'biblionumber'} = $biblionumber; diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss index 9a7470546e..d313d9aeb9 100644 --- a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss +++ b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss @@ -2117,7 +2117,7 @@ li { display: inline-block; } -#bookcoverimg { +.bookcoverimg { text-align: center; } @@ -2127,13 +2127,16 @@ li { } } -.cover-slides { - background: #FFF url("[% interface | html %]/[% theme | html %]/img/spinner-small.gif") center center no-repeat; +#biblio-cover-slider { border: 1px solid #b9d8d9; border-radius: 3px; margin: 5px; padding: 10px 5px 5px 5px; min-height: 175px; +} + +.cover-slides { + background: #FFF url("[% interface | html %]/[% theme | html %]/img/spinner-small.gif") center center no-repeat; .hint { font-size: 90%; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref index 7e7cdfaaa7..abd8269440 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref @@ -316,7 +316,7 @@ Enhanced content: choices: yes: Allow no: "Don't allow" - - multiple images to be attached to each bibliographic record. + - multiple images to be attached to each bibliographic record and item. - - pref: CustomCoverImages choices: diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt index a0fd66876d..6e0d1f78a8 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt @@ -166,8 +166,8 @@ [% IF ( AmazonCoverImages || LocalCoverImages || AdlibrisEnabled || IntranetCoce || (Koha.Preference('CustomCoverImages') && Koha.Preference('CustomCoverImagesURL')) ) %] -
-
+
+
[% IF ( LocalCoverImages ) %] [% IF localimages.count %] [% FOREACH image IN localimages %] @@ -219,8 +219,8 @@
Custom cover image
[% END %] -
-
+
+ [% ELSE %] [% END # /IF ( AmazonCoverImages, etc ) %] @@ -326,11 +326,17 @@ [% END %] [% IF ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %] - [% IF item.imagenumber %] - - - - [% END %] +
+
+ [% FOREACH image IN item.cover_images %] +
+ + Local cover image + +
+ [% END %] +
+
[% END %] @@ -986,71 +992,75 @@ Note that permanent location is a code, and location may be an authval. // http://www.oreillynet.com/pub/a/javascript/2003/10/21/amazonhacks.html function verify_images() { // Loop over each container in the template which contains covers - $(".cover-image").each( function( index ){ - var div = $(this); - // Find the image in the container - var img = div.find("img")[0]; - if( $(img).length > 0 ){ - if( (img.complete != null) && (!img.complete) || img.naturalHeight == 0 ){ - // No image loaded in the container. Remove the slide - div.remove(); - } else { - // All slides start hidden. If this is the first one, show it. - if( index == 0 ){ - div.show(); - } - // Check if Amazon image is present - if ( div.attr("id") == "amazon-bookcoverimg" ) { - w = img.width; - h = img.height; - if ((w == 1) || (h == 1)) { - // Amazon returned single-pixel placeholder - // Remove the container - div.remove(); + $(".cover-slider").each(function(){ + $(this).find(".cover-image").each( function( index ){ + var div = $(this); + // Find the image in the container + var img = div.find("img")[0]; + if( $(img).length > 0 ){ + if( (img.complete != null) && (!img.complete) || img.naturalHeight == 0 ){ + // No image loaded in the container. Remove the slide + div.remove(); + } else { + // All slides start hidden. If this is the first one, show it. + if( index == 0 ){ + div.show(); } - } - if( div.attr("id") == "custom-img" ){ - if ( (img.complete != null) && (!img.complete) || img.naturalHeight == 0 ) { - // No image was loaded via the CustomCoverImages system preference - // Remove the container - div.remove(); + // Check if Amazon image is present + if ( div.attr("id") == "amazon-bookcoverimg" ) { + w = img.width; + h = img.height; + if ((w == 1) || (h == 1)) { + // Amazon returned single-pixel placeholder + // Remove the container + div.remove(); + } } - } - if( div.attr("id") == "coce-coverimg" ){ - // Identify which service's image is being loaded by Coce - if( $(img).attr("src").indexOf('amazon.com') >= 0 ){ - div.find(".hint").html(_("Coce image from Amazon.com")); - } else if( $(img).attr("src").indexOf('google.com') >= 0 ){ - div.find(".hint").html(_("Coce image from Google Books")); - } else if( $(img).attr("src").indexOf('openlibrary.org') >= 0 ){ - div.find(".hint").html(_("Coce image from Open Library")); + if( div.attr("id") == "custom-img" ){ + if ( (img.complete != null) && (!img.complete) || img.naturalHeight == 0 ) { + // No image was loaded via the CustomCoverImages system preference + // Remove the container + div.remove(); + } + } + if( div.attr("id") == "coce-coverimg" ){ + // Identify which service's image is being loaded by Coce + if( $(img).attr("src").indexOf('amazon.com') >= 0 ){ + div.find(".hint").html(_("Coce image from Amazon.com")); + } else if( $(img).attr("src").indexOf('google.com') >= 0 ){ + div.find(".hint").html(_("Coce image from Google Books")); + } else if( $(img).attr("src").indexOf('openlibrary.org') >= 0 ){ + div.find(".hint").html(_("Coce image from Open Library")); + } } } } - } + }); }); - var coverSlides = $(".cover-image"); - if( coverSlides.length > 1 ){ - coverSlides.each(function( index ){ - // If more that one slide is present, add a navigation link - // for activating the slide - var covernav = $(""); - if( index == 0 ){ - // Set the first navigation link as active - $(covernav).addClass("nav-active"); - } - $(covernav).html(""); - $("#cover-slides").append( covernav ); - - }); - } + $(".cover-slider").each(function(){ + var coverSlide = this; + var coverImages = $(this).find(".cover-image"); + if( coverImages.length > 1 ){ + coverImages.each(function( index ){ + // If more that one image is present, add a navigation link + // for activating the slide + var covernav = $(""); + if( index == 0 ){ + // Set the first navigation link as active + $(covernav).addClass("nav-active"); + } + $(covernav).html(""); + $(coverSlide).append( covernav ); + }); + } - if( $(".cover-image:visible").length < 1 ){ - $("#cover-slides").remove(); - } else { - $("#cover-slides").addClass("cover-slides"); - } + if( $(coverSlide).find(".cover-image:visible").length < 1 ){ + $(coverSlide).remove(); + } else { + $(coverSlide).addClass("cover-slides"); + } + }); $("#editions img").each(function(i){ if ( this.src.indexOf('amazon.com') >= 0 ) { @@ -1223,14 +1233,15 @@ Note that permanent location is a code, and location may be an authval. link = $(this).attr("href"); openWindow(link,"Print spine label",400,400); }); - $("#cover-slides").on("click",".cover-nav", function(e){ + $(".cover-slider").on("click",".cover-nav", function(e){ e.preventDefault(); + var cover_slider = $(this).parent(); // Adding click handler for cover image navigation links var num = $(this).data("num"); - $(".cover-nav").removeClass("nav-active"); + $(cover_slider).find(".cover-nav").removeClass("nav-active"); $(this).addClass("nav-active"); - $(".cover-image").hide(); - $(".cover-image").eq( num ).show(); + $(cover_slider).find(".cover-image").hide(); + $(cover_slider).find(".cover-image").eq( num ).show(); }); }); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt index 9abce8f7ec..9ebb48e462 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt @@ -100,7 +100,7 @@ Options
  1. - [% IF AllowMultipleCovers == 0 OR itemnumber%] + [% IF AllowMultipleCovers == 0 %] [% ELSE %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt index 8e531bafcc..1c3cbf464c 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt @@ -1267,7 +1267,9 @@ [% IF ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %] -
    + [% FOR image IN ITEM_RESULT.cover_images %] +
    + [% END %] [% END %] diff --git a/opac/opac-detail.pl b/opac/opac-detail.pl index 67c074cd70..8b935af155 100755 --- a/opac/opac-detail.pl +++ b/opac/opac-detail.pl @@ -763,22 +763,21 @@ if ( not $viewallitems and @items > $max_items_to_display ) { } if ( C4::Context->preference("OPACLocalCoverImages") == 1 ) { - my $cover_image = $item->cover_image; - $itm->{imagenumber} = $cover_image ? $cover_image->imagenumber : undef; + $itm->{cover_images} = $item->cover_images; } my $itembranch = $itm->{$separatebranch}; if ($currentbranch and C4::Context->preference('OpacSeparateHoldings')) { if ($itembranch and $itembranch eq $currentbranch) { push @itemloop, $itm; - $itemloop_has_images++ if $itm->{imagenumber}; + $itemloop_has_images++ if $item->cover_images->count; } else { push @otheritemloop, $itm; - $otheritemloop_has_images++ if $itm->{imagenumber}; + $otheritemloop_has_images++ if $item->cover_images->count; } } else { push @itemloop, $itm; - $itemloop_has_images++ if $itm->{imagenumber}; + $itemloop_has_images++ if $item->cover_images->count; } } } diff --git a/t/db_dependent/Koha/CoverImages.t b/t/db_dependent/Koha/CoverImages.t index 66067df9b7..ff4c12ed54 100644 --- a/t/db_dependent/Koha/CoverImages.t +++ b/t/db_dependent/Koha/CoverImages.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 13; +use Test::More tests => 14; use Test::Exception; use FindBin '$Bin'; @@ -70,16 +70,16 @@ $image = Koha::CoverImage->new( )->store; is( $biblio->cover_images->count, 2, 'There are now two cover images' ); -is( $item->cover_image, undef, 'No cover images yet' ); +is( $item->cover_images->count, 0, 'No cover images yet' ); $image = Koha::CoverImage->new( { itemnumber => $item->itemnumber, src_image => GD::Image->new($logo_filepath) } )->store; -is( ref( $item->cover_image ), +is( ref( $item->cover_images->next ), 'Koha::CoverImage', - 'Koha::Item->cover_image returns a Koha::CoverImage object' ); + 'Koha::Item->cover_images returns a rs of Koha::CoverImage object' ); Koha::CoverImage->new( { @@ -89,5 +89,6 @@ Koha::CoverImage->new( } )->store; is( $biblio->cover_images->count, 3, ); +is( $item->cover_images->count, 2, ); $schema->storage->txn_rollback; diff --git a/tools/upload-cover-image.pl b/tools/upload-cover-image.pl index 85cbedc465..6c19de1e99 100755 --- a/tools/upload-cover-image.pl +++ b/tools/upload-cover-image.pl @@ -94,11 +94,12 @@ if ($fileID) { $fh->close if $fh; if ( defined $srcimage ) { eval { - if ( $replace && $biblionumber ) { - Koha::Biblios->find($biblionumber)->cover_images->delete; - } elsif ( $itemnumber ) { - my $cover_image = Koha::Items->find($itemnumber)->cover_image; - $cover_image->delete if $cover_image; + if ( $replace ) { + if ( $biblionumber ) { + Koha::Biblios->find($biblionumber)->cover_images->delete; + } elsif ( $itemnumber ) { + Koha::Items->find($itemnumber)->cover_images->delete; + } } Koha::CoverImage->new( @@ -181,10 +182,12 @@ if ($fileID) { if ( defined $srcimage ) { $total++; eval { - if ( $replace && $biblionumber ) { - Koha::Biblios->find($biblionumber)->cover_images->delete; - } elsif ( $itemnumber ) { - Koha::Items->find($itemnumber)->cover_image->delete; + if ( $replace ) { + if ( $biblionumber ) { + Koha::Biblios->find($biblionumber)->cover_images->delete; + } elsif ( $itemnumber ) { + Koha::Items->find($itemnumber)->cover_images->delete; + } } Koha::CoverImage->new( -- 2.20.1