Bug 10856: Improve the previous and next items on the shelf browser
authorJonathan Druart <jonathan.druart@biblibre.com>
Tue, 14 May 2013 13:11:11 +0000 (15:11 +0200)
committerGalen Charlton <gmc@esilibrary.com>
Fri, 4 Oct 2013 15:56:35 +0000 (15:56 +0000)
The next and previous links should completely refresh the shelf.

For example:
[<] [1] [2] [3] [4] [5] [6] [>]
Before this patch, the next and previous links were the same as the 1
and 6.
With this patch, after clicking on next, we will get:
[<] [7] [8] [9] [10] [11] [12] [13] [>]

This patch adds a new AJAX script to get the shelf browser block.

Test plan:
- On a detail biblio page, click on a "Browse shelf" link.
- Play with the next and previous links.
- Deactivate Javascript (using NoScript for example) and check that you
  get the same behavior (but the page is reloaded).
- Launch the unit tests: prove t/db_dependent/ShelfBrowser.t

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Katrin Fischer <Katrin.Fischer.83@web.de>
Passes all tests and QA script.

Signed-off-by: Galen Charlton <gmc@esilibrary.com>

C4/ShelfBrowser.pm
koha-tmpl/opac-tmpl/prog/en/includes/shelfbrowser.inc [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt
koha-tmpl/opac-tmpl/prog/en/modules/svc/shelfbrowser.tt [new file with mode: 0644]
opac/opac-detail.pl
opac/svc/shelfbrowser.pl [new file with mode: 0755]
t/db_dependent/ShelfBrowser.t [new file with mode: 0644]

index c885d90..555ad05 100644 (file)
@@ -63,10 +63,9 @@ to take into account.
 
   $nearby = GetNearbyItems($itemnumber, [$num_each_side]);
 
-  @next = @{ $nearby->{next} };
-  @prev = @{ $nearby->{prev} };
+  @items = @{ $nearby->{items} };
 
-  foreach (@next) {
+  foreach (@items) {
       # These won't format well like this, but here are the fields
          print $_->{title};
          print $_->{biblionumber};
@@ -78,10 +77,10 @@ to take into account.
 
   # This is the information required to scroll the browser to the next left
   # or right set. Can be derived from next/prev, but it's here for convenience.
-  print $nearby->{prev_itemnumber};
-  print $nearby->{next_itemnumber};
-  print $nearby->{prev_biblionumber};
-  print $nearby->{next_biblionumber};
+  print $nearby->{prev_item}{itemnumber};
+  print $nearby->{next_item}{itemnumber};
+  print $nearby->{prev_item}{biblionumber};
+  print $nearby->{next_item}{biblionumber};
 
   # These will be undef if the values are not used to calculate the 
   # nearby items.
@@ -92,8 +91,6 @@ to take into account.
   print $nearby->{starting_ccode}->{code};
   print $nearby->{starting_ccode}->{description};
 
-  print $nearby->{starting_itemnumber};
-  
 This finds the items that are nearby to the supplied item, and supplies
 those previous and next, along with the other useful information for displaying
 the shelf browser.
@@ -113,11 +110,13 @@ This will throw an exception if something went wrong.
 =cut
 
 sub GetNearbyItems {
-       my ($itemnumber, $num_each_side) = @_;
-       $num_each_side ||= 3;
+    my ( $itemnumber, $num_each_side, $gap) = @_;
+    $num_each_side ||= 3;
+    $gap ||= 7; # Should be > $num_each_side
+    die "BAD CALL in C4::ShelfBrowser::GetNearbyItems, gap should be > num_each_side"
+        if $gap <= $num_each_side;
 
     my $dbh         = C4::Context->dbh;
-    my $marcflavour = C4::Context->preference("marcflavour");
     my $branches = GetBranches();
 
     my $sth_get_item_details = $dbh->prepare("SELECT cn_sort,homebranch,location,ccode from items where itemnumber=?");
@@ -145,12 +144,12 @@ sub GetNearbyItems {
 
     # Build the query for previous and next items
     my $prev_query ='
-        SELECT *
+        SELECT itemnumber, biblionumber, cn_sort, itemcallnumber
         FROM items
         WHERE
             ((cn_sort = ? AND itemnumber < ?) OR cn_sort < ?) ';
     my $next_query ='
-        SELECT *
+        SELECT itemnumber, biblionumber, cn_sort, itemcallnumber
         FROM items
         WHERE
             ((cn_sort = ? AND itemnumber >= ?) OR cn_sort > ?) ';
@@ -170,60 +169,68 @@ sub GetNearbyItems {
        push @params, $start_ccode->{code};
     }
 
-    my $sth_prev_items = $dbh->prepare($prev_query . $query_cond . ' ORDER BY cn_sort DESC, itemnumber LIMIT ?');
-    my $sth_next_items = $dbh->prepare($next_query . $query_cond . ' ORDER BY cn_sort, itemnumber LIMIT ?');
-    push @params, $num_each_side;
-    $sth_prev_items->execute(@params);
-    $sth_next_items->execute(@params);
-    
-    # Now we have the query run, suck out the data like marrow
-    my @prev_items = reverse GetShelfInfo($sth_prev_items, $marcflavour);
-    my @next_items = GetShelfInfo($sth_next_items, $marcflavour);
-
-    my (
-        $next_itemnumber, $next_biblionumber,
-        $prev_itemnumber, $prev_biblionumber
-    );
-
-    $next_itemnumber = $next_items[-1]->{itemnumber} if @next_items;
-    $next_biblionumber = $next_items[-1]->{biblionumber} if @next_items;
-
-    $prev_itemnumber = $prev_items[0]->{itemnumber} if @prev_items;
-    $prev_biblionumber = $prev_items[0]->{biblionumber} if @prev_items;
-
-    my %result = (
-        next                => \@next_items,
-        prev                => \@prev_items,
-        next_itemnumber     => $next_itemnumber,
-        next_biblionumber   => $next_biblionumber,
-        prev_itemnumber     => $prev_itemnumber,
-        prev_biblionumber   => $prev_biblionumber,   
-        starting_itemnumber => $itemnumber,
-    );
-    $result{starting_homebranch} = $start_homebranch if $start_homebranch;
-    $result{starting_location}   = $start_location   if $start_location;
-    $result{starting_ccode}         = $start_ccode      if $start_ccode;
-    return \%result;
+    my @prev_items = @{
+        $dbh->selectall_arrayref(
+            $prev_query . $query_cond . ' ORDER BY cn_sort DESC, itemnumber LIMIT ?',
+            { Slice => {} },
+            ( @params, $gap )
+        )
+    };
+    my @next_items = @{
+        $dbh->selectall_arrayref(
+            $next_query . $query_cond . ' ORDER BY cn_sort, itemnumber LIMIT ?',
+            { Slice => {} },
+            ( @params, $gap + 1 )
+        )
+    };
+
+    my $prev_item = $prev_items[-1];
+    my $next_item = $next_items[-1];
+    @next_items = splice( @next_items, 0, $num_each_side + 1 );
+    @prev_items = reverse splice( @prev_items, 0, $num_each_side );
+    my @items = ( @prev_items, @next_items );
+
+    $next_item = undef
+        if not $next_item
+            or ( $next_item->{itemnumber} == $items[-1]->{itemnumber}
+                and ( @prev_items or @next_items <= 1 )
+            );
+    $prev_item = undef
+        if not $prev_item
+            or ( $prev_item->{itemnumber} == $items[0]->{itemnumber}
+                and ( @next_items or @prev_items <= 1 )
+            );
+
+    # populate the items
+    @items = GetShelfInfo( @items );
+
+    return {
+        items               => \@items,
+        next_item           => $next_item,
+        prev_item           => $prev_item,
+        starting_homebranch => $start_homebranch,
+        starting_location   => $start_location,
+        starting_ccode      => $start_ccode,
+    };
 }
 
-# This runs through a statement handle and pulls out all the items in it, fills
-# them up with additional info that shelves want, and returns those as a list.
+# populate an item list with its title and upc, oclc and isbn normalized.
 # Not really intended to be exported.
 sub GetShelfInfo {
-    my ($sth, $marcflavour) = @_;
-
-    my @items;
-    while (my $this_item = $sth->fetchrow_hashref()) {
-        my $this_biblio = GetBibData($this_item->{biblionumber});
-        next if (!defined($this_biblio));
-        $this_item->{'title'} = $this_biblio->{'title'};
+    my @items = @_;
+    my $marcflavour = C4::Context->preference("marcflavour");
+    my @valid_items;
+    for my $item ( @items ) {
+        my $this_biblio = GetBibData($item->{biblionumber});
+        next unless defined $this_biblio;
+        $item->{'title'} = $this_biblio->{'title'};
         my $this_record = GetMarcBiblio($this_biblio->{'biblionumber'});
-        $this_item->{'browser_normalized_upc'} = GetNormalizedUPC($this_record,$marcflavour);
-        $this_item->{'browser_normalized_oclc'} = GetNormalizedOCLCNumber($this_record,$marcflavour);
-        $this_item->{'browser_normalized_isbn'} = GetNormalizedISBN(undef,$this_record,$marcflavour);
-        push @items, $this_item;
+        $item->{'browser_normalized_upc'} = GetNormalizedUPC($this_record,$marcflavour);
+        $item->{'browser_normalized_oclc'} = GetNormalizedOCLCNumber($this_record,$marcflavour);
+        $item->{'browser_normalized_isbn'} = GetNormalizedISBN(undef,$this_record,$marcflavour);
+        push @valid_items, $item;
     }
-    return @items;
+    return @valid_items;
 }
 
 # Fetches some basic biblio data needed by the shelf stuff
diff --git a/koha-tmpl/opac-tmpl/prog/en/includes/shelfbrowser.inc b/koha-tmpl/opac-tmpl/prog/en/includes/shelfbrowser.inc
new file mode 100644 (file)
index 0000000..c41647a
--- /dev/null
@@ -0,0 +1,125 @@
+[% BLOCK shelfbrowser %]
+  [% IF OpenOPACShelfBrowser %]
+    <div id="shelfbrowser">
+        <h5 style="text-align: center;">
+            [% IF ( starting_homebranch ) %]Browsing [% starting_homebranch %] Shelves[% END %]
+            [% IF ( starting_location ) %], Shelving location: [% starting_location %][% END %]
+            [% IF ( starting_ccode ) %], Collection code: [% starting_ccode %][% END %]
+            <a style="font-size: 75%;" href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% biblionumber %]" class="close_shelf" >Close shelf browser</a>
+        </h5>
+
+        <table>
+            <tr>
+                <td rowspan="2" style="width:20px;">
+                  [% IF shelfbrowser_prev_item %]
+                    <div id="browser_previous">
+                        <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% shelfbrowser_prev_item.biblionumber %]&amp;shelfbrowse_itemnumber=[% shelfbrowser_prev_item.itemnumber %]#shelfbrowser">Previous</a>
+                    </div>
+                  [% END %]
+                </td>
+
+                [% FOREACH item IN shelfbrowser_items %]
+                    <td>
+                        <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% item.biblionumber %]&amp;shelfbrowse_itemnumber=[% item.itemnumber %]#shelfbrowser">
+                            [% IF ( OPACLocalCoverImages ) %]
+                                <div title="[% item.biblionumber |url %]" class="[% item.biblionumber %] thumbnail-shelfbrowser" id="local-thumbnail-shelf-[% item.biblionumber %]"></div>
+                            [% END %]
+                            [% IF ( OPACAmazonCoverImages ) %]
+                                [% IF ( item.browser_normalized_isbn ) %]
+                                    <img border="0" src="http://images.amazon.com/images/P/[% item.browser_normalized_isbn %].01._AA75_PU_PU-5_.jpg" alt="" />
+                                [% ELSE %]
+                                    <span class="no-image">No cover image available</span>
+                                [% END %]
+                            [% END %]
+
+                            [% IF ( SyndeticsEnabled ) %]
+                                [% IF ( SyndeticsCoverImages ) %]
+                                    [% IF ( content_identifier_exists ) %]
+                                        [% IF ( using_https ) %]
+                                            <img border="0" src="https://secure.syndetics.com/index.aspx?isbn=[% item.browser_normalized_isbn %]/SC.GIF&amp;client=[% SyndeticsClientCode %][% IF ( item.browser_normalized_upc ) %]&amp;upc=[% item.browser_normalized_upc %][% END %][% IF ( item.browser_normalized_oclc ) %]&amp;oclc=[% item.browser_normalized_oclc %][% END %]&amp;type=xw10" alt="" />
+                                        [% ELSE %]
+                                            <img border="0" src="http://www.syndetics.com/index.aspx?isbn=[% item.browser_normalized_isbn %]/SC.GIF&amp;client=[% SyndeticsClientCode %][% IF ( item.browser_normalized_upc ) %]&amp;upc=[% item.browser_normalized_upc %][% END %][% IF ( item.browser_normalized_oclc ) %]&amp;oclc=[% item.browser_normalized_oclc %][% END %]&amp;type=xw10" alt="" />
+                                        [% END %]
+                                    [% ELSE %]
+                                        <span class="no-image">No cover image available</span>
+                                    [% END %]
+                                [% END %]
+                            [% END %]
+
+                            [% IF ( GoogleJackets ) %]
+                                [% IF ( item.browser_normalized_isbn ) %]
+                                    <div style="block" title="[% item.biblionumber |url %]" class="[% item.browser_normalized_isbn %]" id="gbs-thumbnail-preview[% loop.count %]"></div>
+                                [% ELSE %]
+                                    <span class="no-image">No cover image available</span>
+                                [% END %]
+                            [% END %]
+                            [% IF ( BakerTaylorEnabled ) %]
+                                [% IF ( item.browser_normalized_isbn ) %]
+                                    <img alt="See Baker &amp; Taylor" src="[% BakerTaylorImageURL |html %][% item.browser_normalized_isbn %]" />
+                                [% ELSE %]
+                                    <span class="no-image">No cover image available</span>
+                                [% END %]
+                            [% END %]
+                        </a>
+                    </td>
+                [% END %]
+
+                <td rowspan="2" style="width:20px;">
+                  [% IF shelfbrowser_next_item %]
+                    <div id="browser_next">
+                        <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% shelfbrowser_prev_item.biblionumber %]&amp;shelfbrowse_itemnumber=[% shelfbrowser_prev_item.itemnumber %]#shelfbrowser">Next</a>
+                    </div>
+                  [% END %]
+                </td>
+            </tr>
+
+            <tr>
+                [% FOREACH item IN shelfbrowser_items %]
+                    <td class="top">
+                        [% item.itemcallnumber %]
+                        <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% item.biblionumber %]&amp;shelfbrowse_itemnumber=[% item.itemnumber %]#shelfbrowser">[% item.title |html %]</a>
+                    </td>
+                [% END %]
+            </tr>
+        </table>
+    </div>
+    <script type="text/javascript">
+      $(document).ready(function(){
+        $(".close_shelf").click(function(e){
+            e.preventDefault();
+            $("#shelfbrowser").hide();
+        });
+        [% IF shelfbrowser_prev_item.itemnumber %]
+          $("#browser_previous a").click(function(e){
+            e.preventDefault();
+            $.ajax({
+                    url: "/cgi-bin/koha/svc/shelfbrowser.pl",
+                type: "POST",
+                data: {
+                    "shelfbrowse_itemnumber": [% shelfbrowser_prev_item.itemnumber %]
+                },
+                success: function(data){
+                    $("#shelfbrowser").replaceWith(data);
+                }
+            });
+          });
+        [% END %]
+        [% IF shelfbrowser_next_item.itemnumber %]
+          $("#browser_next a").click(function(e){
+            e.preventDefault();
+            $.ajax({
+                url: "/cgi-bin/koha/svc/shelfbrowser.pl",
+                type: "POST",
+                data: {
+                    "shelfbrowse_itemnumber": [% shelfbrowser_next_item.itemnumber %]
+                },
+                success: function(data){
+                    $("#shelfbrowser").replaceWith(data);
+                }
+            });
+          });
+        [% END %]
+      });
+    </script>
+  [% END %]
+[% END %][%# end of shelfbrowser block %]
index d6520f5..3f7053d 100644 (file)
@@ -1068,6 +1068,7 @@ YAHOO.util.Event.onContentReady("furtherm", function () {
     [% END %]
 [% END %]
 
+[% PROCESS 'shelfbrowser.inc' %]
 [% INCLUDE shelfbrowser tab='holdings' %]
 <br clear="all" />
 </div>
@@ -1588,137 +1589,3 @@ YAHOO.util.Event.onContentReady("furtherm", function () {
            [% END %]</tbody>
        </table>
 [% END %][%# end of items_table block %]
-
-[% BLOCK shelfbrowser %]
-    [% IF ( OpenOPACShelfBrowser and shelfbrowser_tab == tab) %]
-        <div id="shelfbrowser">
-            <h5 style="text-align: center;">
-                [% IF ( starting_homebranch ) %]Browsing [% starting_homebranch %] Shelves[% END %]
-                [% IF ( starting_location ) %], Shelving location: [% starting_location %][% END %]
-                [% IF ( starting_ccode ) %], Collection code: [% starting_ccode %][% END %]
-                <a style="font-size: 75%;" href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% biblionumber %]">Close shelf browser</a>
-            </h5>
-
-            <table>
-                <tr>
-                    <td rowspan="2" style="width:20px;">
-                        <div id="browser_previous">
-                            <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% IF ( shelfbrowser_prev_biblionumber ) %][% shelfbrowser_prev_biblionumber %][% ELSE %][% biblionumber %][% END %]&amp;shelfbrowse_itemnumber=[% shelfbrowser_prev_itemnumber %]#shelfbrowser">Previous</a>
-                        </div>
-                    </td>
-                    [% FOREACH PREVIOUS_SHELF_BROWS IN PREVIOUS_SHELF_BROWSE %]
-                        <td>
-                            <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% PREVIOUS_SHELF_BROWS.biblionumber %]&amp;shelfbrowse_itemnumber=[% PREVIOUS_SHELF_BROWS.itemnumber %]#shelfbrowser">
-                                [% IF ( OPACLocalCoverImages ) %]
-                                    <div title="[% PREVIOUS_SHELF_BROWS.biblionumber |url %]" class="[% PREVIOUS_SHELF_BROWS.biblionumber %] thumbnail-shelfbrowser" id="local-thumbnail-shelf-[% PREVIOUS_SHELF_BROWS.biblionumber %]"></div>
-                                [% END %]
-                                [% IF ( OPACAmazonCoverImages ) %]
-                                    [% IF ( PREVIOUS_SHELF_BROWS.browser_normalized_isbn ) %]
-                                        <img border="0" src="http://images.amazon.com/images/P/[% PREVIOUS_SHELF_BROWS.browser_normalized_isbn %].01._AA75_PU_PU-5_.jpg" alt="" />
-                                    [% ELSE %]
-                                        <span class="no-image">No cover image available</span>
-                                    [% END %]
-                                [% END %]
-                                [% IF ( SyndeticsEnabled ) %]
-                                    [% IF ( SyndeticsCoverImages ) %]
-                                        [% IF ( content_identifier_exists ) %]
-                                            [% IF ( using_https ) %]
-                                                <img border="0" src="https://secure.syndetics.com/index.aspx?isbn=[% PREVIOUS_SHELF_BROWS.browser_normalized_isbn %]/SC.GIF&amp;client=[% SyndeticsClientCode %][% IF ( PREVIOUS_SHELF_BROWS.browser_normalized_upc ) %]&amp;upc=[% PREVIOUS_SHELF_BROWS.browser_normalized_upc %][% END %][% IF ( PREVIOUS_SHELF_BROWS.browser_normalized_oclc ) %]&amp;oclc=[% PREVIOUS_SHELF_BROWS.browser_normalized_oclc %][% END %]&amp;type=xw10" alt="" />
-                                            [% ELSE %]
-                                                <img border="0" src="http://www.syndetics.com/index.aspx?isbn=[% PREVIOUS_SHELF_BROWS.browser_normalized_isbn %]/SC.GIF&amp;client=[% SyndeticsClientCode %][% IF ( PREVIOUS_SHELF_BROWS.browser_normalized_upc ) %]&amp;upc=[% PREVIOUS_SHELF_BROWS.browser_normalized_upc %][% END %][% IF ( PREVIOUS_SHELF_BROWS.browser_normalized_oclc ) %]&amp;oclc=[% PREVIOUS_SHELF_BROWS.browser_normalized_oclc %][% END %]&amp;type=xw10" alt="" />
-                                            [% END %]
-                                        [% ELSE %]
-                                            <span class="no-image">No cover image available</span>
-                                        [% END %]
-                                    [% END %]
-                                [% END %]
-                                [% IF ( GoogleJackets ) %]
-                                    [% IF ( PREVIOUS_SHELF_BROWS.browser_normalized_isbn ) %]
-                                        <div style="block" title="[% PREVIOUS_SHELF_BROWS.biblionumber |url %]" class="[% PREVIOUS_SHELF_BROWS.browser_normalized_isbn %]" id="gbs-thumbnail-preview[% loop.count %]"></div>
-                                    [% ELSE %]
-                                        <span class="no-image">No cover image available</span>
-                                    [% END %]
-                                [% END %]
-                                [% IF ( BakerTaylorEnabled ) %]
-                                    [% IF ( PREVIOUS_SHELF_BROWS.browser_normalized_isbn ) %]
-                                        <img alt="See Baker &amp; Taylor" src="[% BakerTaylorImageURL |html %][% PREVIOUS_SHELF_BROWS.browser_normalized_isbn %]" />
-                                    [% ELSE %]
-                                        <span class="no-image">No cover image available</span>
-                                    [% END %]
-                                [% END %]
-                            </a>
-                        </td>
-                    [% END %]
-
-                    [% FOREACH NEXT_SHELF_BROWS IN NEXT_SHELF_BROWSE %]
-                        <td>
-                            <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% NEXT_SHELF_BROWS.biblionumber %]&amp;shelfbrowse_itemnumber=[% NEXT_SHELF_BROWS.itemnumber %]#shelfbrowser">
-                                [% IF ( OPACLocalCoverImages ) %]
-                                    <div title="[% NEXT_SHELF_BROWS.biblionumber |url %]" class="[% NEXT_SHELF_BROWS.biblionumber %] thumbnail-shelfbrowser" id="local-thumbnail-shelf-[% NEXT_SHELF_BROWS.biblionumber %]"></div>
-                                [% END %]
-                                [% IF ( OPACAmazonCoverImages ) %]
-                                    [% IF ( NEXT_SHELF_BROWS.browser_normalized_isbn ) %]
-                                        <img border="0" src="http://images.amazon.com/images/P/[% NEXT_SHELF_BROWS.browser_normalized_isbn %].01._AA75_PU_PU-5_.jpg" alt="" />
-                                    [% ELSE %]
-                                        <span class="no-image">No cover image available</span>
-                                    [% END %]
-                                [% END %]
-
-                                [% IF ( SyndeticsEnabled ) %]
-                                    [% IF ( SyndeticsCoverImages ) %]
-                                        [% IF ( content_identifier_exists ) %]
-                                            [% IF ( using_https ) %]
-                                                <img border="0" src="https://secure.syndetics.com/index.aspx?isbn=[% NEXT_SHELF_BROWS.browser_normalized_isbn %]/SC.GIF&amp;client=[% SyndeticsClientCode %][% IF ( NEXT_SHELF_BROWS.browser_normalized_upc ) %]&amp;upc=[% NEXT_SHELF_BROWS.browser_normalized_upc %][% END %][% IF ( NEXT_SHELF_BROWS.browser_normalized_oclc ) %]&amp;oclc=[% NEXT_SHELF_BROWS.browser_normalized_oclc %][% END %]&amp;type=xw10" alt="" />
-                                            [% ELSE %]
-                                                <img border="0" src="http://www.syndetics.com/index.aspx?isbn=[% NEXT_SHELF_BROWS.browser_normalized_isbn %]/SC.GIF&amp;client=[% SyndeticsClientCode %][% IF ( NEXT_SHELF_BROWS.browser_normalized_upc ) %]&amp;upc=[% NEXT_SHELF_BROWS.browser_normalized_upc %][% END %][% IF ( NEXT_SHELF_BROWS.browser_normalized_oclc ) %]&amp;oclc=[% NEXT_SHELF_BROWS.browser_normalized_oclc %][% END %]&amp;type=xw10" alt="" />
-                                            [% END %]
-                                        [% ELSE %]
-                                            <span class="no-image">No cover image available</span>
-                                        [% END %]
-                                    [% END %]
-                                [% END %]
-
-                                [% IF ( GoogleJackets ) %]
-                                    [% IF ( NEXT_SHELF_BROWS.browser_normalized_isbn ) %]
-                                        <div style="block" title="[% NEXT_SHELF_BROWS.biblionumber |url %]" class="[% NEXT_SHELF_BROWS.browser_normalized_isbn %]" id="gbs-thumbnail-preview[% loop.count %]"></div>
-                                    [% ELSE %]
-                                        <span class="no-image">No cover image available</span>
-                                    [% END %]
-                                [% END %]
-                                [% IF ( BakerTaylorEnabled ) %]
-                                    [% IF ( NEXT_SHELF_BROWS.browser_normalized_isbn ) %]
-                                        <img alt="See Baker &amp; Taylor" src="[% BakerTaylorImageURL |html %][% NEXT_SHELF_BROWS.browser_normalized_isbn %]" />
-                                    [% ELSE %]
-                                        <span class="no-image">No cover image available</span>
-                                    [% END %]
-                                [% END %]
-                            </a>
-                        </td>
-                    [% END %]
-
-                    <td rowspan="2">
-                        <div id="browser_next">
-                            <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% IF ( shelfbrowser_next_biblionumber ) %][% shelfbrowser_next_biblionumber %][% ELSE %][% biblionumber %][% END %]&amp;shelfbrowse_itemnumber=[% shelfbrowser_next_itemnumber %]#shelfbrowser">Next</a>
-                        </div>
-                    </td>
-                </tr>
-
-                <tr>
-                    [% FOREACH PREVIOUS_SHELF_BROWS IN PREVIOUS_SHELF_BROWSE %]
-                        <td class="top">
-                            [% PREVIOUS_SHELF_BROWS.itemcallnumber %]
-                            <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% PREVIOUS_SHELF_BROWS.biblionumber %]&amp;shelfbrowse_itemnumber=[% PREVIOUS_SHELF_BROWS.itemnumber %]#shelfbrowser">[% PREVIOUS_SHELF_BROWS.title |html %]</a>
-                        </td>
-                    [% END %]
-
-                    [% FOREACH NEXT_SHELF_BROWS IN NEXT_SHELF_BROWSE %]
-                        <td class="top" style="width:20px;">
-                            [% NEXT_SHELF_BROWS.itemcallnumber %]
-                            <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% NEXT_SHELF_BROWS.biblionumber %]&amp;shelfbrowse_itemnumber=[% NEXT_SHELF_BROWS.itemnumber %]#shelfbrowser">[% NEXT_SHELF_BROWS.title |html %]</a>
-                        </td>
-                    [% END %]
-                </tr>
-            </table>
-        </div>
-    [% END %]
-[% END %][%# end of shelfbrowser block %]
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/svc/shelfbrowser.tt b/koha-tmpl/opac-tmpl/prog/en/modules/svc/shelfbrowser.tt
new file mode 100644 (file)
index 0000000..50e2b40
--- /dev/null
@@ -0,0 +1,2 @@
+[% PROCESS 'shelfbrowser.inc' %]
+[% INCLUDE shelfbrowser %]
index eb6b77f..0b5ef8c 100755 (executable)
@@ -928,19 +928,15 @@ if (C4::Context->preference("OPACShelfBrowser")) {
     my $starting_itemnumber = $query->param('shelfbrowse_itemnumber');
     if (defined($starting_itemnumber)) {
         $template->param( OpenOPACShelfBrowser => 1) if $starting_itemnumber;
-        my $nearby = GetNearbyItems($starting_itemnumber,3);
+        my $nearby = GetNearbyItems($starting_itemnumber);
 
         $template->param(
             starting_homebranch => $nearby->{starting_homebranch}->{description},
             starting_location => $nearby->{starting_location}->{description},
             starting_ccode => $nearby->{starting_ccode}->{description},
-            starting_itemnumber => $nearby->{starting_itemnumber},
-            shelfbrowser_prev_itemnumber => $nearby->{prev_itemnumber},
-            shelfbrowser_next_itemnumber => $nearby->{next_itemnumber},
-            shelfbrowser_prev_biblionumber => $nearby->{prev_biblionumber},
-            shelfbrowser_next_biblionumber => $nearby->{next_biblionumber},
-            PREVIOUS_SHELF_BROWSE => $nearby->{prev},
-            NEXT_SHELF_BROWSE => $nearby->{next},
+            shelfbrowser_prev_item => $nearby->{prev_item},
+            shelfbrowser_next_item => $nearby->{next_item},
+            shelfbrowser_items => $nearby->{items},
         );
 
         # in which tab shelf browser should open ?
diff --git a/opac/svc/shelfbrowser.pl b/opac/svc/shelfbrowser.pl
new file mode 100755 (executable)
index 0000000..33c9cde
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+
+use Modern::Perl;
+use CGI;
+
+use C4::Auth;
+use C4::Context;
+use C4::Output;
+use C4::ShelfBrowser;
+
+my $cgi = new CGI;
+
+my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+    {
+        template_name   => "svc/shelfbrowser.tt",
+        query           => $cgi,
+        type            => "opac",
+        authnotrequired => ( C4::Context->preference("OpacPublic") ? 1 : 0 ),
+        flagsrequired   => { borrow => 1 },
+    }
+);
+
+# Shelf Browser Stuff
+if (C4::Context->preference("OPACShelfBrowser")) {
+    my $starting_itemnumber = $cgi->param('shelfbrowse_itemnumber');
+    if (defined($starting_itemnumber)) {
+        my $nearby = GetNearbyItems($starting_itemnumber);
+
+        $template->param(
+            starting_homebranch => $nearby->{starting_homebranch}->{description},
+            starting_location => $nearby->{starting_location}->{description},
+            starting_ccode => $nearby->{starting_ccode}->{description},
+            shelfbrowser_prev_item => $nearby->{prev_item},
+            shelfbrowser_next_item => $nearby->{next_item},
+            shelfbrowser_items => $nearby->{items},
+            OpenOPACShelfBrowser => 1,
+        );
+    }
+}
+
+print $template->output;
diff --git a/t/db_dependent/ShelfBrowser.t b/t/db_dependent/ShelfBrowser.t
new file mode 100644 (file)
index 0000000..0730f4a
--- /dev/null
@@ -0,0 +1,212 @@
+#!/usr/bin/perl
+
+use Modern::Perl;
+use Test::More tests => 74;
+use List::Util qw( shuffle );
+use MARC::Field;
+use MARC::Record;
+
+use C4::Biblio;
+use C4::Context;
+use C4::Items;
+
+use_ok('C4::ShelfBrowser');
+
+my $dbh = C4::Context->dbh;
+$dbh->{AutoCommit} = 0;
+$dbh->{RaiseError} = 1;
+
+$dbh->do(q|DELETE FROM reserves|);
+$dbh->do(q|DELETE FROM issues|);
+$dbh->do(q|DELETE FROM items|);
+
+my $cn;
+
+# 100.100 150.100 200.100 210.100 300.000 320.000 400.100 410.100 500.100 510.100 520.100 600.000 610.000 700.100 710.100 720.100 730.100 740.100 750.100
+my @callnumbers = qw(
+    100.100
+    150.100
+    200.100
+    210.100
+    300.000
+    320.000
+    400.100
+    410.100
+    500.100
+    510.100
+    520.100
+    600.000
+    610.000
+    700.100
+    710.100
+    720.100
+    730.100
+    740.100
+    750.100
+);
+
+my $record = MARC::Record->new();
+$record->append_fields(
+    MARC::Field->new('100', ' ', ' ', a => 'Donald E. Knuth.'),
+    MARC::Field->new('245', ' ', ' ', a => 'The art of computer programming'),
+);
+my ( $biblionumber, undef, undef ) = C4::Biblio::AddBiblio($record, '');
+
+for my $callnumber ( shuffle @callnumbers ) {
+    my ( $biblionumber, undef, $itemnumber ) = C4::Items::AddItem({
+        homebranch => 'CPL',
+        holdingbranch => 'CPL',
+        itemcallnumber => $callnumber,
+    }, $biblionumber);
+    $cn->{$callnumber} = {
+        biblionumber => $biblionumber,
+        itemnumber => $itemnumber,
+        itemcallnumber => $callnumber,
+    }
+}
+
+my $nearby;
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'500.100'}{itemnumber} );
+# We have
+# < 320.000 400.100 410.100 500.100 510.100 520.100 600.000 >
+#      6       7       8      [9]       10      11      12
+# Clicking on previous, we want a link to 150.100
+is( $nearby->{prev_item}{itemcallnumber}, '150.100', "Simple case: previous link 1/2" );
+is( $nearby->{prev_item}{itemnumber}, $cn->{'150.100'}{itemnumber}, "Simple case: previous link 2/2" );
+# Clicking on next, we want a link to 730.100
+is( $nearby->{next_item}{itemcallnumber}, '720.100', "Simple case: next link 1/2" );
+is( $nearby->{next_item}{itemnumber}, $cn->{'720.100'}{itemnumber}, "Simple case: next link 2/2" );
+
+is( $nearby->{items}[0]{itemcallnumber}, '320.000', "Simple case: item 1");
+is( $nearby->{items}[1]{itemcallnumber}, '400.100', "Simple case: item 2");
+is( $nearby->{items}[2]{itemcallnumber}, '410.100', "Simple case: item 3");
+is( $nearby->{items}[3]{itemcallnumber}, '500.100', "Simple case: item 4");
+is( $nearby->{items}[4]{itemcallnumber}, '510.100', "Simple case: item 5");
+is( $nearby->{items}[5]{itemcallnumber}, '520.100', "Simple case: item 6");
+is( $nearby->{items}[6]{itemcallnumber}, '600.000', "Simple case: item 7");
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'500.100'}{itemnumber}, 2, 3 );
+# We have
+# < 400.100 410.100 500.100 510.100 520.100 >
+#      7       8      [9]       10      11
+# Clicking on previous, we want a link to 320.000
+is( $nearby->{prev_item}{itemcallnumber}, '320.000', "Test gap: previous link 1/2" );
+is( $nearby->{prev_item}{itemnumber}, $cn->{'320.000'}{itemnumber}, "Test gap: previous link 2/2" );
+# Clicking on next, we want a link to 600.000
+is( $nearby->{next_item}{itemcallnumber}, '600.000', "Test gap: next link 1/2" );
+is( $nearby->{next_item}{itemnumber}, $cn->{'600.000'}{itemnumber}, "Test gap: next link 2/2" );
+
+is( scalar( @{$nearby->{items}} ), 5, "Test gap: got 5 items" );
+is( $nearby->{items}[0]{itemcallnumber}, '400.100', "Test gap: item 1");
+is( $nearby->{items}[1]{itemcallnumber}, '410.100', "Test gap: item 2");
+is( $nearby->{items}[2]{itemcallnumber}, '500.100', "Test gap: item 3");
+is( $nearby->{items}[3]{itemcallnumber}, '510.100', "Test gap: item 4");
+is( $nearby->{items}[4]{itemcallnumber}, '520.100', "Test gap: item 5");
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'300.000'}{itemnumber} );
+# We have
+# < 150.100 200.100 210.100 300.000 320.000 400.100 410.100 >
+#      2       3       4      [5]      6       7       8
+# Clicking on previous, we want a link to 100.100
+is( $nearby->{prev_item}{itemcallnumber}, '100.100', "Test start shelf: previous link 1/2" );
+is( $nearby->{prev_item}{itemnumber}, $cn->{'100.100'}{itemnumber}, "Test start shelf: previous link 2/2" );
+# Clicking on next, we want a link to 600.000
+is( $nearby->{next_item}{itemcallnumber}, '600.000', "Test start shelf: next link 1/2" );
+is( $nearby->{next_item}{itemnumber}, $cn->{'600.000'}{itemnumber}, "Test start shelf: next link 2/2" );
+
+is( $nearby->{items}[0]{itemcallnumber}, '150.100', "Test start shelf: item 1");
+is( $nearby->{items}[1]{itemcallnumber}, '200.100', "Test start shelf: item 2");
+is( $nearby->{items}[2]{itemcallnumber}, '210.100', "Test start shelf: item 3");
+is( $nearby->{items}[3]{itemcallnumber}, '300.000', "Test start shelf: item 4");
+is( $nearby->{items}[4]{itemcallnumber}, '320.000', "Test start shelf: item 5");
+is( $nearby->{items}[5]{itemcallnumber}, '400.100', "Test start shelf: item 6");
+is( $nearby->{items}[6]{itemcallnumber}, '410.100', "Test start shelf: item 7");
+
+
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'100.100'}{itemnumber} );
+# We have
+# 100.100 150.100 200.100 210.100 >
+#   [1]       2       3       4
+# There is no previous link
+is( $nearby->{prev_item}, undef, "Test first item on a shelf: no previous link" );
+# Clicking on next, we want a link to 410.100
+is( $nearby->{next_item}{itemcallnumber}, '410.100', "Test first item on a shelf: next link 1/2" );
+is( $nearby->{next_item}{itemnumber}, $cn->{'410.100'}{itemnumber}, "Test first item on a shelf: next link 2/2" );
+
+is( scalar( @{$nearby->{items}} ), 4, "Test first item on a shelf: There are 4 items displayed" );
+is( $nearby->{items}[0]{itemcallnumber}, '100.100', "Test first item on a shelf: item 1");
+is( $nearby->{items}[1]{itemcallnumber}, '150.100', "Test first item on a shelf: item 2");
+is( $nearby->{items}[2]{itemcallnumber}, '200.100', "Test first item on a shelf: item 3");
+is( $nearby->{items}[3]{itemcallnumber}, '210.100', "Test first item on a shelf: item 4");
+
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'150.100'}{itemnumber} );
+# We have
+# 100.100 150.100 200.100 210.100 300.000 >
+#    1      [2]       3       4      5
+# There is no previous link
+is( $nearby->{prev_item}, undef, "Test second item on a shelf: no previous link" );
+# Clicking on next, we want a link to 500.100
+is( $nearby->{next_item}{itemcallnumber}, '500.100', "Test second item on a shelf: next link 1/2" );
+is( $nearby->{next_item}{itemnumber}, $cn->{'500.100'}{itemnumber}, "Test second item on a shelf: next link 2/2" );
+
+is( scalar( @{$nearby->{items}} ), 5, "Test second item on a shelf: got 5 items" );
+is( $nearby->{items}[0]{itemcallnumber}, '100.100', "Test second item on a shelf: item 1");
+is( $nearby->{items}[1]{itemcallnumber}, '150.100', "Test second item on a shelf: item 2");
+is( $nearby->{items}[2]{itemcallnumber}, '200.100', "Test second item on a shelf: item 3");
+is( $nearby->{items}[3]{itemcallnumber}, '210.100', "Test second item on a shelf: item 4");
+is( $nearby->{items}[4]{itemcallnumber}, '300.000', "Test second item on a shelf: item 5");
+
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'710.100'}{itemnumber} );
+# We have
+# < 600.000 610.000 700.100 710.100 720.100 730.100 740.100 >
+#      12      13      14     [15]     16      17      18
+# Clicking on previous, we want a link to 410.100
+is( $nearby->{prev_item}{itemcallnumber}, '410.100', "Test end shelf: previous link 1/2" );
+is( $nearby->{prev_item}{itemnumber}, $cn->{'410.100'}{itemnumber}, "Test end shelf: previous link 2/2" );
+# Clicking on next, we want a link to 730.100
+is( $nearby->{next_item}{itemcallnumber}, '750.100', "Test end shelf: next link is a link to the last item 1/2" );
+is( $nearby->{next_item}{itemnumber}, $cn->{'750.100'}{itemnumber}, "Test end shelf: next link is a link to the last item 2/2" );
+
+is( $nearby->{items}[0]{itemcallnumber}, '600.000', "Test end shelf: item 1");
+is( $nearby->{items}[1]{itemcallnumber}, '610.000', "Test end shelf: item 2");
+is( $nearby->{items}[2]{itemcallnumber}, '700.100', "Test end shelf: item 3");
+is( $nearby->{items}[3]{itemcallnumber}, '710.100', "Test end shelf: item 4");
+is( $nearby->{items}[4]{itemcallnumber}, '720.100', "Test end shelf: item 5");
+is( $nearby->{items}[5]{itemcallnumber}, '730.100', "Test end shelf: item 6");
+is( $nearby->{items}[6]{itemcallnumber}, '740.100', "Test end shelf: item 7");
+
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'740.100'}{itemnumber} );
+# We have
+# < 710.100 720.100 730.100 740.100 750.100
+#      15      16      17     [18]     19
+# Clicking on previous, we want a link to
+is( $nearby->{prev_item}{itemcallnumber}, '520.100', "Test end of the shelf: previous link 1/2" );
+is( $nearby->{prev_item}{itemnumber}, $cn->{'520.100'}{itemnumber}, "Test end of the shelf: previous link 2/2" );
+# No next link
+is( $nearby->{next_item}, undef, "Test end of the shelf: no next link" );
+
+is( scalar( @{$nearby->{items}} ), 5, "Test end of the shelf: got 5 items" );
+is( $nearby->{items}[0]{itemcallnumber}, '710.100', "Test end of the shelf: item 1");
+is( $nearby->{items}[1]{itemcallnumber}, '720.100', "Test end of the shelf: item 2");
+is( $nearby->{items}[2]{itemcallnumber}, '730.100', "Test end of the shelf: item 3");
+is( $nearby->{items}[3]{itemcallnumber}, '740.100', "Test end of the shelf: item 4");
+is( $nearby->{items}[4]{itemcallnumber}, '750.100', "Test end of the shelf: item 5");
+
+$nearby = C4::ShelfBrowser::GetNearbyItems( $cn->{'750.100'}{itemnumber} );
+# We have
+# < 720.100 730.100 740.100 750.100
+#      16      17      18     [19]
+# Clicking on previous, we want a link to
+is( $nearby->{prev_item}{itemcallnumber}, '600.000', "Test last item of the shelf: previous link 1/2" );
+is( $nearby->{prev_item}{itemnumber}, $cn->{'600.000'}{itemnumber}, "Test last item of the shelf: previous link 2/2" );
+# No next link
+is( $nearby->{next_item}, undef, "Test end of the shelf: no next link" );
+
+is( scalar( @{$nearby->{items}} ), 4, "Test last item of the shelf: got 4 items" );
+
+$dbh->rollback;