From 0b7dc201c855aab717e8f5e263d17f5e3736f615 Mon Sep 17 00:00:00 2001
From: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Date: Tue, 24 Jan 2023 12:22:34 +0000
Subject: [PATCH] Bug 32711: Add biblio details to modal

This patch adds biblio details to the self-checkout modal. As part of
this we add 'biblio' to the x-koha-embed option on the public items
endpoint, clone the js-biblio-format include from the staff client
adapting it slightly for OPAC use along the way and also import
escape_str and escapeHtml from staff to opac too.

Signed-off-by: Silvia Meakins <smeakins@eso.org>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
---
 api/v1/swagger/paths/items.yaml               |  1 +
 .../en/includes/js-biblio-format.inc          | 64 +++++++++++++++++++
 .../bootstrap/en/includes/modals/checkout.inc |  4 +-
 .../bootstrap/en/includes/opac-bottom.inc     |  1 +
 koha-tmpl/opac-tmpl/bootstrap/js/global.js    | 14 ++++
 .../opac-tmpl/bootstrap/js/modals/checkout.js | 23 +++++--
 6 files changed, 101 insertions(+), 6 deletions(-)
 create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/includes/js-biblio-format.inc

diff --git a/api/v1/swagger/paths/items.yaml b/api/v1/swagger/paths/items.yaml
index ac8c313a14..2a1591ec44 100644
--- a/api/v1/swagger/paths/items.yaml
+++ b/api/v1/swagger/paths/items.yaml
@@ -426,6 +426,7 @@
           type: string
           enum:
             - +strings
+            - biblio
         collectionFormat: csv
     consumes:
       - application/json
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/js-biblio-format.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/js-biblio-format.inc
new file mode 100644
index 0000000000..77c2fe5c18
--- /dev/null
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/js-biblio-format.inc
@@ -0,0 +1,64 @@
+<script>
+    (function() {
+        /**
+         * Format the biblio response from a Koha RESTful API request.
+         * @param  {Object}  biblio  The biblio json object as returned from the Koha RESTful API
+         * @param  {Object}  config  A configuration object
+         *                           Valid keys are: `link`
+         * @return {string}          The formatted HTML string
+         */
+        window.$biblio_to_html = function(biblio, config) {
+
+            if (biblio === undefined) {
+                return ''; // empty string for no biblio
+            }
+
+            var title = '<span class="biblio-title">';
+            if (biblio.title != null && biblio.title != '') {
+                title += escape_str(biblio.title);
+            } else {
+                title += __("No title");
+            }
+            title += '</span>';
+
+            // add subtitle
+            if (biblio.subtitle != null && biblio.subtitle != '') {
+                title += ' <span class="biblio-subtitle">' + escape_str(biblio.subtitle) + '</span>';
+            }
+
+            // set title as link
+            if (config && config.link) {
+                if (config.link === 'marcdetail') {
+                    title = '<a href="/cgi-bin/koha/opac-MARCdetail.pl?biblionumber=' + encodeURIComponent(biblio.biblio_id) + '" class="title">' + title + '</a>';
+                } else if (config.link === 'labeled_marc') {
+                    title = '<a href="/cgi-bin/koha/opac-labeledMARCdetail.pl?biblionumber=' + encodeURIComponent(biblio.biblio_id) + '" class="title">' + title + '</a>';
+                } else if (config.link === 'isbd') {
+                    title = '<a href="/cgi-bin/koha/opac-ISBDdetail.pl?biblionumber=' + encodeURIComponent(biblio.biblio_id) + '" class="title">' + title + '</a>';
+                } else {
+                    title = '<a href="/cgi-bin/koha/opac-detail.pl?biblionumber=' + encodeURIComponent(biblio.biblio_id) + '" class="title">' + title + '</a>';
+                }
+            }
+
+            // add medium
+            if (biblio.medium != null && biblio.medium != '') {
+                title += ' <span class="biblio-medium">' + escape_str(biblio.medium) + '</span>';
+            }
+
+            // add part numbers/names
+            let part_numbers = (typeof biblio.part_number === 'string') ? biblio.part_number.split("|") : [];
+            let part_names = (typeof biblio.part_name === 'string') ? biblio.part_name.split("|") : [];
+            let i = 0;
+            while (part_numbers[i] || part_names[i]) {
+                if (part_numbers[i]) {
+                    title += ' <span class="part-number">' + escape_str(part_numbers[i]) + '</span>';
+                }
+                if (part_names[i]) {
+                    title += ' <span class="part-name">' + escape_str(part_names[i]) + '</span>';
+                }
+                i++;
+            }
+
+            return title;
+        };
+    })();
+</script>
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc
index 6a19e717de..615345ef77 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc
@@ -19,6 +19,8 @@
                     <thead>
                       <tr>
                           <th>Barcode</th>
