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)

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
This commit is contained in:
Jonathan Druart 2020-08-11 18:26:01 +02:00
parent 7bc87ce75e
commit a06223a20d
11 changed files with 130 additions and 118 deletions

View File

@ -782,19 +782,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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -2115,7 +2115,7 @@ li {
display: inline-block;
}
#bookcoverimg {
.bookcoverimg {
text-align: center;
}
@ -2125,13 +2125,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%;

View File

@ -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:

View File

@ -166,8 +166,8 @@
[% IF ( AmazonCoverImages || LocalCoverImages || AdlibrisEnabled || IntranetCoce || (Koha.Preference('CustomCoverImages') && Koha.Preference('CustomCoverImagesURL')) ) %]
</div>
<div class="col-xs-3" id="bookcoverimg">
<div id="cover-slides">
<div class="col-xs-3 bookcoverimg">
<div id="biblio-cover-slider" class="cover-slider">
[% IF ( LocalCoverImages ) %]
[% IF localimages.count %]
[% FOREACH image IN localimages %]
@ -219,8 +219,8 @@
<div class="hint">Custom cover image</div>
</div>
[% END %]
</div> <!-- /#cover-slides -->
</div> <!-- /#bookcoverimg.col-xs-3 -->
</div> <!-- /.cover-slider -->
</div> <!-- /.bookcoverimg.col-xs-3 -->
[% ELSE %]
</div> <!-- /.col-xs-* -->
[% END # /IF ( AmazonCoverImages, etc ) %]
@ -326,11 +326,17 @@
[% END %]
[% IF ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %]
<td class="cover">
[% IF item.imagenumber %]
<a href="/cgi-bin/koha/catalogue/imageviewer.pl?itemnumber=[% item.itemnumber | uri %]&amp;imagenumber=[% item.imagenumber | uri %]">
<img src="/cgi-bin/koha/catalogue/image.pl?thumbnail=1amp;imagenumber=[% item.imagenumber | uri %]" />
</a>
[% END %]
<div class="bookcoverimg">
<div class="cover-slider">
[% FOREACH image IN item.cover_images %]
<div class="cover-image local-coverimg">
<a href="/cgi-bin/koha/catalogue/imageviewer.pl?itemnumber=[% image.itemnumber | uri %]&amp;imagenumber=[% image.imagenumber | uri %]">
<img src="/cgi-bin/koha/catalogue/image.pl?thumbnail=1&amp;imagenumber=[% image.imagenumber | uri %]" alt="Local cover image" />
</a>
</div>
[% END %]
</div>
</div>
</td>
[% 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 = $("<a href=\"#\" data-num=\"" + index + "\" class=\"cover-nav\"></a>");
if( index == 0 ){
// Set the first navigation link as active
$(covernav).addClass("nav-active");
}
$(covernav).html("<i class=\"fa fa-circle\"></i>");
$("#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 = $("<a href=\"#\" data-num=\"" + index + "\" class=\"cover-nav\"></a>");
if( index == 0 ){
// Set the first navigation link as active
$(covernav).addClass("nav-active");
}
$(covernav).html("<i class=\"fa fa-circle\"></i>");
$(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();
});
});

View File

@ -100,7 +100,7 @@
<legend>Options</legend>
<ol>
<li class="checkbox">
[% IF AllowMultipleCovers == 0 OR itemnumber%]
[% IF AllowMultipleCovers == 0 %]
<input type="checkbox" id="replace" name="replace" checked="checked" disabled="disabled" value="1" />
[% ELSE %]
<input type="checkbox" id="replace" name="replace" value="1" />

View File

@ -1267,7 +1267,9 @@
[% IF ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %]
<td class="cover">
<div title="[% ITEM_RESULT.itemnumber | html %]" data-imagenumber="[% ITEM_RESULT.imagenumber | html %]" data-biblionumber="[% ITEM_RESULT.biblionumber %]" class="local-thumbnail-preview"></div>
[% FOR image IN ITEM_RESULT.cover_images %]
<div title="[% ITEM_RESULT.itemnumber | html %]" data-imagenumber="[% image.imagenumber | html %]" data-biblionumber="[% ITEM_RESULT.biblionumber | html %]" class="local-thumbnail-preview"></div>
[% END %]
</td>
[% END %]

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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(