+                          <th>Title</th>
+                          <th>Call number</th>
                           <th>Due date</th>
                       </tr>
                     </thead>
@@ -26,7 +28,7 @@
                     </tbody>
                     <tfoot>
                       <tr>                    
-                        <td colspan="2" class="text-right"><span id="checkoutsCount"></span> items checked out</td>
+                        <td colspan="4" class="text-right"><span id="checkoutsCount"></span> items checked out</td>
                       </tr>
                     </tfoot>
                 </table>
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc
index 518aed4e24..5f8cf1a50e 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc
@@ -295,6 +295,7 @@ $(document).ready(function() {
 });
 </script>
 [% INCLUDE 'js-date-format.inc' %]
+[% INCLUDE 'js-biblio-format.inc' %]
 [% PROCESS jsinclude %]
 [% IF ( Koha.Preference('OPACUserJS') ) %]
     <script>
diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/global.js b/koha-tmpl/opac-tmpl/bootstrap/js/global.js
index b9ea0b6edf..020b593e79 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/js/global.js
+++ b/koha-tmpl/opac-tmpl/bootstrap/js/global.js
@@ -27,6 +27,20 @@ function formatstr(str, col) {
     });
 };
 
+var HtmlCharsToEscape = {
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;'
+};
+String.prototype.escapeHtml = function() {
+    return this.replace(/[&<>]/g, function(c) {
+        return HtmlCharsToEscape[c] || c;
+    });
+};
+function escape_str(s){
+    return s != null ? s.escapeHtml() : "";
+}
+
 function confirmDelete(message) {
     return (confirm(message) ? true : false);
 }
diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js b/koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js
index 1243ee67c8..09bea14da0 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js
+++ b/koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js
@@ -55,8 +55,18 @@ $(document).ready(function() {
         // Display checkouts table if not already visible
         $('#checkoutsTable').show();
         // Add checkout to checkouts table
-        $('#checkoutsTable > tbody').append('<tr><td>' + current_item.external_id +'</td><td>'+ $date(checkout.due_date) +'</td></tr>');
-        $('#checkoutsCount').html(++checkouts_count);
+        $("#checkoutsTable > tbody").append(
+            "<tr><td>" +
+                current_item.external_id +
+                "</td><td>" +
+                $biblio_to_html(current_item.biblio, { link: 0 }) +
+                "</td><td>" +
+                current_item.callnumber +
+                "</td><td>" +
+                $date(checkout.due_date) +
+                "</td></tr>"
+        );
+        $("#checkoutsCount").html(++checkouts_count);
         // Reset to submission
         $('#checkoutConfirm').replaceWith('<button type="submit" id="checkoutSubmit" class="btn btn-primary">Submit</button>');
     };
@@ -108,9 +118,12 @@ $(document).ready(function() {
 
         let item_id;
         let items = $.ajax({
-            url: '/api/v1/public/items?external_id=' + external_id,
-            dataType: 'json',
-            type: 'GET'
+            url: "/api/v1/public/items?external_id=" + external_id,
+            headers: {
+                "x-koha-embed": "biblio",
+            },
+            dataType: "json",
+            type: "GET",
         });
 
         $('#availabilityResult').replaceWith('<div id="availabilityResult"></div>');
-- 
2.40.1