Bug 33568: Display library names instead of codes for recall
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / modules / catalogue / detail.tt
1 [% USE raw %]
2 [% USE Asset %]
3 [% USE To %]
4 [% USE Koha %]
5 [% USE KohaDates %]
6 [% USE KohaPlugins %]
7 [% USE AuthorisedValues %]
8 [% USE Branches %]
9 [% USE Biblio %]
10 [% USE Frameworks %]
11 [% USE Price %]
12 [% USE TablesSettings %]
13 [% PROCESS 'i18n.inc' %]
14 [% SET CoverImagePlugins = KohaPlugins.get_plugins_intranet_cover_images %]
15
16 [% IF Koha.Preference('AmazonAssocTag') %]
17     [% AmazonAssocTag = '?tag=' _ Koha.Preference('AmazonAssocTag') %]
18 [% ELSE %]
19     [% AmazonAssocTag = '' %]
20 [% END %]
21
22 [% SET plugins_intranet_catalog_biblio_tabs = KohaPlugins.get_plugins_intranet_catalog_biblio_tab({ biblio => biblio, biblio_id => biblionumber }) %]
23
24 [% SET footerjs = 1 %]
25 [% INCLUDE 'doc-head-open.inc' %]
26 <title>[% FILTER collapse %]
27     [% IF ( unknownbiblionumber ) %]
28         [% t("Unknown record") | html %]
29     [% ELSE %]
30         [% title_in_title = INCLUDE 'biblio-title-head.inc' %]
31         [% tx("Details for {title}", { title = title_in_title }) | html %]
32     [% END %] &rsaquo;
33     [% t("Catalog") | html %] &rsaquo;
34     [% t("Koha") | html %]
35 [% END %]</title>
36 [% Asset.css("lib/Chocolat/css/chocolat.css") | $raw %]
37 [% INCLUDE 'doc-head-close.inc' %]
38 </head>
39
40 <body id="catalog_detail" class="catalog">
41
42 [% WRAPPER 'header.inc' %]
43     [% INCLUDE 'cat-search.inc' %]
44 [% END %]
45
46 [% WRAPPER 'sub-header.inc' %]
47     [% WRAPPER breadcrumbs %]
48         [% WRAPPER breadcrumb_item %]
49             <a href="/cgi-bin/koha/catalogue/search.pl">Catalog</a>
50         [% END %]
51
52         [% IF ( unknownbiblionumber ) %]
53             [% WRAPPER breadcrumb_item bc_active= 1 %]
54                 <span>Unknown record</span>
55             [% END %]
56         [% ELSE %]
57             [% WRAPPER breadcrumb_item %]
58                 [% INCLUDE 'biblio-title.inc' link = 1 %]
59             [% END %]
60             [% WRAPPER breadcrumb_item bc_active= 1 %]
61                 <span>Details</span>
62             [% END %]
63         [% END %]
64     [% END #/ WRAPPER breadcrumbs %]
65 [% END #/ WRAPPER sub-header.inc %]
66
67 <div class="main container-fluid">
68     <div class="row">
69         <div class="col-sm-10 col-sm-push-2">
70             <main>
71                 [% INCLUDE 'messages.inc' %]
72                 <div class="row">
73
74 [% IF ( unknownbiblionumber ) %]
75   <div class="dialog message">The record you requested does not exist ([% biblionumber | html %]).</div>
76 [% ELSE %]
77
78 [% IntranetCoce    = Koha.Preference('IntranetCoce') %]
79 [% CoceProviders   = Koha.Preference('CoceProviders') %]
80 [% CoceHost        = Koha.Preference('CoceHost') %]
81 [% SyndeticsCovers = Koha.Preference('SyndeticsEnabled') && Koha.Preference('SyndeticsCoverImages') %]
82
83 [% INCLUDE 'cat-toolbar.inc' %]
84     [% IF ( ocoins ) %]
85         <!-- COinS / OpenURL -->
86         <span class="Z3988" title="[% ocoins | html %]"></span>
87     [% END %]
88
89     [% IF ( CoverImagePlugins || AmazonCoverImages  || LocalCoverImages || IntranetCoce || ( SyndeticsCovers ) || (Koha.Preference('CustomCoverImages') && Koha.Preference('CustomCoverImagesURL')) ) %]
90         <div id="catalogue_detail_biblio" class="col-xs-9">
91     [% ELSE %]
92         <div id="catalogue_detail_biblio" class="col-xs-12">
93     [% END %]
94         [% IF decoding_error || analytics_error %]
95             <div class="page-section bg-danger">
96                <h1>Errors found</h1>
97                [% IF decoding_error %]
98                    <h2>Encoding errors</h2>
99                    <p class="biberror">There is at least one encoding error with this bibliographic record, the view may be degraded.</p>
100                    <pre class="error">[% decoding_error | html %]</pre>
101                [% END %]
102                [% IF analytics_error %]
103                    <h2>Analytics errors</h2>
104                    <p class="analytics_error">There was an error searching for analytic records, please see the logs for details.</p>
105                [% END %]
106             </div>
107         [% END %]
108
109         <div class="page-section">
110
111         [% XSLTBloc | $raw %]
112
113         [% IF shelves.count %]
114             <span class="results_summary"><span class="label">Lists that include this title: </span>
115             [% FOREACH s IN shelves %]
116                 <a href="/cgi-bin/koha/virtualshelves/shelves.pl?op=view&amp;shelfnumber=[% s.shelfnumber | uri %]">[% s.shelfname | html %]</a>
117                 [% IF ( loop.last ) %][% ELSE %]|[% END %]
118             [% END %]
119             </span>
120         [% END %]
121         [% IF ( TagsEnabled &&  TagsShowOnDetail &&  TagLoop ) %]
122                 <span class="results_summary"><span class="label">Tags:</span>
123                     [% FOREACH TagLoo IN TagLoop %]
124                         [% IF ( CAN_user_tools_moderate_tags ) %]
125                         <a href="/cgi-bin/koha/tags/list.pl?tag=[% TagLoo.term |uri %]">[% TagLoo.term | html %]</a>
126                         [% ELSE %]
127                         [% TagLoo.term | html %]
128                         [% END %]
129                         <span class="weight">([% TagLoo.weight_total | html %])</span>[% IF ( loop.last ) %][% ELSE %], [% END %]
130                     [% END %]
131                     </span>
132         [% END %]
133         <span id="catalogue_detail_marc_preview" class="results_summary"><span class="label">MARC preview:</span> <a href="/cgi-bin/koha/catalogue/showmarc.pl?id=[% biblionumber | uri %]&amp;viewas=html" title="MARC" class="previewMARC">Show</a></span>
134         <span id="catalogue_detail_framework" class="results_summary">
135             <span class="label">MARC framework:</span>
136             <span class="frameworkcode">[% Frameworks.GetName(biblio.frameworkcode) | html %]</span>
137         </span>
138         [% IF !item_level_itypes ||  Koha.Preference("BiblioItemtypeInfo") %]
139            <span class="results_summary itemtype"><span class="label">Itemtype:</span>
140           [% IF ( !noItemTypeImages && imageurl ) %]
141               <img src="[% imageurl | html %]" alt="" />
142           [% END %]
143           [% IF ( description ) %]
144               <span class="itypetext">[% description | html %]</span>
145           [% ELSE %]
146               <span class="itypetext">[% itemtype | html %]</span>
147           [% END %]
148           </span>
149         [% END %]
150
151         [% IF ( Koha.Preference('SearchEngine') == 'Elasticsearch' ) %]
152             <span id="catalogue_detail_elastic_record" class="results_summary"><span class="label">Elasticsearch record:</span> <a href="/cgi-bin/koha/catalogue/showelastic.pl?id=[% biblionumber | uri %]" title="Elasticsearch record" class="previewElastic">Show</a></span>
153         [% END %]
154
155         [% IF ( holdcount ) %]
156             <span class="results_summary">
157                 <span class="label">Holds:</span>
158                 <span class="number_box">
159                     [% IF CAN_user_reserveforothers_place_holds %]
160                         <a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblionumber | uri %]">[% holdcount | html %]</a>
161                     [% ELSE %]
162                         <span>[% holdcount | html %]</span>
163                     [% END %]
164                 </span>
165             </span>
166         [% END %]
167
168         [% IF illrequests.count %]
169             <span class="results_summary">
170                 <span class="label">ILL requests:</span>
171                 [% IF CAN_user_ill %]
172                     [% FOREACH ill IN illrequests %]
173                         <a href="/cgi-bin/koha/ill/ill-requests.pl?method=illview&illrequest_id=[% ill.illrequest_id | uri %]">Request [% ill.illrequest_id | html %]</a>[% IF ! loop.last %], [% END %]
174                     [% END %]
175                 [% ELSE %]
176                     [% FOREACH ill IN illrequests %]
177                         <span>Request [% ill.illrequest_id | html %]</span>[% IF ! loop.last %], [% END %]
178                     [% END %]
179                 [% END %]
180             </span>
181         [% END %]
182
183         [% IF ( article_requests_count = biblio.article_requests.filter_by_current.count ) %]
184             <span class="results_summary">
185                 <span class="label">Article requests:</span>
186                 <span class="number_box">
187                     <a href="/cgi-bin/koha/circ/request-article.pl?biblionumber=[% biblionumber | uri %]">[% article_requests_count | html %]</a>
188                 </span>
189             </span>
190         [% END %]
191
192         [% IF course_reserves %]
193             <span class="results_summary"><span class="label">Courses that have reserved this title: </span>
194             [% FOREACH c IN course_reserves %]
195                 <a href="/cgi-bin/koha/course_reserves/course-details.pl?course_id=[% c.course_id | uri %]">[% c.course.course_name | html %]</a>
196                 [% IF ( loop.last ) %][% ELSE %]|[% END %]
197             [% END %]
198             </span>
199         [% END %]
200         </div> [%# .page-section %]
201
202         [% IF ( CoverImagePlugins || AmazonCoverImages  || LocalCoverImages || IntranetCoce || ( SyndeticsCovers ) || (Koha.Preference('CustomCoverImages') && Koha.Preference('CustomCoverImagesURL')) ) %]
203         </div>
204             <div class="col-xs-3 bookcoverimg">
205                 <div id="biblio-cover-slider" class="cover-slider" data-isbn="[% normalized_isbn | html %]">
206                     [% IF ( LocalCoverImages ) %]
207                         [% IF localimages.count %]
208                             [% FOREACH image IN localimages %]
209                                 <div class="cover-image local-coverimg">
210                                     <a href="/cgi-bin/koha/catalogue/image.pl?imagenumber=[% image.imagenumber | uri %]" title="Local cover image">
211                                         <img src="/cgi-bin/koha/catalogue/image.pl?thumbnail=1&amp;imagenumber=[% image.imagenumber | uri %]" alt="Local cover image" data-link="/cgi-bin/koha/catalogue/imageviewer.pl?biblionumber=[% biblionumber | uri %]&amp;imagenumber=[% image.imagenumber | uri %]" />
212                                     </a>
213                                     <div class="hint">Local cover image</div>
214                                 </div>
215                             [% END %]
216                         [% END %]
217                     [% END %]
218
219                     [% IF ( AmazonCoverImages && normalized_isbn) %]
220                         <div class="cover-image" id="amazon-bookcoverimg">
221                             <a href="https://images-na.ssl-images-amazon.com/images/P/[% normalized_isbn | uri %].01.LZZZZZZZ.jpg" title="Amazon cover image">
222                                 <img src="https://images-na.ssl-images-amazon.com/images/P/[% normalized_isbn | uri %].01.MZZZZZZZ.jpg" alt="Amazon cover image" data-link="http://www.amazon[% AmazonTld | uri %]/gp/reader/[% normalized_isbn | uri %][% AmazonAssocTag | uri %]#reader-link"/>
223                             </a>
224                             <div class="hint">Image from Amazon.com</div>
225                         </div>
226                     [% END %]
227
228                     [% IF ( IntranetCoce && CoceProviders && normalized_isbn ) %]
229                         [% coce_id = normalized_ean || normalized_isbn %]
230                         <div class="cover-image coce-coverimg">
231                             [% IF ( coce_id ) %]
232                                 <a title="Image from Coce" class="[% coce_id | html %]" id="coce-thumbnail-preview"></a>
233                             [% ELSE %]
234                                 <span class="no-image">No cover image available</span>
235                             [% END %]
236                             <div class="hint">Image from Coce</div>
237                         </div>
238                     [% END %]
239
240                     [% IF ( SyndeticsCovers ) %]
241                         [% IF ( content_identifier_exists ) %]
242                         <div class="cover-image" id="syndetics-bookcoverimg">
243                             <a href="https://secure.syndetics.com/index.aspx?isbn=[% normalized_isbn | url %]/LC.GIF&amp;client=[% Koha.Preference('SyndeticsClientCode') | url %]&amp;type=xw10&amp;upc=[% normalized_upc | url %]&amp;oclc=[% normalized_oclc | url %]" title="Syndetics cover image">
244                                 <img src="https://secure.syndetics.com/index.aspx?isbn=[% normalized_isbn | url %]/[% Koha.Preference('SyndeticsCoverImageSize') | url %].GIF&amp;client=[% Koha.Preference('SyndeticsClientCode') | url %]&amp;type=xw10&amp;upc=[% normalized_upc | url %]&amp;oclc=[% normalized_oclc | url %]" alt="" class="thumbnail" />
245                             </a>
246                             <div class="hint">Image from Syndetics</div>
247                         </div>
248                             [% ELSE %]
249                                 <span class="no-image">No cover image available</span>
250                             [% END %]
251                     [% END %]
252
253                     [% IF Koha.Preference('CustomCoverImages') && Koha.Preference('CustomCoverImagesURL') %]
254                         [% SET custom_cover_image_url = biblio.custom_cover_image_url %]
255                         [% IF custom_cover_image_url %]
256                             <div class="cover-image" id="custom-coverimg">
257                                 <a class="custom_cover_image" href="[% custom_cover_image_url | url %]" title="Custom cover image">
258                                     <img id="custom-img" alt="Custom cover image" src="[% custom_cover_image_url | url %]" />
259                                 </a>
260                                 <div class="hint">Custom cover image</div>
261                             </div>
262                         [% END %]
263                     [% END %]
264                 </div> <!-- /.cover-slider -->
265             </div> <!-- /.bookcoverimg.col-xs-3 -->
266         [% ELSE %]
267         </div> <!-- /.col-xs-* -->
268         [% END # /IF ( AmazonCoverImages, etc ) %]
269 </div>
270
271 <div id="bibliodetails" class="toptabs">
272
273 <ul class="nav nav-tabs" role="tablist">
274     [% IF Koha.Preference('SeparateHoldings') %]
275         <li role="presentation">
276             [%# FIXME We could build the numbers from DataTable's info %]
277             <a href="#holdings" aria-controls="holdings" role="tab" data-toggle="tab">[% Branches.GetLoggedInBranchname | html %] holdings ([% items_to_display_count - ( other_holdings_count || 0 ) - ( hidden_count || 0 ) || 0 | html %])</a>
278         </li>
279         <li role="presentation">
280             <a href="#otherholdings"  aria-controls="otherholdings" role="tab" data-toggle="tab">Other holdings ([% other_holdings_count || 0 | html %])</a>
281         </li>
282     [% ELSE %]
283         <li role="presentation">
284             <a href="#holdings" aria-controls="holdings" role="tab" data-toggle="tab">Holdings ([% items_to_display_count || 0 | html %])</a>
285         </li>
286     [% END %]
287     [% IF Koha.Preference('EnableItemGroups') %]
288         <li role="presentation">
289             <a href="#item_groups" aria-controls="item_groups" role="tab" data-toggle="tab">Item groups</a>
290         </li>
291     [% END %]
292 [% IF ( MARCNOTES || notes ) %]<li role="presentation"><a href="#description" aria-controls="description" role="tab" data-toggle="tab">Descriptions ([% ( MARCNOTES.size || 1 ) | html %])</a></li>[% END %]
293 [% IF ComponentParts && ComponentParts.size %]<li id="components_tab" role="presentation"><a href="#components"  aria-controls="components" role="tab" data-toggle="tab">Components ([% ComponentParts.size | html %])</a></li>[% END %]
294 [% IF ( subscriptionsnumber ) %]<li role="presentation"><a href="#subscriptions"  aria-controls="subscriptions" role="tab" data-toggle="tab">Subscriptions</a></li>[% END %]
295 [% IF Koha.Preference('AcquisitionDetails') %]<li role="presentation"><a href="#acq_details"  aria-controls="acq_details" role="tab" data-toggle="tab">Acquisition details</a></li>[% END %]
296 [% IF suggestions.count %]<li role="presentation"><a href="#suggestion_details"  aria-controls="suggestion_details" role="tab" data-toggle="tab">Suggestion details</a></li>[% END %]
297 [% IF ( FRBRizeEditions ) %][% IF ( XISBNS ) %]<li role="presentation"><a href="#editions"  aria-controls="editions" role="tab" data-toggle="tab">Editions</a></li>[% END %][% END %]
298 [% IF ( ( Koha.Preference('CatalogConcerns') || Koha.Preference('OpacCatalogConcerns') ) && CAN_user_editcatalogue_edit_catalogue ) %]<li role="presentation"><a href="#concerns" aria-controls="concerns" role="tab" data-toggle="tab">Concerns ([% biblio.tickets.count | html %])</a></li>[% END %]
299 [% IF ( LocalCoverImages ) %]
300     <li role="presentation">
301         <a href="#images"  aria-controls="images" role="tab" data-toggle="tab">Images ([% localimages.count || 0 | html %])</a>
302     </li>
303 [% END %]
304 [% IF HTML5MediaEnabled && HTML5MediaSets.size %]
305     <li id="media_tab" role="presentation"><a href="#html5media"  aria-controls="html5media" role="tab" data-toggle="tab">Play media</a></li>
306 [% END %]
307 [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && Koha.Preference('NovelistSelectStaffView') == 'tab' ) %]
308     <li class="NovelistSelect" style="display:none;" role="presentation"><a href="#NovelistSelect"  aria-controls="NovelistSelect" role="tab" data-toggle="tab">NoveList Select</a></li>
309 [% END %]
310 [% FOREACH plugins_intranet_catalog_biblio_tab IN plugins_intranet_catalog_biblio_tabs %]
311     <li role="presentation"><a href="#[% plugins_intranet_catalog_biblio_tab.id | uri %]"  aria-controls="[% plugins_intranet_catalog_biblio_tab.id | uri %]" role="tab" data-toggle="tab">[% plugins_intranet_catalog_biblio_tab.title | html %]</a></li>
312 [% END %]
313 </ul>
314
315 <div class="tab-content">
316 [% items_table_block_iter = 0 %]
317 [% BLOCK items_table %]
318     [% items_table_block_iter = items_table_block_iter + 1 %]
319     <div class="[% tab | html %]_table_table_controls">
320         [% IF (StaffDetailItemSelection) %]
321             <span class="show_hide_filters">
322                 <a href="#" class="show_filters" data-tab="[% tab | html %]"><i class="fa fa-filter"></i> Show filters</a>
323                 <a href="#" class="hide_filters" data-tab="[% tab | html %]" style="display: none;"><i class="fa fa-filter"></i> Hide filters</a>
324             </span>
325             | <a href="#" class="SelectAll" data-tab="[% tab | html %]"><i class="fa fa-check"></i> Select all</a>
326             | <a href="#" class="ClearAll" data-tab="[% tab | html %]"><i class="fa fa-times"></i> Clear all</a>
327             <span class="itemselection_actions">
328               | Actions:
329               [% IF CAN_user_tools_items_batchdel %]
330                 <a class="itemselection_action_delete"><i class="fa fa-trash-can"></i> Delete selected items</a>
331               [% END %]
332               [% IF CAN_user_tools_items_batchmod %]
333                 <a class="itemselection_action_modify"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Modify selected items</a>
334               [% END %]
335               [% IF CAN_user_editcatalogue_manage_item_groups && biblio.item_groups.count %]
336                 <a class="itemselection_action_item_group_set" href="#"><i class="fa fa-book"></i> Add/move to item group</a>
337                 <a class="itemselection_action_item_group_unset" href="#"><i class="fa fa-unlink"></i> Remove from item group</a>
338               [% END %]
339             </span>
340         [% END %]
341     </div>
342
343     <table class="items_table" id="[% tab | html %]_table">
344         <thead>
345             [% IF (StaffDetailItemSelection) %]<th id="[% tab | html %]_checkbox" data-colname="[% tab | html %]_checkbox" class="NoSort"></th>[% END %]
346             [% IF Koha.Preference('LocalCoverImages') %]
347                 <th id="[% tab | html %]_cover_image" data-colname="[% tab | html %]_cover_image">Cover image</th>
348             [% END %]
349             [% IF ( item_level_itypes ) %]<th id="[% tab | html %]_itype" data-colname="[% tab | html %]_itype">Item type</th>[% END %]
350             <th id="[% tab | html %]_holdingbranch" data-colname="[% tab | html %]_holdingbranch">Current library</th>
351             <th id="[% tab | html %]_homebranch" data-colname="[% tab | html %]_homebranch">Home library</th>
352             <th id="[% tab | html %]_ccode" data-colname="[% tab | html %]_ccode">Collection</th>
353             [% IF Koha.Preference('EnableItemGroups') %]
354                 <th id="[% tab | html %]_item_group" data-colname="[% tab | html %]_item_group">Item group</th>
355             [% END %]
356             <th id="[% tab | html %]_itemcallnumber" data-colname="[% tab | html %]_itemcallnumber">Call number</th>
357             <th id="[% tab | html %]_enumchron" data-colname="[% tab | html %]_enumchron">Serial enumeration / chronology</th>
358             <th id="[% tab | html %]_status" data-colname="[% tab | html %]_status">Status</th>
359             <th id="[% tab | html %]_lastseen" data-colname="[% tab | html %]_lastseen">Last seen</th>
360             <th id="[% tab | html %]_issues" data-colname="[% tab | html %]_issues">Checkouts</th>
361             <th id="[% tab | html %]_renewals" data-colname="[% tab | html %]_renewals">Renewals</th>
362             <th id="[% tab | html %]_dateaccessioned" data-colname="[% tab | html %]_dateaccessioned">Date accessioned</th>
363             <th id="[% tab | html %]_datelastborrowed" data-colname="[% tab | html %]_datelastborrowed">Date last borrowed</th>
364             <th id="[% tab | html %]_barcode" data-colname="[% tab | html %]_barcode">Barcode</th>
365             <th id="[% tab | html %]_uri" data-colname="[% tab | html %]_uri">URL</th>
366             <th id="[% tab | html %]_copynumber" data-colname="[% tab | html %]_copynumber">Copy number</th>
367             <th id="[% tab | html %]_stocknumber" data-colname="[% tab | html %]_stocknumber">Inventory number</th>
368             <th id="[% tab | html %]_materials" data-colname="[% tab | html %]_materials">Materials specified</th>
369             <th id="[% tab | html %]_itemnotes" data-colname="[% tab | html %]_itemnotes">Public notes</th>
370             <th id="[% tab | html %]_itemnotes_nonpublic" data-colname="[% tab | html %]_itemnotes_nonpublic">Non-public notes</th>
371             [% IF ( hostrecords ) %]<th id="[% tab | html %]_hostrecord" data-colname="[% tab | html %]_hostrecord">Host records</th>[% END %]
372             [% IF ( analyze ) %]<th id="[% tab | html %]_usedin" data-colname="[% tab | html %]_usedin">Used in</th><th></th>[% END %]
373             [% IF Koha.Preference('UseCourseReserves') %]<th id="[% tab | html %]_course_reserves" data-colname="[% tab | html %]_course_reserves">Course reserves</th>[% END %]
374             [% IF ( SpineLabelShowPrintOnBibDetails ) %]<th id="[% tab | html %]_spinelabel" data-colname="[% tab | html %]_spinelabel" class="NoSort">Spine label</th>[% END %]
375             [% IF ( CAN_user_editcatalogue_edit_items ) %]<th id="[% tab | html %]_actions" data-colname="[% tab | html %]_actions"class="NoSort noExport">&nbsp;</th>[% END %]
376             </tr>
377         </thead>
378     </table>
379 [% END %][%# end of block items_table %]
380
381 [% IF Koha.Preference('EnableItemGroups') %]
382     <div role="tabpanel" class="tab-pane" id="item_groups">
383         [% IF CAN_user_editcatalogue_manage_item_groups %]
384             <div class="item_groups_table_table_controls">
385                 <a href="#" class="item-group-create btn btn-default btn-xs"><i class="fa fa-plus"></i> New item group</a>
386             </div>
387         [% END %]
388         <table class="items-group-table" id="items-group-table">
389             <thead>
390                 <tr>
391                     <th>Display order</th>
392                     <th>Description</th>
393                     <th class="NoSort">&nbsp;</th>
394                 </tr>
395             </thead>
396         </table>
397     </div>
398 [% END %]
399
400
401 <div role="tabpanel" class="tab-pane" id="holdings">
402
403 [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && Koha.Preference('NovelistSelectStaffView') == 'above' ) %]
404     <span class="results_summary NovelistSelect" style="display:none;">
405         <span class="label">Novelist Select: </span>
406         <div data-novelist-novelistselect=[% normalized_isbn | html %]></div>
407     </span>
408 [% END %]
409
410 [% SET hidden_count = all_items_count - items_to_display_count %]
411 [% IF all_items_count %]
412     [% PROCESS items_table tab="holdings" %]
413
414     [% IF hidden_count %]
415         [%# FIXME We could deal with that in JS and prevent a full refresh %]
416         <p><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblionumber | uri %]&amp;showallitems=1">Show all items ([% hidden_count | html %] hidden)</a>
417     [% END %]
418 [% ELSE %]
419     [% IF ( ALTERNATEHOLDINGS ) %]
420     [% FOREACH ALTERNATEHOLDING IN ALTERNATEHOLDINGS %]
421         <div id="alternateholdings"><span class="holdings_label">Holdings:</span> [% ALTERNATEHOLDING.holding | html %]</div>
422     [% END %]
423     [% ELSE %]
424     <div id="noitems">No physical items for this record</div>
425     [% END %]
426 [% END %]
427
428 [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && Koha.Preference('NovelistSelectStaffView') == 'below' ) %]
429     <span class="results_summary NovelistSelect" style="display:none;">
430         <span class="label">Novelist Select: </span>
431         <div data-novelist-novelistselect=[% normalized_isbn | html %]></div>
432     </span>
433 [% END %]
434     </div>
435
436 [% IF Koha.Preference('SeparateHoldings') %]
437     <div role="tabpanel" class="tab-pane" id="otherholdings">
438         [% PROCESS items_table tab="otherholdings" %]
439     </div>
440 [% END %]
441
442 [% IF ( MARCNOTES ) %]
443
444 <div role="tabpanel" class="tab-pane" id="description">
445 <div class="content_set">
446
447     [% FOREACH MARCNOTE IN MARCNOTES %]
448         <p class="marcnote marcnote-[% MARCNOTE.tag | html %]" id="marcnote-[% MARCNOTE.tag | html %]-[% loop.count | html %]">
449             [% IF MARCNOTE.marcnote.match('^https?://\S+$') %]
450                 <a href="[% MARCNOTE.marcnote | url %]">[% MARCNOTE.marcnote | html %]</a>
451             [% ELSE %]
452                 [% MARCNOTE.marcnote | html | html_line_break %]
453             [% END %]
454         </p>
455 [% END %]
456 </div>
457 </div>
458
459 [% END %]
460
461 [% IF ComponentParts && ComponentParts.size %]
462 <div role="tabpanel" class="tab-pane" id="components">
463     <div class="content_set">
464         <table>
465             [% FOR PART IN ComponentParts %]
466             <tr>
467                 <td>
468                     [% PART | $raw %]
469                 </td>
470             </tr>
471             [% END %]
472         </table>
473         [% IF ComponentParts.size == Koha.Preference('MaxComponentRecords')%]
474         <p>Only [% ComponentParts.size | html %] results are shown: <a href="/cgi-bin/koha/catalogue/search.pl?q=[% ComponentPartsQuery | url %]"/>show all component parts</a></p>
475         [% END %]
476     </div> <!-- /.content_set -->
477 </div> <!-- /#components -->
478
479 [% END %]
480
481 [% IF ( subscriptionsnumber ) %]
482 <div role="tabpanel" class="tab-pane" id="subscriptions">
483 <div id="catalogue_detail_subscriptions">
484     <h2>This is a serial subscription</h2>
485     <p> (There are [% subscriptionsnumber | html %] subscriptions associated with this title).</p> 
486     [% FOREACH subscription IN subscriptions %]
487             [% IF subscription.branchcode %]
488                 <h3>At library: [% Branches.GetName(subscription.branchcode) || subscription.branchcode | html %]</h3>
489             [% END %]
490             [% IF ( subscription.closed ) %]<p>This subscription is closed.</p>[% END %]
491             [% IF ( subscription.location ) %]<p class="subscription_location">Location: [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => subscription.location ) | html %]</p>[% END %]
492             [% IF ( subscription.callnumber ) %]<p>Callnumber: [% subscription.callnumber | html %] </p>[% END %]
493             [% IF ( subscription.subscriptionnotes ) %]<p>[% subscription.subscriptionnotes | html | html_line_break %] </p>[% END %]
494             [% IF ( subscription.missinglist ) %]<p>Missing issues: [% subscription.missinglist | html %] </p>[% END %]
495             [% IF ( subscription.librariannote ) %]<p>([% subscription.librariannote | html %])</p>[% END %]
496             [% IF ( subscription.latestserials ) %]
497             <p> The [% subscription.staffdisplaycount | html %] latest issues related to this subscription:</p>
498             <table>
499                 <tr>
500                     <th>Issue #</th>
501                     <th>Date arrived</th>
502                     <th>Date published</th>
503                     <th>Date published (text)</th>
504                     <th>Status</th>
505                     <th>Note</th>
506                 </tr>
507             [% FOREACH latestserial IN subscription.latestserials %]
508                 <tr>
509                     <td>[% latestserial.serialseq | html %]</td>
510                     <td data-order="[% latestserial.planneddate | html %]">[% latestserial.planneddate | $KohaDates %]</td>
511                     <td data-order="[% latestserial.publisheddate | html %]">[% latestserial.publisheddate | $KohaDates %]</td>
512                     <td>[% latestserial.publisheddatetext | html %]</td>
513                     <td>
514                         [% INCLUDE 'serial-status.inc' serial = latestserial %]
515                     </td>
516                     <td>[% latestserial.notes | html %]</td>
517                 </tr>
518             [% END %]
519             </table>
520             [% END %]
521             [% IF ( CAN_user_serials ) %]
522                 <p>
523                     <a class="btn btn-link" href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=[% subscription.subscriptionid | uri %]"><i class="fa fa-list" aria-hidden="true"></i> Subscription details</a>
524                 </p>
525             [% END %]
526     [% END %]
527 </div>
528 </div>
529 [% END %]
530
531 [% IF Koha.Preference('AcquisitionDetails') %]
532 <div role="tabpanel" class="tab-pane" id="acq_details">
533   [% IF orders.count %]
534     <table id="orders">
535       <thead>
536         <tr>
537           <th>Vendor</th>
538           <th>Invoice</th>
539           <th>Basket group</th>
540           <th>Basket</th>
541           <th>Order number</th>
542           <th>Creation date</th>
543           <th>Receive date</th>
544           <th>Status</th>
545           <th>Quantity</th>
546           <th title="Estimated cost tax incl. while pending, actual cost tax incl. once received">Price</th>
547           <th>Internal note</th>
548           <th>Subscription</th>
549           <th>Subscription call number</th>
550         </tr>
551       </thead>
552       <tbody>
553       [% FOR order IN orders %]
554         [% SET basket = order.basket %]
555         [% SET vendor = basket.bookseller %]
556           <tr>
557             <td>
558                 <a href="/cgi-bin/koha/acqui/supplier.pl?booksellerid=[% vendor.id | uri %]" title="Vendor detail page">[% vendor.name | html %]</a>
559             </td>
560             <td>
561             [% IF order.invoiceid %]
562                 [% IF CAN_user_acquisition %]
563                     <div><a href="/cgi-bin/koha/acqui/invoice.pl?invoiceid=[% order.invoiceid | uri %]"
564                        title="Invoice detail page">
565                        [% order.invoice.invoicenumber | html %]</a></div>
566                 [% ELSE %]
567                     <div>[% order.invoice.invoicenumber | html %]</div>
568                 [% END %]
569
570                 [% IF ( Koha.Preference('EDIFACT') && CAN_user_acquisition_edi_manage && order.invoice.message_id ) %]
571                     <div><a href="/cgi-bin/koha/acqui/edimsg.pl?id=[% order.invoice.message_id | uri %]" title="EDI INVOICE message">EDI message</a></div>
572                 [% END %]
573             [% END %]
574             </td>
575             <td>
576             [% IF basket.basketgroupid %]
577                 [% SET basket_group = basket.basket_group %]
578                 [% IF CAN_user_acquisition_group_manage %]
579                     <a href="/cgi-bin/koha/acqui/basketgroup.pl?op=add&booksellerid=[% vendor.id | uri %]&basketgroupid=[% basket_group.id | uri %]">[% basket_group.name | html%] ([% basket_group.id | html %])</a>
580                 [% ELSE %]
581                     [% basket_group.name | html %] ([% basket_group.id | html %])
582                 [% END %]
583             [% END %]
584             </td>
585             <td>[% IF CAN_user_acquisition_order_manage %]
586                 <a href="/cgi-bin/koha/acqui/basket.pl?basketno=[% basket.basketno | uri %]">[% basket.basketname | html %] ([% basket.basketno | html %])</a>
587             [% ELSE %]
588                 [% basket.basketname | html %] ([% basket.basketno | html %])
589             [% END %]</td>
590             <td>[% order.ordernumber | html %]</td>
591             <td data-order="[% basket.creationdate | uri %]">[% basket.creationdate | $KohaDates%]</td>
592             <td data-order="[% order.datereceived | uri %]">[% order.datereceived | $KohaDates%]</td>
593             <td>
594               [% SWITCH order.orderstatus %]
595                 [% CASE 'new' %]<span>New</span>
596                 [% CASE 'ordered' %]<span>Ordered</span>
597                 [% CASE 'partial' %]<span>Partial</span>
598                 [% CASE 'complete' %]<span>Complete</span>
599                 [% CASE 'cancelled' %]<span>Cancelled</span>
600               [% END %]
601             </td>
602             <td>[% order.quantity | html %]</td>
603             <td>[% IF ( order.orderstatus == "complete" ) %][% order.unitprice_tax_included | $Price %][% ELSE %][% order.ecost_tax_included | $Price %][% END %]
604             <td>[% order.order_internalnote | html %]</td>
605             <td>
606                 [% IF order.subscriptionid %]
607                     <a href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=[% order.subscriptionid | uri %]">[% order.subscriptionid | html %]</a>
608                 [% END %]
609             </td>
610             <td>
611                 [% IF order.subscriptionid %]
612                     [% order.subscription.callnumber | html %]
613                 [% END %]
614             </td>
615           </tr>
616       [% END %]
617       </tbody>
618     </table>
619   [% ELSE %]
620     <span class="noorder">There is no order for this bibliographic record.</span>
621   [% END %]
622 </div>
623 [% END %]
624
625 [% IF suggestions.count %]
626     <div role="tabpanel" class="tab-pane" id="suggestion_details">
627         [% IF nb_archived_suggestions > 0 %]
628             <p>[% tnpx('pluralization', 'There is one archived suggestion.', 'There are {count} archived suggestions.', nb_archived_suggestions, { count = nb_archived_suggestions }) | $raw  %]
629         [% END %]
630         <table id="suggestions" class="sorted">
631             <thead>
632                 <tr>
633                     <th class="NoSort">&nbsp;</th>
634                     <th class="anti-the">Suggestion</th>
635                     <th>Suggested by - on</th>
636                     <th>Managed by - on</th>
637                     <th>Last modification by - on</th>
638                     <th>Library</th>
639                     <th>Fund</th>
640                     <th>Status</th>
641                 </tr>
642             </thead>
643             <tbody>
644             [% FOREACH suggestion IN suggestions %]
645                 <tr>
646                     <td>[% suggestion.suggestionid | html %]</td>
647                     <td>
648                         <a href="/cgi-bin/koha/suggestion/suggestion.pl?suggestionid=[% suggestion.suggestionid | uri %]&amp;op=show" title="suggestion" >
649                             [% suggestion.title | html %][% IF ( suggestion.author ) %], by [% suggestion.author | html %][% END %]</a>
650                         <br />
651                         [% IF ( suggestion.copyrightdate ) %]&copy; [% suggestion.copyrightdate | html %] [% END %]
652                         [% IF ( suggestion.volumedesc ) %]; Volume:<em>[% suggestion.volumedesc | html %]</em> [% END %]
653                         [% IF ( suggestion.isbn ) %]; ISBN:<em>[% suggestion.isbn | html %]</em> [% END %][% IF ( suggestion.publishercode ) %]; Published by [% suggestion.publishercode | html %] [% END %][% IF ( suggestion.publicationyear ) %] in <em>[% suggestion.publicationyear | html %]</em> [% END %][% IF ( suggestion.place ) %] in <em>[% suggestion.place | html %]</em> [% END %][% IF ( suggestion.collectiontitle ) %]; [% suggestion.collectiontitle | html %] [% END %][% IF ( suggestion.itemtype ) %]; [% AuthorisedValues.GetByCode( 'SUGGEST_FORMAT', suggestion.itemtype, 0 ) | html %] [% END %]<br />[% IF ( suggestion.note ) %]<div class="suggestion_note"><i class="fa fa-comment"></i> [% suggestion.note | html %]</div>[% END %]
654                     </td>
655                     <td>
656                         <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% suggestion.suggestedby | uri %]">[% INCLUDE 'patron-title.inc' patron => suggestion.suggester %]</a>
657                         [% IF suggestion.suggesteddate %] - [% suggestion.suggesteddate | $KohaDates %][% END %]
658                     </td>
659                     <td>
660                         <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% suggestion.managedby | uri %]">[% INCLUDE 'patron-title.inc' patron => suggestion.manager %]</a>
661                         [% IF suggestion.manageddate %] - [% suggestion.manageddate | $KohaDates %][% END %]
662                     </td>
663                     <td>
664                         <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% suggestion.lastmodificationby | uri %]">[% INCLUDE 'patron-title.inc' patron => suggestion.last_modifier %]</a>
665                         [% IF suggestion.lastmodificationdate %] - [% suggestion.lastmodificationdate | $KohaDates %][% END %]
666                     </td>
667                     <td>
668                         [% Branches.GetName( suggestion.branchcode ) | html %]
669                     </td>
670                     <td>
671                         [% suggestion.fund.budget_name | html %]
672                     </td>
673                     <td>
674                         [% IF    suggestion.STATUS == 'ASKED'     %]<span>Pending</span>
675                         [% ELSIF suggestion.STATUS == 'ACCEPTED'  %]<span>Accepted</span>
676                         [% ELSIF suggestion.STATUS == 'ORDERED'   %]<span>Ordered</span>
677                         [% ELSIF suggestion.STATUS == 'REJECTED'  %]<span>Rejected</span>
678                         [% ELSIF suggestion.STATUS == 'CHECKED'   %]<span>Checked</span>
679                         [% ELSIF suggestion.STATUS == 'AVAILABLE' %]<span>Available</span>
680                         [% ELSIF AuthorisedValues.GetByCode( 'SUGGEST_STATUS', suggestion.STATUS ) %]
681                             [% AuthorisedValues.GetByCode( 'SUGGEST_STATUS', suggestion.STATUS ) | html %]
682                         [% ELSE %]<span>Status unknown</span>
683                         [% END %]
684                         [% IF suggestion.reason %]
685                             <br />([% suggestion.reason | html %])
686                         [% END %]
687                     </td>
688                 </tr>
689                 [% END %]
690             </tbody>
691         </table>
692     </div>
693 [% END %]
694
695 [% IF ( FRBRizeEditions ) %][% IF ( XISBNS ) %]
696 <div role="tabpanel" class="tab-pane" id="editions"><h4>Editions</h4>
697 <table>
698 [% FOREACH XISBN IN XISBNS %]<tr>[% IF ( AmazonCoverImages ) %]<td><a href="http://www.amazon.com/gp/reader/[% XISBN.normalized_isbn | uri %][% AmazonAssocTag | uri %]#reader-link"><img src="https://images-na.ssl-images-amazon.com/images/P/[% XISBN.normalized_isbn | html %].01._AA75_PU_PU-5_.jpg" /></a></td>[% END %]
699 [% IF ( !item_level_itypes || Koha.Preference('BiblioItemtypeInfo') ) %]<td>[% IF ( noItemTypeImages ) %]<span class="itypetext">[% XISBN.description | html %]</span>[% ELSE %]<img src="[% XISBN.imageurl | html %]" alt="[% XISBN.description | html %]" title="[% XISBN.description | html %]">[% END %]</td>[% END %]
700 <td><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% XISBN.biblionumber | uri %]">[% XISBN.title | html %]</a> <span>by</span> [% XISBN.author | html %] &copy;[% XISBN.copyrightdate | html %]
701   [% IF ( XISBN.publishercode ) %]
702 [% XISBN.publishercode | html %] [% IF ( XISBN.place ) %]([% XISBN.place | html %])[% END %] [% IF ( XISBN.publicationyear ) %], [% XISBN.publicationyear | html %][% END %] [% IF ( XISBN.editionstatement ) %][% XISBN.editionstatement | html %][% END %] [% IF ( XISBN.editionresponsibility ) %][% XISBN.editionresponsibility | html %][% END %]
703     [% END %]
704                 [% IF ( XISBN.pages ) %] [% END %][% XISBN.pages | html %] [% IF ( XISBN.illus ) %][% XISBN.illus | html %][% END %]
705                 [% IF ( XISBN.size ) %], [% END %][% XISBN.size | html %]
706 </td>
707
708 [% END %]
709 </table></div>[% END %]
710 [% END %]
711
712 [% IF ( ( Koha.Preference('CatalogConcerns') || Koha.Preference('OpacCatalogConcerns') ) && CAN_user_editcatalogue_edit_catalogue ) %]
713 <div role="tabpanel" class="tab-pane" id="concerns">
714     <fieldset class="action" style="cursor:pointer;">
715         <a id="hideResolved"><i class="fa fa-minus-square"></i> Hide resolved</a>
716         | <a id="showAll"><i class="fa fa-bars"></i> Show all</a>
717     </fieldset>
718
719     <table id="table_concerns" width="100%">
720         <thead>
721             <tr>
722                 <th>Reported</th>
723                 <th>Details</th>
724                 <th>Status</th>
725                 <th data-class-name="actions noExport">Actions</th>
726             </tr>
727         </thead>
728     </table>
729 </div>
730 [% END %]
731
732 [% IF ( LocalCoverImages ) %]
733     <div role="tabpanel" class="tab-pane" id="images">
734         [% IF localimages.count %]
735             <p>Click on an image to view it in the image viewer</p>
736             <ul class="thumbnails">
737                 [% FOREACH image IN localimages %]
738                     [% IF image %]
739                         <li id="imagenumber-[% image.imagenumber | html %]" class="thumbnail">
740                             <a href="/cgi-bin/koha/catalogue/imageviewer.pl?biblionumber=[% biblionumber | uri %]&amp;imagenumber=[% image.imagenumber | uri %]">
741                                 <img src="/cgi-bin/koha/catalogue/image.pl?thumbnail=1&amp;imagenumber=[% image.imagenumber | uri %]" />
742                             </a>
743                             [% IF CAN_user_tools_upload_local_cover_images %]
744                                 <a href="#" class="remove"><i class="fa fa-trash-can"></i> Delete image</a>
745                             [% END %]
746                         </li>
747                     [% END %]
748                 [% END %]
749             </ul>
750         [% ELSE # - No image passed JavaScript takes care %]
751             <span class="noimagesuploaded">No images have been uploaded for this bibliographic record yet.</span>
752         [% END %]
753         [% IF ( CAN_user_tools_upload_local_cover_images ) %]
754             <p>Upload an image file: <a class="btn btn-default btn-xs" href="/cgi-bin/koha/tools/upload-cover-image.pl?biblionumber=[% biblionumber | uri %]&amp;filetype=image"><i class="fa fa-upload" aria-hidden="true"></i> Upload</a>
755             </p>
756         [% END %]
757     </div>
758 [% END %]
759
760 [% IF ( HTML5MediaEnabled ) %]
761 <div role="tabpanel" class="tab-pane" id="html5media">
762           [% FOREACH HTML5MediaSet IN HTML5MediaSets %]
763             <p>
764                 [% IF HTML5MediaSet.is_youtube %]
765                     <iframe id="player" width="640" height="360" src="[% HTML5MediaSet.srcblock | url %]"></iframe>
766                 [% ELSE %]
767                   <[% HTML5MediaParent | html %] controls preload=none>
768                     <[% HTML5MediaSet.child | html %] src="[% HTML5MediaSet.srcblock | url %]"[% HTML5MediaSet.typeblock | html %] />
769                     [[% HTML5MediaParent | html %] tag not supported by your browser.]
770                   </[% HTML5MediaParent | html %]>
771                 [% END %]
772             </p>
773           [% END %]
774 </div>
775 [% END %]
776
777
778 [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && Koha.Preference('NovelistSelectStaffView') == 'tab' ) %]
779     <div role="tabpanel" class="tab-pane" id="NovelistSelect" class="novelistSelect">
780         <div data-novelist-novelistselect=[% normalized_isbn | html %]></div>
781     </div>
782 [% END %]
783
784 [% FOREACH plugins_intranet_catalog_biblio_tab IN plugins_intranet_catalog_biblio_tabs %]
785     <div role="tabpanel" class="tab-pane" id="[% plugins_intranet_catalog_biblio_tab.id | html %]">
786         [% plugins_intranet_catalog_biblio_tab.content | $raw %]
787     </div>
788 [% END %]
789
790 </div><!-- /tab-content -->
791 </div><!-- /bibliodetails -->
792
793 <div id="export" style="margin-top: 1em;">
794 <form method="get" action="/cgi-bin/koha/catalogue/export.pl">
795 <table>  <tr>
796       <th>Save record</th>   </tr>
797     <tr><td> Select download format:    <select name="format">
798         <option value="mods">MODS (XML)</option>
799         <option data-toggle="modal" data-target="#exportModal_">Dublin Core</option>
800         <option value="marcxml">MARCXML</option>
801         <option value="marc8">MARC (non-Unicode/MARC-8)</option>
802         <option value="utf8">MARC (Unicode/UTF-8)</option>    </select>
803         <input type="submit" name="save" class="btn btn-primary" value="Download record" /></td>
804   </tr>
805   <tr><td>
806     <input type="hidden" name="op" value="export" /><input type="hidden" name="bib" value="[% biblionumber | html %]" />
807   </td></tr>
808 </table>
809 </form>
810 </div>
811
812 <div id="marcPreview" class="modal" tabindex="-1" role="dialog" aria-labelledby="marcPreviewLabel" aria-hidden="true">
813     <div class="modal-dialog modal-lg">
814     <div class="modal-content">
815     <div class="modal-header">
816         <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
817         <h3 id="marcPreviewLabel">MARC preview</h3>
818     </div>
819     <div class="modal-body">
820         <div id="loading"> <img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading </div>
821     </div>
822     <div class="modal-footer">
823         <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
824     </div>
825     </div>
826     </div>
827 </div>
828
829 <div id="elasticPreview" class="modal" tabindex="-1" role="dialog" aria-labelledby="elasticPreviewLabel" aria-hidden="true">
830     <div class="modal-dialog modal-lg">
831     <div class="modal-content">
832     <div class="modal-header">
833         <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
834         <h3 id="elasticPreviewLabel">Elasticsearch record</h3>
835     </div>
836     <div class="modal-body">
837         <div id="loading"> <img src="[% interface | html %]/[% theme | html %]/img/spinner-small.gif" alt="" /> Loading </div>
838     </div>
839     <div class="modal-footer">
840         <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
841     </div>
842     </div>
843     </div>
844 </div>
845
846             </main>
847         </div> <!-- /.col-sm-10.col-sm-push-2 -->
848
849         <div class="col-sm-2 col-sm-pull-10">
850             <aside>
851                 [% INCLUDE 'biblio-view-menu.inc' %]
852             </aside>
853         </div> <!-- /.col-sm-2.col-sm-pull-10 -->
854      </div> <!-- /.row -->
855
856 [% END %]
857
858 <div class="modal fade" id="modal-item-group-create" tabindex="-1" role="dialog" aria-labelledby="modal-item-group-create-label">
859     <div class="modal-dialog">
860         <div class="modal-content">
861             <div class="modal-header">
862                 <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
863                 <h3 id="modal-item-group-create-label"><i class="fa fa-plus"></i> Create a new item group</h3>
864             </div>
865             <form method="get" id="modal-item-group-create-form" class="validated">
866                 <div class="modal-body">
867                     <fieldset>
868                         <p>
869                             <label for="item_group_description" class="required">Name: </label>
870                             <input name="description" id="modal-item-group-create-form-description" type="text" size="30" required="required" class="required" />
871                             <span class="required">Required</span>
872                         </p>
873                         <p>
874                             <label for="item_group_display_order" class="required">Display order: </label>
875                             <input name="display_order" id="modal-item-group-create-form-display_order" value="0" size="5" required="required" class="required" />
876                             <span class="required">Required</span>
877                             <br/>
878                             <span class="hint">Numbers only, item groups will be displayed in counting order</span>
879                         </p>
880                     </fieldset>
881                 </div>
882                 <div class="modal-footer">
883                     <button id="modal-item-group-create-submit" class="btn btn-default"><i class="fa fa-plus"></i> Submit</button>
884                     <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
885                 </div>
886             </form>
887         </div>
888     </div>
889 </div>
890
891 <div class="modal fade" id="modal-item-group-edit" tabindex="-1" role="dialog" aria-labelledby="modal-item-group-edit-label">
892     <div class="modal-dialog">
893         <div class="modal-content">
894             <div class="modal-header">
895                 <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
896                 <h3 id="modal-item-group-edit-label"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit item group</h3>
897             </div>
898             <form method="get" id="modal-item-group-edit-form" class="validated">
899                 <div class="modal-body">
900                     <fieldset>
901                         <p>
902                             <label for="item_group_description" class="required">Name: </label>
903                             <input name="description" id="modal-item-group-edit-form-description" type="text" size="30" required="required" class="required" />
904                             <span class="required">Required</span>
905                         </p>
906                         <p>
907                             <label for="item_group_display_order" class="required">Sort order: </label>
908                             <input name="display_order" id="modal-item-group-edit-form-display_order" size="5" />
909                             <span class="hint">Numbers only, item groups will be displayed in counting order</span>
910                         </p>
911                     </fieldset>
912                 </div>
913                 <div class="modal-footer">
914                     <button id="modal-item-group-edit-submit" class="btn btn-default"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Submit</button>
915                     <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
916                 </div>
917             </form>
918         </div>
919     </div>
920 </div>
921
922 <div class="modal fade" id="modal-item-group-delete" tabindex="-1" role="dialog" aria-labelledby="modal-item-group-delete-label">
923     <div class="modal-dialog">
924         <div class="modal-content">
925             <div class="modal-header">
926                 <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
927                 <h3 id="modal-item-group-delete-label"><i class='fa fa-trash-can'></i> Delete item group</h3>
928             </div>
929             <div class="modal-body">
930                 Are you sure you want to delete this item group?
931             </div>
932             <div class="modal-footer">
933                 <button id="modal-item-group-delete-submit" class="btn btn-danger"><i class='fa fa-trash-can'></i> Delete</button>
934                 <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
935             </div>
936         </div>
937     </div>
938 </div>
939
940 <div class="modal fade" id="modal-item-group-set" tabindex="-1" role="dialog" aria-labelledby="modal-item-group-set-label">
941     <div class="modal-dialog">
942         <div class="modal-content">
943             <div class="modal-header">
944                 <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
945                 <h3 id="modal-item-group-set-label"><i class='fa fa-book'></i> Set item group for items</h3>
946             </div>
947             <form method="get" id="modal-item-group-set-form" class="validated">
948                 <div class="modal-body">
949                     <fieldset>
950                         <p>
951                             <label for="item_group" class="required">Item group: </label>
952                             <select name="item_group" id="item-group-add-form-select">
953                                 [% FOREACH ig IN biblio.item_groups.search({}, {order_by => 'display_order'}) %]
954                                     <option value="[% ig.id | html %]">[% ig.description | html %]</option>
955                                 [% END %]
956                             </select>
957                             <span class="required">Required</span>
958                         </p>
959                     </fieldset>
960                 </div>
961                 <div class="modal-footer">
962                     <button id="modal-item-group-set-submit" class="btn btn-default"><i class='fa fa-book'></i> Set item group</button>
963                     <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
964                 </div>
965             </form>
966         </div>
967     </div>
968 </div>
969
970 <div class="modal fade" id="modal-item-group-unset" tabindex="-1" role="dialog" aria-labelledby="modal-item-group-unset-label">
971     <div class="modal-dialog">
972         <div class="modal-content">
973             <div class="modal-header">
974                 <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
975                 <h3 id="modal-item-group-unset-label"><i class='fa fa-unlink'></i> Remove item from item group</h3>
976             </div>
977             <div class="modal-body">
978                 Are you sure you want to remove these item(s) from their item group(s)?
979             </div>
980             <div class="modal-footer">
981                 <button id="modal-item-group-unset-submit" class="btn btn-danger"><i class='fa fa-unlink'></i> Remove</button>
982                 <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
983             </div>
984         </div>
985     </div>
986 </div>
987
988     [% IF bundlesEnabled %]
989     <div class="modal" id="addToBundleModal" tabindex="-1" role="dialog" aria-labelledby="addToBundleLabel">
990         <form method="get" id="addToBundleForm" action="">
991             <div class="modal-dialog" role="document">
992                 <div class="modal-content">
993                     <div class="modal-header">
994                         <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
995                         <h3 id="addToBundleLabel">Add to bundle</h3>
996                     </div>
997                     <div class="modal-body">
998                         <div id="addResult"></div>
999                         <fieldset class="rows">
1000                             <ol>
1001                                 <li>
1002                                     <label class="required" for="external_id">Item barcode: </label>
1003                                     <input type="text" id="external_id" name="external_id" required="required">
1004                                     <span class="required">Required</span>
1005                                 </li>
1006                             </ol>
1007                         </fieldset>
1008                     </div>
1009                     <div class="modal-footer">
1010                         <button type="submit" class="btn btn-default">Submit</button>
1011                         <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
1012                     </div>
1013                 </div>
1014             </div>
1015         </form>
1016     </div>
1017
1018     <div class="modal" id="removeFromBundleModal" tabindex="-1" role="dialog" aria-labelledby="removeFromBundleLabel">
1019         <form method="get" id="removeFromBundleForm" action="">
1020             <div class="modal-dialog" role="document">
1021                 <div class="modal-content">
1022                     <div class="modal-header">
1023                         <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
1024                         <h3 id="removeFromBundleLabel">Remove from bundle</h3>
1025                     </div>
1026                     <div class="modal-body">
1027                         <div id="removeResult"></div>
1028                         <fieldset class="rows">
1029                             <ol>
1030                                 <li>
1031                                     <label class="required" for="external_id">Item barcode: </label>
1032                                     <input type="text" id="rm_external_id" name="external_id" required="required">
1033                                     <span class="required">Required</span>
1034                                 </li>
1035                             </ol>
1036                         </fieldset>
1037                     </div>
1038                     <div class="modal-footer">
1039                         <button type="submit" class="btn btn-default">Submit</button>
1040                         <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
1041                     </div>
1042                 </div>
1043             </div>
1044         </form>
1045     </div>
1046     [% END %]
1047
1048     [% IF ( Koha.Preference('CatalogConcerns') ) %]
1049     [% INCLUDE 'modals/add_catalog_concern.inc' %]
1050     [% END %]
1051
1052     [% IF ( ( Koha.Preference('CatalogConcerns') || Koha.Preference('OpacCatalogConcerns') ) && CAN_user_editcatalogue_edit_catalogue ) %]
1053     [% INCLUDE 'modals/display_ticket.inc' %]
1054     [% END %]
1055
1056 [% MACRO jsinclude BLOCK %]
1057     [% INCLUDE 'catalog-strings.inc' %]
1058     [% INCLUDE 'calendar.inc' %]
1059     [% INCLUDE 'select2.inc' %]
1060     [% INCLUDE 'js-date-format.inc' %]
1061     [% Asset.js("js/catalog.js") | $raw %]
1062     [% Asset.js("js/recalls.js") | $raw %]
1063     [% Asset.js("js/coce.js") | $raw %]
1064     [% Asset.js("lib/Chocolat/js/chocolat.js") | $raw %]
1065     [% IF ( Koha.Preference('CatalogConcerns') ) %]
1066         <script>
1067             /* Set a variable needed by add_catalog_concern.js */
1068             var logged_in_user_borrowernumber = "[% logged_in_user.borrowernumber | html %]";
1069         </script>
1070         [% Asset.js("js/modals/add_catalog_concern.js") | $raw %]
1071      [% END %]
1072      [% IF ( ( Koha.Preference('CatalogConcerns') || Koha.Preference('OpacCatalogConcerns') ) && CAN_user_editcatalogue_edit_catalogue ) %]
1073          <script>
1074             $(document).ready(function() {
1075                 var table_settings = [% TablesSettings.GetTableSettings( 'cataloguing', 'concerns', 'table_concerns', 'json' ) | $raw %];
1076
1077                 var filtered = false;
1078                 let additional_filters = {
1079                     resolved_date: function(){
1080                         if ( filtered ) {
1081                             return { "=": null };
1082                         } else {
1083                             return;
1084                         }
1085                     },
1086                     biblio_id: [% biblionumber | uri %]
1087                 };
1088
1089                 var tickets_url = '/api/v1/tickets';
1090                 var tickets = $("#table_concerns").kohaTable({
1091                     "ajax": {
1092                         "url": tickets_url
1093                     },
1094                     "embed": [
1095                         "reporter",
1096                         "resolver",
1097                         "updates+count",
1098                     ],
1099                     'emptyTable': '<div class="dialog message">' + _("Congratulations, there are no catalog concerns.") + '</div>',
1100                     "columnDefs": [ {
1101                         "targets": [0,1,2],
1102                         "render": function (data, type, row, meta) {
1103                             if ( type == 'display' ) {
1104                                 if ( data != null ) {
1105                                     return data.escapeHtml();
1106                                 }
1107                                 else {
1108                                     return "";
1109                                 }
1110                             }
1111                             return data;
1112                         }
1113                     } ],
1114                     "columns": [
1115                         {
1116                             "data": "reported_date:reporter.firstname",
1117                             "render": function(data, type, row, meta) {
1118                                 let reported = '<span class="date clearfix">' + $datetime(row.reported_date) + '</span>';
1119                                 reported += '<span class="reporter clearfix">' + $patron_to_html(row.reporter, {
1120                                     display_cardnumber: false,
1121                                     url: true
1122                                 }) + '</span>';
1123                                 return reported;
1124                             },
1125                             "searchable": true,
1126                             "orderable": true
1127                         },
1128                         {
1129                             "data": "title:body",
1130                             "render": function(data, type, row, meta) {
1131                                 let resolved = ( row.resolved_date ) ? true : false;
1132                                 let result = '<a role="button" href="#" data-toggle="modal" data-target="#ticketDetailsModal" data-concern="' + encodeURIComponent(row.ticket_id) + '" data-resolved="' + resolved + '">' + row.title + '</a>';
1133                                 if (row.updates_count) {
1134                                     result += '<span class="pull-right"><a role="button" href="#" data-toggle="modal" data-target="#ticketDetailsModal" data-concern="' + encodeURIComponent(row.ticket_id) + '"><i class="fa fa-comment" aria-hidden="true"></i> ' + row.updates_count + '</a></span>';
1135                                 }
1136                                 result += '<div id="detail_' + row.ticket_id + '" class="hidden">' + row.body + '</div>';
1137                                 return result;
1138                             },
1139                             "searchable": true,
1140                             "orderable": true
1141                         },
1142                         {
1143                             "data": "resolved_date",
1144                             "render": function(data, type, row, meta) {
1145                                 let result = '';
1146                                 if (row.resolved_date) {
1147                                     result += _("Resolved by:") + ' <span>' + $patron_to_html(row.resolver, {
1148                                         display_cardnumber: false,
1149                                         url: true
1150                                     }) + '</span>';
1151                                     result += '<span class="clearfix">' + $datetime(row.resolved_date) + '</span>';
1152                                 } else {
1153                                     result += _("Open");
1154                                 }
1155                                 return result;
1156                             },
1157                             "searchable": true,
1158                             "orderable": true
1159                         },
1160                         {
1161                             "data": function(row, type, val, meta) {
1162                                 let resolved = ( row.resolved_date ) ? true : false;
1163                                 let result = '<a class="btn btn-default btn-xs" role="button" href="#" data-toggle="modal" data-target="#ticketDetailsModal" data-concern="' + encodeURIComponent(row.ticket_id) + '" data-resolved="' + resolved + '"><i class="fa-solid fa-eye" aria-hidden="true"></i> ' + _("Details") + '</a>';
1164                                 return result;
1165                             },
1166                             "searchable": false,
1167                             "orderable": false
1168                         },
1169                     ]
1170                 }, table_settings, 0, additional_filters);
1171
1172                 $('#hideResolved').on("click", function() {
1173                     filtered = true;
1174                     tickets.DataTable().draw();
1175                 });
1176
1177                 $('#showAll').on("click", function() {
1178                     filtered = false;
1179                     tickets.DataTable().draw();
1180                 });
1181             });
1182         </script>
1183         [% Asset.js("js/modals/display_ticket.js") | $raw %]
1184     [% END %]
1185     <script>
1186         var interface = "[% interface | html %]";
1187         var theme = "[% theme | html %]";
1188         // http://www.oreillynet.com/pub/a/javascript/2003/10/21/amazonhacks.html
1189         function verify_cover_images() {
1190             // Loop over each container in the template which contains covers
1191             $(".cover-slider").each(function(){
1192                 var lightbox_descriptions = [];
1193                 var first_shown = 0;
1194                 $(this).find(".cover-image").each( function( index ){
1195                 var div = $(this);
1196                 // Find the image in the container
1197                 var img = div.find("img")[0];
1198                 if( $(img).length > 0 ){
1199                     var description = "";
1200                         // All slides start hidden. If this is the first one, show it.
1201                         if( first_shown == 0 ){
1202                             div.show();
1203                             first_shown = 1;
1204                         }
1205                         // Check if Amazon image is present
1206                         if ( div.attr("id") == "amazon-bookcoverimg"  ) {
1207                             w = img.width;
1208                             h = img.height;
1209                             if ((w == 1) || (h == 1)) {
1210                                 // Amazon returned single-pixel placeholder
1211                                 // Remove the container
1212                                 div.remove();
1213                             } else {
1214                                 lightbox_descriptions.push(_("Amazon cover image (<a href='%s'>see the original image</a>)").format($(img).data('link')));
1215                             }
1216                         } else if( div.attr("id") == "custom-coverimg" ){
1217                             if ( (img.complete != null) && (!img.complete) || img.naturalHeight == 0 ) {
1218                                 // No image was loaded via the CustomCoverImages system preference
1219                                 // Remove the container
1220                                 div.remove();
1221                             } else {
1222                                 lightbox_descriptions.push( _("Custom cover image") );
1223                             }
1224                         } else if ( div.attr("id") == "syndetics-bookcoverimg" ){
1225                                 lightbox_descriptions.push(_("Syndetics cover image (<a href='%s'>see the original image</a>)").format($(img).data('link')));
1226                         }
1227                         else if( div.hasClass("coce-coverimg" ) ){
1228                             // Identify which service's image is being loaded by Coce
1229                             var coce_description;
1230                             if( $(img).attr("src").indexOf('amazon.com') >= 0 ){
1231                                 coce_description = _("Coce image from Amazon.com");
1232                             } else if( $(img).attr("src").indexOf('google.com') >= 0 ){
1233                                 coce_description = _("Coce image from Google Books");
1234                             } else if( $(img).attr("src").indexOf('openlibrary.org') >= 0 ){
1235                                 coce_description = _("Coce image from Open Library");
1236                             }
1237                             div.find(".hint").html(coce_description);
1238                             lightbox_descriptions.push(coce_description);
1239                         } else if ( div.attr("class") == "cover-image local-coverimg" ) {
1240                             lightbox_descriptions.push(_("Local cover image (<a href='%s'>edit</a>)").format($(img).data('link')));
1241                         } else {
1242                             lightbox_descriptions.push(_("Cover image source unknown"));
1243                         }
1244                     }
1245                 });
1246
1247                 // Lightbox for cover images
1248                 Chocolat(this.querySelectorAll('.cover-image a'), {
1249                     description: function(){
1250                         return lightbox_descriptions[this.settings.currentImageIndex];
1251                     }
1252                 });
1253
1254             });
1255
1256             $(".cover-slider").each(function(){
1257                 var coverSlide = this;
1258                 var coverImages = $(this).find(".cover-image");
1259                 if( coverImages.length > 1 ){
1260                     coverImages.each(function( index ){
1261                         // If more that one image is present, add a navigation link
1262                         // for activating the slide
1263                         var covernav = $("<a href=\"#\" data-num=\"" + index + "\" class=\"cover-nav\"></a>");
1264                         if( index == 0 ){
1265                             // Set the first navigation link as active
1266                             $(covernav).addClass("nav-active");
1267                         }
1268                         $(covernav).html("<i class=\"fa fa-circle\"></i>");
1269                         $(coverSlide).append( covernav );
1270                     });
1271                 }
1272
1273                 if( $(coverSlide).attr('id') == 'biblio-cover-slider' // Hide if not visible, but only for the biblio images. Images for items are only local cover images
1274                     && $(coverSlide).find(".cover-image:visible").length < 1 ){
1275                     $(coverSlide).remove();
1276                 } else {
1277                     $(coverSlide).addClass("cover-slides");
1278                     var img = $(coverSlide).find(".cover-image:visible").find("img")[0];
1279                     if( $(img).length > 0 && img.complete && img.naturalHeight > 0 ){
1280                         $(".cover-slides").css({"background-image":"none"});
1281                     }
1282                 }
1283             });
1284
1285             $("#editions img").each(function(i){
1286                 if ( this.src.indexOf('amazon.com') >= 0 ) {
1287                     w = this.width;
1288                     h = this.height;
1289                     if ((w == 1) || (h == 1)) {
1290                         this.src = 'https://images-na.ssl-images-amazon.com/images/G/01/x-site/icons/no-img-sm.gif';
1291                     } else if ( (this.complete != null) && (!this.complete) || this.naturalHeight == 0 ) {
1292                         this.src = 'https://images-na.ssl-images-amazon.com/images/G/01/x-site/icons/no-img-sm.gif';
1293                     }
1294                 }
1295             });
1296         }
1297
1298         function removeLocalImage(imagenumber) {
1299             var thumbnail = $("#imagenumber-" + imagenumber );
1300             var copy = thumbnail.html();
1301             thumbnail.find("img").css("opacity", ".2");
1302             thumbnail.find("a.remove").html("<img style='display:inline-block' src='" + interface + "/" + theme + "/img/spinner-small.gif' alt='' />");
1303             const client = APIClient.cover_image;
1304             client.cover_images.delete(imagenumber).then(
1305                 success => {
1306                     if ( success.deleted == 1 ) {
1307                         thumbnail.remove();
1308                     } else {
1309                         thumbnail.html( copy );
1310                         alert(_("An error occurred on deleting this image"));
1311                     }
1312                     if ( $('ul.thumbnails > li').length == 0 ) {
1313                         showNoImageMessage();
1314                     }
1315                 },
1316                 error => {
1317                     thumbnail.html( copy );
1318                     alert(_("An error occurred on deleting this image"));
1319                     console.warn("Something wrong happened: %s".format(error));
1320                 }
1321             );
1322         }
1323
1324         function showNoImageMessage() {
1325             var no_images_msg = _("No images have been uploaded for this bibliographic record yet.");
1326             no_images_msg = '<p>' + no_images_msg + '</p>';
1327             [% IF ( CAN_user_tools_upload_local_cover_images ) %]
1328                 var please_upload = _("Upload an image file: %sUpload%s").format("<a class='btn btn-default btn-xs' href='/cgi-bin/koha/tools/upload-cover-image.pl?biblionumber=" + biblionumber + "&amp;filetype=image'><i class='fa fa-upload' aria-hidden='true'></i> ","</a>");
1329                 no_images_msg += "<p id='upload_image'>" + please_upload + '</p>';
1330             [% END %]
1331             $('#images').html(no_images_msg);
1332         }
1333
1334         [% IF StaffDetailItemSelection %]
1335
1336             let items_selection = {};
1337             function itemSelectionBuildDeleteLink(tab_id) {
1338                 var itemnumbers = items_selection[tab_id];
1339                 if (itemnumbers.length > 0) {
1340                     var url = '/cgi-bin/koha/tools/batchMod.pl?op=show&del=1';
1341                     url += '&itemnumber=' + itemnumbers.join('&itemnumber=');
1342                     url += '&biblionumber=[% biblionumber | uri %]';
1343                     url += '&src=CATALOGUING';
1344                     $('a.itemselection_action_delete').attr('href', url);
1345                 } else {
1346                     return false;
1347                 }
1348                 return true
1349             }
1350
1351             function itemSelectionBuildModifyLink(tab_id) {
1352                 var itemnumbers = items_selection[tab_id];
1353                 if (itemnumbers.length > 0) {
1354                     var url = '/cgi-bin/koha/tools/batchMod.pl?op=show';
1355                     url += '&itemnumber=' + itemnumbers.join('&itemnumber=');
1356                     url += '&biblionumber=[% biblionumber | uri %]';
1357                     url += '&src=CATALOGUING';
1358                     $('a.itemselection_action_modify').attr('href', url);
1359                 } else {
1360                     return false;
1361                 }
1362                 return true;
1363             }
1364
1365             function itemSelectionBuildActionLinks(tab_id) {
1366                 var delete_link_ok = itemSelectionBuildDeleteLink(tab_id);
1367                 var modify_link_ok = itemSelectionBuildModifyLink(tab_id);
1368                 var div = $("#" + tab_id);
1369                 if (modify_link_ok || delete_link_ok) {
1370                     $('.itemselection_actions', div).show();
1371                 } else {
1372                     $('.itemselection_actions', div).hide();
1373                 }
1374             }
1375
1376             $(document).ready(function() {
1377
1378                 $(".SelectAll").on("click",function(e){
1379                     e.preventDefault();
1380                     var tab = $(this).data("tab");
1381                     $("input[name='itemnumber'][type='checkbox']", $("#"+tab)).prop('checked', true);
1382                     itemSelectionBuildActionLinks(tab);
1383                 });
1384
1385                 $(".ClearAll").on("click",function(e){
1386                     e.preventDefault();
1387                     var tab = $(this).data("tab");
1388                     $("input[name='itemnumber'][type='checkbox']", $("#"+tab)).prop('checked', false);
1389                     itemSelectionBuildActionLinks(tab);
1390                 });
1391
1392                 $(".show_filters").on("click",function(e){
1393                     e.preventDefault();
1394                     let tab_id = $(this).data("tab");
1395                     let tab = $("#"+tab_id);
1396                     tab.find(".show_filters").hide();
1397                     tab.find(".hide_filters").show();
1398                     $("#"+tab_id+"_table thead tr:eq(1)").remove();
1399                     build_items_table(tab_id, true, { dom: dataTablesDefaults.dom, destroy: true } );
1400                 });
1401
1402                 $(".hide_filters").on("click",function(e){
1403                     e.preventDefault();
1404                     let tab_id = $(this).data("tab");
1405                     let tab = $("#"+tab_id);
1406                     tab.find(".hide_filters").hide();
1407                     tab.find(".show_filters").show();
1408                     $("#"+tab_id+"_table thead tr:eq(1)").remove();
1409                     build_items_table(tab_id, false, { dom: 'C<"top pager"ilpfB><"#filter_c">tr<"bottom pager"ip>', destroy: true } );
1410                 });
1411             });
1412         [% END %]
1413
1414         $(document).ready(function() {
1415             // Pick details tab to display by default
1416             [% IF count == 0 %]
1417                 [% IF ( Koha.Preference('HTML5MediaEnabled') == 'staff' or Koha.Preference('HTML5MediaEnabled') == 'both' ) && HTML5MediaSets.size %]
1418                     $(".nav-tabs a[href='#html5media']").tab("show");
1419                 [% ELSIF ComponentParts && ComponentParts.size %]
1420                     $(".nav-tabs a[href='#components']").tab("show");
1421                 [% ELSE %]
1422                     $(".nav-tabs a[href='#holdings']").tab("show");
1423                 [% END %]
1424             [% ELSE %]
1425                 $(".nav-tabs a[href='#holdings']").tab("show");
1426             [% END %]
1427             $('#search-form').focus();
1428             $('.thumbnails > li > .remove').click(function() {
1429                 var result = confirm(_("Are you sure you want to delete this cover image?"));
1430
1431                 if ( result == true ) {
1432                     var imagenumber = $(this).parent().attr('id').split('-')[1];
1433                     removeLocalImage(imagenumber);
1434                 }
1435
1436                 return false;
1437             });
1438             [% IF ( IntranetCoce && CoceProviders ) %]
1439                 KOHA.coce.getURL('[% CoceHost | html %]', '[% CoceProviders | html %]');
1440             [% END %]
1441
1442             $("body").on("click",".previewMARC", function(e){
1443                 e.preventDefault();
1444                 var page = $(this).attr("href");
1445                 $("#marcPreview .modal-body").load(page + " table");
1446                 $('#marcPreview').modal({show:true});
1447
1448             });
1449
1450            [% IF ( Koha.Preference('SearchEngine') == 'Elasticsearch' ) %]
1451             $("body").on("click",".previewElastic", function(e){
1452                 e.preventDefault();
1453                 var pageElastic = $(this).attr("href");
1454                 $("#elasticPreview .modal-body").load(pageElastic, function( response, status, xhr ) {
1455                     if( status == 'error' ){
1456                         $("#elasticPreview .modal-body").html("<h1>"+_("An error has occurred!")+"</h1><h2><em>"+_("Error 404")+"</em></h2><ul><li>"+_("An internal link in the staff interface is broken and the page does not exist")+"</li></ul><h3>"+_("What's next?")+"</h3><ul style='margin-bottom: 1em; padding-bottom: 1em; border-bottom: 1px solid #CCC;'><li>"+_("Use top menu bar to navigate to another part of Koha.")+"</li><li>"+_("To report a broken link or any other issue, please contact the Koha administrator.")+" <a href='mailto:[% Koha.Preference("KohaAdminEmailAddress") | uri %]'>"+_("Send email")+"</a></li></ul>");
1457                     }
1458                 });
1459                 $('#elasticPreview').modal({show:true});
1460             });
1461            [% END %]
1462
1463             [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && ( normalized_isbn || normalized_upc ) ) %]
1464                 novSelect.loadContentForQuery({
1465                     ClientIdentifier : '[% IF normalized_isbn %][% normalized_isbn | html %][% ELSE %][% normalized_upc | html %][% END %]',
1466                     ISBN : '[% IF normalized_isbn %][% normalized_isbn | html %][% ELSE %][% normalized_upc | html %][% END %]',
1467                     version : '2.1'
1468                 },
1469                 '[% Koha.Preference('NovelistSelectStaffProfile') | html %]',
1470                 '[% Koha.Preference('NovelistSelectPassword') | html %]',
1471                 function(d){
1472                     if ( d.length > 0 ){ //If no content
1473                         $(".NovelistSelect").show();
1474                     }
1475                  });
1476              [% END %]
1477              $(".print-label").on("click", function(e){
1478                 e.preventDefault();
1479                 link = $(this).attr("href");
1480                 openWindow(link,"Print spine label",400,400);
1481              });
1482              $(".cover-slider").on("click",".cover-nav", function(e){
1483                  e.preventDefault();
1484                 var cover_slider = $(this).parent();
1485                 // Adding click handler for cover image navigation links
1486                 var num = $(this).data("num");
1487                 $(cover_slider).find(".cover-nav").removeClass("nav-active");
1488                 $(this).addClass("nav-active");
1489                 $(cover_slider).find(".cover-image").hide();
1490                 $(cover_slider).find(".cover-image").eq( num ).show();
1491              });
1492         });
1493
1494
1495         [% IF ( IntranetCoce && CoceProviders ) %]
1496             let counter_wait = 0;
1497             function wait_for_images(cb){
1498
1499                 var loaded = 1;
1500                 counter_wait++;
1501
1502                 if ( loaded ) {
1503                     loaded = KOHA.coce.done;
1504                 }
1505
1506                 if (!loaded && counter_wait < 50) {// Do not wait more than 5 seconds
1507                     window.setTimeout(function(){wait_for_images(cb);}, 100);
1508                 } else {
1509                     if (counter_wait >= 50 ) {
1510                         console.log("Could not retrieve the images")
1511                     }
1512                     cb();
1513                 }
1514             }
1515
1516             $(window).load(function() {
1517                 wait_for_images(verify_cover_images);
1518             });
1519         [% ELSE %]
1520             $(window).load(function() {
1521                 verify_cover_images();
1522             });
1523         [% END %]
1524     </script>
1525     [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && ( normalized_isbn || normalized_upc ) ) %]
1526         <script src="https://imageserver.ebscohost.com/novelistselect/ns2init.js"></script>
1527     [% END %]
1528     [% INCLUDE 'datatables.inc' %]
1529     [% Asset.js("lib/jquery/plugins/jquery.dataTables.columnFilter.js") | $raw %]
1530     [% INCLUDE 'columns_settings.inc' %]
1531     [% INCLUDE 'js-date-format.inc' %]
1532     [% INCLUDE 'js-patron-format.inc' %]
1533     [% INCLUDE 'js-biblio-format.inc' %]
1534     [% Asset.js("js/browser.js") | $raw %]
1535     [% Asset.js("js/table_filters.js") | $raw %]
1536     [% Asset.js("js/place_booking_modal.js") | $raw %]
1537     <script>
1538         var browser;
1539         browser = KOHA.browser('[% searchid | html %]', parseInt(biblionumber, 10));
1540         browser.show();
1541
1542         [% IF bundlesEnabled %]
1543         var bundle_settings = [% TablesSettings.GetTableSettings('catalogue', 'detail','bundle_tables','json') | $raw %];
1544         var bundle_lost_value = [% Koha.Preference('BundleLostValue') | html %];
1545         [% END %]
1546
1547         $(document).ready(function() {
1548
1549             [% IF bundlesEnabled %] // Bundle handling
1550             function createChild ( row, itemnumber, duedate ) {
1551
1552                 // Toolbar
1553                 var bundle_toolbar = $('<div id="toolbar" class="btn-toolbar"></div>');
1554                 bundle_toolbar.append('<a class="btn btn-default" data-toggle="modal" data-target="#addToBundleModal" data-item="' + itemnumber + '"><i class="fa fa-plus"></i> ' + _("Add to bundle") + '</a>');
1555                 bundle_toolbar.append('<a class="btn btn-default" data-toggle="modal" data-target="#removeFromBundleModal" data-item="' + itemnumber + '"><i class="fa fa-minus"></i> ' + _("Remove from bundle") + '</a>');
1556
1557                 // Disable management if there's a duedate
1558                 if(duedate) {
1559                     bundle_toolbar.children('.btn').addClass("disabled");
1560                     bundle_toolbar.attr("title", _("This bundle is checked out, it cannot be modified"));
1561                 }
1562
1563                 // This is the table we'll convert into a DataTable
1564                 var bundles_table = $('<table class="display tbundle" data-itemnumber="'+itemnumber+'" id="bundle_table_'+itemnumber+'" width="100%"/>');
1565
1566                 // Display it the child row
1567                 row.child( bundle_toolbar.add(bundles_table), 'bundle' ).show();
1568
1569                 // Initialise as a DataTable
1570                 var bundle_table_url = "/api/v1/items/" + itemnumber + "/bundled_items?";
1571                 var bundle_table = bundles_table.kohaTable({
1572                     "ajax": {
1573                         "url": bundle_table_url
1574                     },
1575                     "embed": [
1576                         "biblio",
1577                         "return_claim.patron"
1578                     ],
1579                     "order": [[ 1, "asc" ]],
1580                     "columnDefs": [ {
1581                         "targets": [0,1,2,3],
1582                         "render": function (data, type, row, meta) {
1583                             if ( data && type == 'display' ) {
1584                                 return data.escapeHtml();
1585                             }
1586                             return data;
1587                         }
1588                     } ],
1589                     "columns": [
1590                         {
1591                             "data": "biblio.title:biblio.subtitle:biblio.medium",
1592                             "title": _("Title"),
1593                             "searchable": true,
1594                             "orderable": true,
1595                             "render": function(data, type, row, meta) {
1596                                 return $biblio_to_html(row.biblio, { link: 1 });
1597                             }
1598                         },
1599                         {
1600                             "data": "biblio.author",
1601                             "title": _("Author"),
1602                             "searchable": true,
1603                             "orderable": true,
1604                         },
1605                         {
1606                             "data": "callnumber",
1607                             "title": _("Callnumber"),
1608                             "searchable": true,
1609                             "orderable": true,
1610                         },
1611                         {
1612                             "data": "external_id",
1613                             "title": _("Barcode"),
1614                             "searchable": true,
1615                             "orderable": true,
1616                         },
1617                         {
1618                             "data": "lost_status:last_seen_date:return_claim.patron",
1619                             "title": _("Status"),
1620                             "searchable": false,
1621                             "orderable": false,
1622                             "render": function(data, type, row, meta) {
1623                                 if ( row.lost_status == bundle_lost_value ) {
1624                                     let out = '<span class="lost">' + _("Last seen") + ': ' + $date(row.last_seen_date) + '</span>';
1625                                     if ( row.return_claim ) {
1626                                         out = out + '<span class="claims_return">' + _("Claims returned by") + ': ' + $patron_to_html( row.return_claim.patron, { display_cardnumber: false, url: true } ) + '</span>';
1627                                     }
1628                                     return out;
1629                                 }
1630                                 else if ( row.lost_status !== 0 ) {
1631                                     return '<span class="lost">' + _("Lost") + ': ' + row.lost_status + '</span>';
1632                                 }
1633                                 return '<span class="available">' + _("Present") + '</span>';
1634                             }
1635                         },
1636                         {
1637                             "data": function( row, type, val, meta ) {
1638                                 var result;
1639                                 if (duedate) {
1640                                     result = '<button class="btn btn-default btn-xs remove disabled" role="button" data-itemnumber="'+row.item_id+'" title="%s"><i class="fa fa-minus" aria-hidden="true"></i> %s</button>\n'.format(_("This bundle is checked out, it cannot be modified"), _("Remove"));
1641                                 } else {
1642                                     result = '<button class="btn btn-default btn-xs remove" role="button" data-itemnumber="'+row.item_id+'"><i class="fa fa-minus" aria-hidden="true"></i> '+_("Remove")+'</button>\n';
1643                                 }
1644                                 return result;
1645                             },
1646                             "title": _("Actions"),
1647                             "searchable": false,
1648                             "orderable": false,
1649                             "class": "noExport"
1650                         }
1651                     ]
1652                 }, bundle_settings, 1);
1653                 $(".tbundle").on("click", ".remove:not(.disabled)", function(){
1654                     var bundle_table = $(this).closest('table');
1655                     var host_itemnumber = bundle_table.data('itemnumber');
1656                     var component_itemnumber = $(this).data('itemnumber');
1657                     var unlink_item_url = "/api/v1/items/" + host_itemnumber + "/bundled_items/" + component_itemnumber;
1658                     $.ajax({
1659                         type: "DELETE",
1660                         url: unlink_item_url,
1661                         success: function(){
1662                             bundle_table.DataTable({ 'retrieve': true }).draw(false);
1663                         }
1664                     });
1665                 });
1666
1667                 return;
1668             }
1669
1670             var bundle_changed;
1671             var bundle_form_active;
1672             $("#addToBundleModal").on("shown.bs.modal", function(e){
1673                 var button = $(e.relatedTarget);
1674                 var item_id = button.data('item');
1675                 $("#addResult").replaceWith('<div id="addResult"></div>');
1676                 $("#addToBundleForm").attr('action', '/api/v1/items/' + item_id + '/bundled_items');
1677                 $("#external_id").focus();
1678                 bundle_changed = 0;
1679                 bundle_form_active = item_id;
1680             });
1681
1682             function addToBundle (url, data) {
1683                   /* Send the data using post with external_id */
1684                   var posting = $.post({
1685                       url: url,
1686                       data: JSON.stringify(data),
1687                       contentType: "application/json; charset=utf-8",
1688                       dataType: "json"
1689                   });
1690
1691                   const barcode = data.external_id;
1692
1693                   /* Report the results */
1694                   posting.done(function(data) {
1695                       $('#addResult').replaceWith('<div id="addResult" class="alert alert-success">'+_("Success: Added '%s'").format(barcode)+'</div>');
1696                       $('#external_id').val('').focus();
1697                       bundle_changed = 1;
1698                   });
1699                   posting.fail(function(data) {
1700                       if ( data.status === 409 ) {
1701                           var response = data.responseJSON;
1702                           if ( response.error_code === 'already_bundled' ) {
1703                               $('#addResult').replaceWith('<div id="addResult" class="alert alert-warning">'+_("Warning: Item '%s' already attached").format(barcode)+'</div>');
1704                           } else if (response.error_code === 'bundle_checkout_out') {
1705                               $('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Bundle is currently checked out")+'</div>');
1706                           } else if (response.error_code === 'checked_out') {
1707                               const button = $('<button type="button">')
1708                                 .addClass('btn btn-xs')
1709                                 .text(_("Check in and add to bundle"))
1710                                 .on('click', function () {
1711                                     addToBundle(url, { external_id: barcode, force_checkin: true });
1712                                 });
1713                               $('#addResult')
1714                                 .empty()
1715                                 .attr('class', 'alert alert-warning')
1716                                 .append(__x('Warning: Item {barcode} is checked out', { barcode }))
1717                                 .append(' ', button);
1718                           } else if (response.error_code === 'failed_checkin') {
1719                               $('#addResult')
1720                                 .empty()
1721                                 .attr('class', 'alert alert-danger')
1722                                 .append(__x('Failure: Item {barcode} cannot be checked in', { barcode }))
1723                           } else if (response.error_code === 'reserved') {
1724                               const button = $('<button type="button">')
1725                                 .addClass('btn btn-xs')
1726                                 .text(_("Ignore holds and add to bundle"))
1727                                 .on('click', function () {
1728                                     addToBundle(url, { external_id: barcode, ignore_holds: true });
1729                                 });
1730                               $('#addResult')
1731                                 .empty()
1732                                 .attr('class', 'alert alert-warning')
1733                                 .append(__x('Warning: Item {barcode} is on hold', { barcode }))
1734                                 .append(' ', button);
1735                           } else {
1736                               $('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Item '%s' belongs to another bundle").format(barcode)+'</div>');
1737                           }
1738                       } else if ( data.status === 404 ) {
1739                           $('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Item '%s' not found").format(barcode)+'</div>');
1740                       } else if ( data.status === 400 ) {
1741                           var response = data.responseJSON;
1742                           if ( response.error_code === "failed_nesting" ) {
1743                               $('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Item '%s' is a bundle and bundles cannot be nested").format(barcode)+'</div>');
1744                           } else {
1745                               $('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Check the logs for details.")+'</div>');
1746                           }
1747                       } else {
1748                           $('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Check the logs for details.")+'</div>');
1749                       }
1750                       $('#external_id').val('').focus();
1751                   });
1752             }
1753
1754             $("#addToBundleForm").submit(function(event) {
1755                   /* stop form from submitting normally */
1756                   event.preventDefault();
1757
1758                   const url = this.action;
1759                   const data = { external_id: this.elements.external_id.value };
1760
1761                   addToBundle(url, data);
1762             });
1763
1764             $("#addToBundleModal").on("hidden.bs.modal", function(e){
1765                 if ( bundle_changed ) {
1766                     $('#bundle_table_'+bundle_form_active).DataTable({ 'retrieve': true }).ajax.reload();
1767                 }
1768                 bundle_form_active = 0;
1769                 bundle_changed = 0;
1770             });
1771
1772             $("#removeFromBundleModal").on("shown.bs.modal", function(e){
1773                 var button = $(e.relatedTarget);
1774                 var item_id = button.data('item');
1775                 $("#removeResult").replaceWith('<div id="removeResult"></div>');
1776                 $("#removeFromBundleForm").attr('action', '/api/v1/items/' + item_id + '/bundled_items/');
1777                 $("#rm_external_id").focus();
1778                 bundle_changed = 0;
1779                 bundle_form_active = item_id;
1780             });
1781
1782             $("#removeFromBundleForm").submit(function(event) {
1783
1784                 /* stop form from submitting normally */
1785                 event.preventDefault();
1786
1787                 /* get the action attribute from the <form action=""> element */
1788                 var $form = $(this),
1789                 url = $form.attr('action');
1790
1791                 var barcode = $('#rm_external_id').val();
1792
1793                 /* Fetch itemnumber using rm_external_id */
1794                 var itemReq = $.get('/api/v1/items', { q: JSON.stringify({
1795                     external_id: barcode
1796                 }) }, null, "json");
1797
1798                 var itemnumber;
1799                 itemReq.done(function(data) {
1800                     if (data.length === 1) {
1801                         itemnumber = data[0].item_id;
1802
1803                         /* Remove link using fetch itemnumber */
1804                         var deleteReq = $.ajax( url + itemnumber, {
1805                             type : 'DELETE'
1806                         });
1807
1808                         /* Report the results */
1809                         deleteReq.done(function(data) {
1810                             var barcode = $('#rm_external_id').val();
1811                             $('#removeResult').replaceWith('<div id="removeResult" class="alert alert-success">'+_("Success: Removed '%s'").format(barcode)+'</div>');
1812                             $('#rm_external_id').val('').focus();
1813                             bundle_changed = 1;
1814                         });
1815                         deleteReq.fail(function(data) {
1816                             var barcode = $('#rm_external_id').val();
1817                             if ( data.status === 409 ) {
1818                                 var response = data.responseJSON;
1819                                 if (response.error_code === 'bundle_checkout_out') {
1820                                     $('#removeResult').replaceWith('<div id="removeResult" class="alert alert-danger">'+_("Failure: Bundle is currently checked out")+'</div>');
1821                                 } else if ( response.key === "PRIMARY" ) {
1822                                     $('#removeResult').replaceWith('<div id="removeResult" class="alert alert-warning">'+_("Warning: Item '%s' already attached").format(barcode)+'</div>');
1823                                 } else {
1824                                     $('#removeResult').replaceWith('<div id="removeResult" class="alert alert-danger">'+_("Failure: Item '%s' belongs to another bundle").format(barcode)+'</div>');
1825                                 }
1826                             } else if ( data.status === 404 ) {
1827                                 $('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Item '%s' not found").format(barcode)+'</div>');
1828                             } else {
1829                                 $('#removeResult').replaceWith('<div id="removeResult" class="alert alert-danger">'+_("Failure: Check the logs for details")+'</div>');
1830                             }
1831                             $('#rm_external_id').val('').focus();
1832                         });
1833                     } else {
1834                         $('#removeResult').replaceWith('<div id="removeResult" class="alert alert-danger">'+_("Failed: Barcode matched more than one item '%s'").format(barcode)+'</div>');
1835                     }
1836                 });
1837                 itemReq.fail(function(data) {
1838                      $('#removeResult').replaceWith('<div id="removeResult" class="alert alert-danger">'+_("Failed: Item not found '%s'").format(barcode)+'</div>');
1839                     $('#rm_external_id').val('').focus();
1840
1841                 });
1842             });
1843
1844             $("#removeFromBundleModal").on("hidden.bs.modal", function(e){
1845                 if ( bundle_changed ) {
1846                     $('#bundle_table_'+bundle_form_active).DataTable({ 'retrieve': true }).ajax.reload();
1847                 }
1848                 bundle_form_active = 0;
1849                 bundle_changed = 0;
1850             });
1851             // End bundle handling
1852             [% END %]
1853
1854             let items_tab_ids = [ 'holdings', 'otherholdings' ];
1855             items_tab_ids.forEach( function( tab_id, index ) {
1856                 build_items_table(tab_id, false, { dom: 'C<"top pager"ilpfB><"#filter_c">tr<"bottom pager"ip>' });
1857
1858                 [% IF bundlesEnabled %]
1859                 // Add event listener for opening and closing bundle details
1860                 $('#' + table_name + ' tbody').on('click', 'button.details-control', function () {
1861                     var button = $(this);
1862                     var tr = button.closest('tr');
1863                     var dTable = button.closest('table').DataTable({ 'retrieve': true });
1864
1865                     var itemnumber = tr.data('itemnumber');
1866                     var duedate = tr.data('duedate');
1867                     var row = dTable.row( tr );
1868
1869                     if ( row.child.isShown() ) {
1870                         // This row is already open - close it
1871                         row.child.hide();
1872                         tr.removeClass('shown');
1873                         button.removeClass('active');
1874                     }
1875                     else {
1876                         // Open this row
1877                         createChild(row, itemnumber, duedate);
1878                         tr.addClass('shown');
1879                         button.addClass('active');
1880                     }
1881                 } );
1882                 [% END %]
1883             });
1884
1885             [% IF Koha.Preference('AcquisitionDetails') %]
1886                 var table_settings = [% TablesSettings.GetTableSettings('catalogue', 'detail', 'acquisitiondetails-table', 'json') | $raw %];
1887                 var acquisitiondetails_table = KohaTable("orders", {
1888                     "dom": 'C<"top pager"ilpfB><"#filter_c">tr<"bottom pager"ip>',
1889                     "paginate": false,
1890                     "autoWidth": false,
1891                     "order": [[ 4, "desc" ]],
1892                 }, table_settings);
1893             [% END %]
1894
1895             [% IF suggestions.count %]
1896                 $(".sorted").dataTable($.extend(true, {}, dataTablesDefaults, {
1897                     "columnDefs": [
1898                         { "orderable": false, "searchable":  false, "targets": [ 'NoSort' ] },
1899                         { "type": "anti-the", "targets":  [ "anti-the" ] }
1900                     ],
1901                     "pagingType": "full"
1902                 }));
1903             [% END %]
1904
1905         });
1906
1907         [% IF found1 && Koha.Preference('RetainCatalogSearchTerms') %]
1908             $(document).ready(function() {
1909                 var search_index = localStorage.getItem("cat_search_pulldown_selection");
1910                 var search_value = localStorage.getItem("searchbox_value");
1911                 if ( search_index ){ $('#cat-search-block select.advsearch').val(search_index)};
1912                 if ( search_value ){ $('#cat-search-block #search-form').val(search_value)};
1913             });
1914         [% END %]
1915
1916         [% IF Koha.Preference('EnableItemGroups') %]
1917             // Load item groups table
1918             var itemGroupsTable = $("#items-group-table").kohaTable({
1919                 autoWidth: false,
1920                 dom: '<"top pager"ilp>t<"bottom pager"ip>r',
1921                 columns: [
1922                     {
1923                         data: "display_order",
1924                         title: _("Display order"),
1925                         searchable: true,
1926                         orderable: true,
1927                     },
1928                     {
1929                         data: "description",
1930                         title: _("Description"),
1931                         searchable: true,
1932                         orderable: true,
1933                     },
1934                     {
1935                         data: function( oObj ) {
1936                             [% IF CAN_user_editcatalogue_manage_item_groups %]
1937                                 return `<button class='item-group-edit btn btn-default btn-xs' data-item-group-id='${oObj.item_group_id}'>
1938                                     <i class="fa-solid fa-pencil" aria-hidden="true"></i> ${_("Edit")}
1939                                 </button>`
1940                                 + '&nbsp'
1941                                 + `<button class='item-group-delete btn btn-default btn-xs' data-item-group-id='${oObj.item_group_id}'>
1942                                     <i class='fa fa-trash-can'></i> ${('Delete')}
1943                                 </button>`;
1944                             [% ELSE %]
1945                                 return "";
1946                             [% END %]
1947                         },
1948                         searchable: false,
1949                         orderable: false,
1950                     },
1951                 ],
1952                 paginate: false,
1953                 ajax: { url: `/api/v1/biblios/${biblionumber}/item_groups?_per_page=-1` },
1954             });
1955
1956             // Create new item groups
1957             $('.item-group-create').on('click', function(){
1958                 $('#modal-item-group-create-form-description').val("");
1959                 $('#modal-item-group-create-submit').removeAttr('disabled');
1960                 $('#modal-item-group-create').modal('show');
1961             });
1962
1963             $("#modal-item-group-create-form").validate({
1964                 submitHandler: function(form) {
1965                     $.ajax({
1966                         url: `/api/v1/biblios/${biblionumber}/item_groups`,
1967                         headers: { "x-koha-embed": "items" },
1968                         success: function(item_groups){
1969                             $('#modal-item-group-create-submit').attr('disabled', 'disabled');
1970
1971                             var settings = {
1972                               "url": `/api/v1/biblios/${biblionumber}/item_groups`,
1973                               "method": "POST",
1974                               "headers": {
1975                                 "Content-Type": "application/json"
1976                               },
1977                               "data": JSON.stringify(
1978                                   {
1979                                       "description": $("#modal-item-group-create-form-description").val(),
1980                                       "display_order": $("#modal-item-group-create-form-display_order").val(),
1981                                   }
1982                               ),
1983                             };
1984
1985                             $.ajax(settings)
1986                             .done(function (response) {
1987                                 $('#item-group-add-form-select').append($('<option>', {
1988                                     value: response.item_group_id,
1989                                     text: response.description
1990                                 }));
1991
1992                                 $('#modal-item-group-create').modal('hide');
1993                                 if ( item_groups.length == 0 ) {
1994                                     // This bib has no previous item groups, reload the page
1995                                     window.location.replace(`/cgi-bin/koha/catalogue/detail.pl?biblionumber=${biblionumber}`);
1996                                 } else {
1997                                     // Has other item groups, just reload the table
1998                                     itemGroupsTable.api().ajax.reload();
1999                                 }
2000                             })
2001                             .fail(function(err) {
2002                                 var message = err.responseJSON.error;
2003                                 alert(message);
2004                             });
2005                         }
2006                     });
2007                 }
2008             });
2009
2010             $('#modal-item-group-create').on('shown.bs.modal', function () {
2011                 $('#modal-item-group-create-form-description').focus();
2012             })
2013
2014             // Edit existing item groups
2015             $('body').on( 'click', '.item-group-edit', function(){
2016                 const item_group_id = $(this).data('item-group-id');
2017                 const url = `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`;
2018                 $.get( url, function( data ) {
2019                     $('#modal-item-group-edit-form-description').val( data.description );
2020                     $('#modal-item-group-edit-form-display_order').val( data.display_order );
2021                     $('#modal-item-group-edit-submit').data('item-group-id', item_group_id );
2022                     $('#modal-item-group-edit-submit').removeAttr('disabled');
2023                     $('#modal-item-group-edit').modal('show');
2024                 });
2025             });
2026
2027             $("#modal-item-group-edit-form").validate({
2028                 submitHandler: function(form) {
2029                     $('#modal-item-group-edit-submit').attr('disabled', 'disabled');
2030
2031                     const item_group_id = $('#modal-item-group-edit-submit').data('item-group-id');
2032                     const url = `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`;
2033
2034                     var settings = {
2035                       "url": url,
2036                       "method": "PUT",
2037                       "headers": {
2038                         "Content-Type": "application/json"
2039                       },
2040                       "data": JSON.stringify(
2041                           {
2042                               "description": $("#modal-item-group-edit-form-description").val(),
2043                               "display_order": $("#modal-item-group-edit-form-display_order").val(),
2044                           }
2045                       ),
2046                     };
2047
2048                     $.ajax(settings)
2049                     .done(function (response) {
2050                         $('#modal-item-group-edit').modal('hide');
2051                         itemGroupsTable.api().ajax.reload();
2052                     })
2053                     .fail(function(err) {
2054                         var message = err.responseJSON.error;
2055                         alert(message);
2056                     });
2057                 }
2058             });
2059
2060             $('#modal-item-group-edit').on('shown.bs.modal', function () {
2061                 $('#modal-item-group-edit-form-description').focus();
2062             })
2063
2064             // Delete existing item groups
2065             $('body').on( 'click', '.item-group-delete', function(){
2066                 const item_group_id = $(this).data('item-group-id');
2067                 $('#modal-item-group-delete-submit').data('item-group-id', item_group_id );
2068                 $('#modal-item-group-delete-submit').removeAttr('disabled');
2069                 $('#modal-item-group-delete').modal('show');
2070             });
2071             $("#modal-item-group-delete-submit").on('click', function(){
2072                 $('#modal-item-group-delete-submit').attr('disabled', 'disabled');
2073                 const item_group_id = $("#modal-item-group-delete-submit").data('item-group-id');
2074
2075                 $.ajax({
2076                     url: `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`,
2077                     headers: { "x-koha-embed": "items" },
2078                     success: function(item_group_data){
2079                         $.ajax({
2080                           "url": `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`,
2081                           "method": "DELETE",
2082                         })
2083                         .done(function (response) {
2084                             $('#modal-item-group-delete').modal('hide');
2085                             $(`#item-group-add-form-select option[value='${item_group_id}']`).remove();
2086                             if ( item_group_data.items === null ) {
2087                                 // No items for this item group, we can just refresh the table
2088                                 itemGroupsTable.api().ajax.reload();
2089                             } else {
2090                                 // This item group had items attached to it, we need to reload the page
2091                                 window.location.replace(`/cgi-bin/koha/catalogue/detail.pl?biblionumber=${biblionumber}`);
2092                             }
2093                         })
2094                         .fail(function(err) {
2095                             var message = err.responseJSON.error;
2096                             alert(message);
2097                         });
2098                     }
2099                 });
2100             });
2101
2102             // Add item(s) to a item group
2103             $('.itemselection_action_item_group_set').on('click', function(){
2104                 $('#modal-item-group-set').modal('show');
2105             });
2106
2107             $("#modal-item-group-set-form").validate({
2108                 submitHandler: function(form) {
2109                     $('#modal-item-group-set-submit').attr('disabled', 'disabled');
2110
2111                     const item_group_id = $('#item-group-add-form-select').val();
2112
2113                     let itemnumbers = new Array();
2114                     $("input[name='itemnumber'][type='checkbox']:checked").each(function() {
2115                         const itemnumber = $(this).val();
2116                         itemnumbers.push( itemnumber );
2117                     });
2118                     if (itemnumbers.length > 0) {
2119                         let url = '/cgi-bin/koha/catalogue/detail.pl?op=set_item_group';
2120                         url += '&itemnumber=' + itemnumbers.join('&itemnumber=');
2121                         url += '&biblionumber=[% biblionumber | uri %]';
2122                         url += `&item_group_id=${item_group_id}`;
2123
2124                         window.location.replace(url);
2125                     }
2126
2127                     $('#modal-item-group-set').modal('hide');
2128                 }
2129             });
2130
2131             // Remove item(s) from an item group
2132             $('.itemselection_action_item_group_unset').on('click', function(){
2133                 $('#modal-item-group-unset').modal('show');
2134             });
2135
2136             $("#modal-item-group-unset-submit").on('click', function(){
2137                 $('#modal-item-group-unset-submit').attr('disabled', 'disabled');
2138
2139                 let itemnumbers = new Array();
2140                 $("input[name='itemnumber'][type='checkbox']:checked").each(function() {
2141                     const itemnumber = $(this).val();
2142                     itemnumbers.push( itemnumber );
2143                 });
2144                 if (itemnumbers.length > 0) {
2145                     let url = '/cgi-bin/koha/catalogue/detail.pl?op=unset_item_group';
2146                     url += '&itemnumber=' + itemnumbers.join('&itemnumber=');
2147                     url += '&biblionumber=[% biblionumber | uri %]';
2148
2149                     window.location.replace(url);
2150                 }
2151
2152                 $('#modal-item-group-unset').modal('hide');
2153
2154             });
2155         [% END %]
2156         const can_edit_items_from = [% To.json(can_edit_items_from || {}) | $raw %];
2157         const item_type_image_locations = [% To.json(item_type_image_locations) | $raw %];
2158         const av_loc = new Map([% To.json(AuthorisedValues.Get('LOC')) | $raw %].map( av => [av.authorised_value, av.lib]));
2159         const av_lost = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.itemlost' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2160         const av_withdrawn = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.withdrawn' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2161         const av_damaged = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.damaged' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2162         const av_not_for_loan= new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.notforloan' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2163         const av_restricted = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.restricted' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2164         [% IF Koha.Preference('UseCourseReserves') %]
2165             const av_courses_term = new Map([% To.json(AuthorisedValues.Get('TERM')) | $raw %].map( av => [av.authorised_value, av.lib]));
2166         [% END %]
2167         [% IF Koha.Preference('URLLinkText') %]
2168             const url_link_text = "[% Koha.Preference('URLLinkText') | html %]";
2169         [% ELSE %]
2170             const url_link_text = _("Link to resource");
2171         [% END %]
2172         [%# FIXME The X-Base-Total-Count will be the number of items of the biblios %]
2173         [%# In case or SeparateHoldings we may need to display the number of biblios in each tab %]
2174         [%# Do we need separate/new endpoints or do we hack the somewhere client-side? %]
2175         let item_table_url = "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?";
2176         let embed = ["+strings,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,item_type"];
2177         [% IF Koha.Preference('LocalCoverImages') %]
2178             embed.push('cover_image_ids');
2179         [% END %]
2180         [% IF Koha.Preference('EnableItemGroups') %]
2181             embed.push('item_group_item.item_group.description');
2182         [% END %]
2183         [% IF biblio.serial %]
2184             embed.push('serialitem.serial');
2185         [% END %]
2186         [% IF Koha.Preference('UseRecalls') %]
2187             embed.push('recall', 'recall+strings', 'recall.patron')
2188         [% END %]
2189         embed.push('in_bundle', 'bundle_host');
2190         [% IF Koha.Preference('UseCourseReserves') %]
2191             embed.push('course_item.course_reserves.course');
2192         [% END %]
2193
2194         let items_table_settings = {
2195             holdings: [% TablesSettings.GetTableSettings('catalogue', 'detail','holdings_table','json') | $raw %],
2196             otherholdings: [% TablesSettings.GetTableSettings('catalogue', 'detail','otherholdings_table','json')  | $raw %],
2197         };
2198
2199         function build_items_table (tab_id, add_filters, dt_options) {
2200
2201             let default_filters = {};
2202             [% IF Koha.Preference('SeparateHoldings') %]
2203                 [% SET SeparateHoldingsBranch = Koha.Preference('SeparateHoldingsBranch') || 'homebranch' %];
2204                 let branch = '[% IF SeparateHoldingsBranch == 'homebranch' %]me.home_library_id[% ELSE %]me.holding_library_id[% END %]';
2205                 if ( tab_id == 'holdings' ) {
2206                     default_filters[branch] = '[% Branches.GetLoggedInBranchcode() | html %]';
2207                 } else {
2208                     default_filters[branch] = { '!=': '[% Branches.GetLoggedInBranchcode() | html  %]' };
2209                 }
2210             [% END %]
2211
2212             [% IF hidden_count %]
2213                 default_filters.lost_status = "0";
2214             [% END %]
2215             if ( !items_selection.hasOwnProperty(tab_id) ){
2216                 items_selection[tab_id] = [];
2217             }
2218             var items_table = $("#" + tab_id + '_table').kohaTable({
2219                 ajax: { url: item_table_url },
2220                 order: [[ 0, "asc" ]],
2221                 embed,
2222                 autoWidth: false,
2223                 bKohaColumnsUseNames: true,
2224                 columns: [
2225                 [% IF (StaffDetailItemSelection) %]
2226                 {
2227                     data: "me.item_id",
2228                     searchable: false,
2229                     orderable: false,
2230                     render: function (data, type, row, meta) {
2231                         if ( can_edit_items_from[row.holding_library_id] ){
2232                             if ( items_selection[tab_id].includes(row.item_id) ) {
2233                                 return '<input type="checkbox" value="%s" name="itemnumber" checked />'.format(row.item_id);
2234                             } else {
2235                                 return '<input type="checkbox" value="%s" name="itemnumber" />'.format(row.item_id);
2236                             }
2237                         } else {
2238                             return ''
2239                         }
2240                     }
2241                 },
2242                 [% END %]
2243                 [% IF Koha.Preference('LocalCoverImages') %]
2244                 {
2245                     data: "",
2246                     className: "cover",
2247                     searchable: false,
2248                     orderable: false,
2249                     render: function (data, type, row, meta) {
2250                         if ( !row.cover_image_ids.length > 0 ) {
2251                             return '';
2252                         }
2253                         let node = '<div class="bookcoverimg">';
2254                         node += '<div class="cover-slider">';
2255                         row.cover_image_ids.forEach(id => {
2256                             node += '<div class="cover-image local-coverimg">';
2257                             node += '<a href="/cgi-bin/koha/catalogue/image.pl?itemnumber=%s&amp;imagenumber=%s" title="Local cover image">'.format(id, id);
2258                             node += '<img src="/cgi-bin/koha/catalogue/image.pl?thumbnail=1&amp;imagenumber=%s" alt="Local cover image" data-link="/cgi-bin/koha/catalogue/imageviewer.pl?itemnumber=[% item.itemnumber | uri %]&amp;imagenumber=%s" />'.format(id, id);
2259                             node += '</a>';
2260                             node += '</div>';
2261                         });
2262                         node += '</div>';
2263                         node += '</div>';
2264                         return node;
2265                     }
2266                 },
2267                 [% END %]
2268                 [% IF ( item_level_itypes ) %]
2269                 {
2270                     data: "me.itype:biblioitem.itemtype",
2271                     className: "itype",
2272                     searchable: true,
2273                     orderable: true,
2274                     render: function (data, type, row, meta) {
2275                         let node = '';
2276                         [% UNLESS noItemTypeImages %]
2277                             let image_location = item_type_image_locations[row.item_type_id];
2278                             let item_type_description = row._strings.item_type_id.str;
2279                             node += image_location
2280                                 ? '<img src="%s" alt="%s" title="%s" /> '.format(escape_str(image_location), escape_str(item_type_description), escape_str(item_type_description))
2281                                 : '';
2282                         [% END %]
2283                         node += '<span class="itypedesc itypetext">%s</span>'.format(escape_str(item_type_description));
2284                         return node;
2285                     }
2286                 },
2287                 [% END %]
2288                 {
2289                     data: "me.holding_library_id",
2290                     className: "location",
2291                     searchable: true,
2292                     orderable: true,
2293                     render: function (data, type, row, meta) {
2294                         return escape_str(row._strings.holding_library_id.str);
2295                     }
2296                 },
2297                 {
2298                     data: "me.home_library_id",
2299                     className: "homebranch",
2300                     searchable: true,
2301                     orderable: true,
2302                     render: function (data, type, row, meta) {
2303                         let nodes = '<span class="homebranchdesc">%s</span>'.format(escape_str(row._strings.home_library_id.str));
2304                         nodes += '<span class="shelvingloc">'
2305                         [%# If permanent location is defined, show description or code and             %]
2306                         [%# display current location in parentheses. If not, display current location. %]
2307                         [%# Note that permanent location is a code, and location may be an authval.    %]
2308                         let loc_str = row._strings.location.str;
2309                         if ( row.permanent_location && row.permanent_location != row.location ) {
2310                             let permanent_loc_str = av_loc[row.permanent_location];
2311                             nodes += '%s (%s)'.format(escape_str(permanent_loc_str), escape_str(loc_str));
2312                         } else {
2313                             nodes += escape_str(loc_str);
2314                         }
2315                         nodes += '</span>';
2316                         return nodes;
2317                     }
2318                 },
2319                 {
2320                     data: "me.collection_code",
2321                     searchable: true,
2322                     orderable: true,
2323                     render: function (data, type, row, meta) {
2324                         return escape_str(row._strings.collection_code.str);
2325                     }
2326                 },
2327                 [% IF Koha.Preference('EnableItemGroups') %]
2328                 {
2329                     data: "item_group_item.item_group.description",
2330                     className: "item_group",
2331                     searchable: true,
2332                     orderable: true,
2333                     render: function (data, type, row, meta) {
2334                         if ( row.item_group_item ) {
2335                             return escape_str(row.item_group_item.item_group.description);
2336                         } else {
2337                             return "";
2338                         }
2339                     }
2340                 },
2341                 [% END %]
2342                 {
2343                     data: "me.callnumber",
2344                     className: "itemcallnumber",
2345                     searchable: true,
2346                     orderable: true,
2347                     render: function (data, type, row, meta) {
2348                         return escape_str(row.callnumber);
2349                     }
2350
2351                 },
2352                 {
2353                     data: "me.serial_issue_number",
2354                     className: "enumchron",
2355                     searchable: true,
2356                     orderable: true,
2357                     render: function (data, type, row, meta) {
2358                         let nodes = "";
2359                         [%# FIXME Previously we displayed the column if at least one item of the biblio had an enumchron/serial_issue_number. Now it's only if one item of the ones displayed on the current page, how is that bad? How can it be fixed in an elegant way? Should we display the column only if biblio.serial? %]
2360                         let serial = row.serialitem ? row.serialitem.serial : null;
2361                         if ( row.serial_issue_number && serial && serial.serialseq ) {
2362                             nodes += '<span class="enum">%s</span>'.format(escape_str(row.serial_issue_number));
2363                             if ( serial.serialseq && row.serial_issue_number != serial.serialseq ) {
2364                                 nodes += ' <span class="sep"> -- </span>'
2365                                 nodes += ' <span class="serialseq">%s</span>'.format(escape_str(serial.serialseq));
2366                             }
2367                         } else if ( row.serial_issue_number ) {
2368                             nodes += ' <span class="enum">%s</span>'.format(escape_str(row.serial_issue_number));
2369                         } else if ( serial && serial.serialseq ) {
2370                             nodes += '<span class="serialseq">%s</span>'.format(escape_str(serial.serialseq));
2371                         }
2372                         if ( serial && serial.publisheddate ) {
2373                             nodes += ' <span class="pubdate">(%s)</span>'.format($date(serial.publisheddate));
2374                         }
2375                         return nodes;
2376                     }
2377                 },
2378                 {
2379                     data: "me.lost_status",
2380                     className: "status",
2381                     searchable: false, // FIXME We are losing the ability to search on the status
2382                     orderable: false,
2383                     render: function (data, type, row, meta) {
2384                         let nodes = "";
2385                         if ( row.checkout ) {
2386                             nodes += '<span>';
2387                             if ( row.checkout.onsite_checkout ) {
2388                                 let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
2389                                 nodes += _("Currently in local use by %s").format(patron_to_html);
2390                             } else {
2391                                 nodes += '<span class="datedue">';
2392                                 let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
2393                                 nodes += _("Checked out to %s").format(patron_to_html);
2394                             }
2395                             nodes += ': ';
2396                             nodes += _("due %s").format($date(row.checkout.due_date, { as_due_date: true }));
2397                             nodes += "</span>"
2398                         } else if ( row.transfer ) {
2399                             if ( row.transfer.datesent ) {
2400                                 nodes += '<span class="intransit">%s</span>'.format(_("In transit from %s to %s since %s").format(escape_str(row.transfer._strings.from_library.str), escape_str(row.transfer._strings.to_library.str), $date(row.transfer.datesent)));
2401                             } else {
2402                                 nodes += '<span class="transitrequested">%s</span>'.format(_("Transit pending from %s to %s since %s").format(escape_str(row.transfer._strings.from_library_.str), escape_str(row.transfer._strings.to_library.str), $date(row.transfer.daterequested)));
2403                             }
2404                         }
2405
2406                         if ( row.lost_status ) {
2407                             let lost_lib = av_lost.get(row.lost_status.toString()) || _("Unavailable (lost or missing");
2408                             nodes += '<span class="lost">%s</span>'.format(escape_str(lost_lib));
2409                         }
2410
2411                         if ( row.withdrawn ) {
2412                             let withdrawn_lib = av_withdrawn.get(row.withdrawn.toString()) || _("Withdrawn");
2413                             nodes += '<span class="wdn">%s</span>'.format(escape_str(withdrawn_lib));
2414                         }
2415
2416                         if ( row.damaged ) {
2417                             let damaged_lib = av_damaged.get(row.damaged.toString()) || _("Damaged");
2418                             nodes += '<span class="dmg">%s</span>'.format(escape_str(damaged_lib));
2419                         }
2420
2421                         if ( row.not_for_loan_status || row.item_type.notforloan ) {
2422                             let not_for_loan_lib = av_not_for_loan.get(row.not_for_loan_status.toString());
2423                             nodes += '<span class="notforloan">%s'.format(_("Not for loan")) + ( not_for_loan_lib ? '<span class="reason"> (%s)</span>'.format(escape_str(not_for_loan_lib)) : '' ) + '</span>';
2424                         }
2425
2426                         if ( row.first_hold ) {
2427                             if ( row.first_hold.waiting_date ) {
2428                                 [%# FIXME We lost the desk name, we need an additional embed %]
2429                                 nodes += '<span class="waitingat">%s</span>'.format(_("Waiting at %s since %s.".format(row.first_hold._strings.pickup_library_id.str, $date(row.first_hold.waiting_date))));
2430                                 [% IF Koha.Preference('canreservefromotherbranches') %]
2431                                     if ( row.first_hold.waiting_date || row.first_hold.priority == 1 ) {
2432                                         let patron_to_html = $patron_to_html(row.first_hold.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
2433                                         nodes += ' <span class="heldfor">%s</span>'.format(_("Hold for: %s").format(patron_to_html));
2434                                     }
2435                                 [% END %]
2436                             } else {
2437                                 nodes += '<span class="holdonitem">%s</span>'.format(_("There is an item level hold on this item (priority = %s).").format(row.first_hold.priority));
2438                             }
2439                         }
2440
2441                         [% IF Koha.Preference('UseRecalls') %]
2442                             if ( row.recall ) {
2443                                 if ( row.recall.waiting_date ) {
2444                                     nodes += '<span>%s</span>'.format(_("Waiting at %s since %s").format(escape_str(row.recall.pickup_library_id.str), $date(row.recall.waiting_date)));
2445                                 } else {
2446                                     let patron_to_html = $patron_to_html(row.recall.patron);
2447                                     nodes += '<span>%s</span>'.format(_("recalled by %s on %s").format(patron_to_html, $date(row.recall.created_date)))
2448                                 }
2449                             }
2450                         [% END %]
2451
2452                         if ( ! ( row.not_for_loan_status || row.item_type.notforloan || row.checked_out_date || row.lost_status || row.withdrawn || row.damaged || row.transfer || row.first_hold || row.recall ) ) {
2453                             nodes += ' <span>%s</span>'.format(_("Available"))
2454                         }
2455
2456                         if ( row.restricted_status ) {
2457                             nodes += '<span class="restricted">(%s)</span>'.format(escape_str(av_restricted.get(row.restricted_status.toString())));
2458                         }
2459
2460                         if ( row.in_bundle ) {
2461                             nodes += '<span class="bundled">%s</span>'.format(_("In bundle: %s").format($biblio_to_html(row.bundle_host.biblio, { link: true })));
2462                         }
2463                         return nodes;
2464                     }
2465                 },
2466                 {
2467                     data: "me.last_seen_date",
2468                     className: "datelastseen",
2469                     searchable: true,
2470                     orderable: true,
2471                     render: function (data, type, row, meta) {
2472                         return $date(row.last_seen_date);
2473                     }
2474                 },
2475                 {
2476                     data: "me.checkouts_count",
2477                     className: "issues",
2478                     searchable: true,
2479                     orderable: true,
2480                     render: function (data, type, row, meta) {
2481                         return row.checkouts_count || 0;
2482                     }
2483                 },
2484                 {
2485                     data: "me.renewals_count",
2486                     className: "renewals",
2487                     searchable: true,
2488                     orderable: true,
2489                     render: function (data, type, row, meta) {
2490                         return row.renewals_count || 0;
2491                     }
2492                 },
2493                 {
2494                     data: "me.acquisition_date",
2495                     className: "dateaccessioned",
2496                     searchable: true,
2497                     orderable: true,
2498                     render: function (data, type, row, meta) {
2499                         return $date(row.acquisition_date);
2500                     }
2501                 },
2502                 {
2503                     data: "me.last_checkout_date",
2504                     className: "datelastborrowed",
2505                     searchable: true,
2506                     orderable: true,
2507                     render: function (data, type, row, meta) {
2508                         return $date(row.last_checkout_date);
2509                     }
2510                 },
2511                 {
2512                     data: "me.external_id",
2513                     className: "",
2514                     searchable: true,
2515                     orderable: true,
2516                     render: function (data, type, row, meta) {
2517                         return '<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=%s#item%s">%s</a>'.format(row.biblio_id, row.item_id, row.external_id);
2518                     }
2519                 },
2520                 {
2521                     data: "me.uri",
2522                     className: "uri",
2523                     searchable: true,
2524                     orderable: true,
2525                     render: function (data, type, row, meta) {
2526                         if ( !row.uri ) return "";
2527
2528                         let nodes = '';
2529                         if ( row.uri.split(' \| ').length > 1 ) {
2530                             row.uri.split(' \| ').forEach((uri, i) => {
2531                                 nodes += '<a href="%s">%s</a><br/>'.format(escape_str(uri), escape_str(uri));
2532                             });
2533                         } else {
2534                             nodes += '<a href="%s">%s</a><br/>'.format(escape_str(row.uri), escape_str(url_link_text));
2535                         }
2536                         return nodes;
2537                     }
2538                 },
2539                 {
2540                     data: "me.copy_number",
2541                     className: "copynumber",
2542                     searchable: true,
2543                     orderable: true,
2544                     render: function (data, type, row, meta) {
2545                         return escape_str(row._strings.copy_number ? row._strings.copy_number.str : row.copy_number);
2546                     }
2547                 },
2548                 {
2549                     data: "me.inventory_number",
2550                     className: "stocknumber",
2551                     searchable: true,
2552                     orderable: true,
2553                     render: function (data, type, row, meta) {
2554                         return escape_str(row.inventory_number);
2555                     }
2556                 },
2557                 {
2558                     data: "me.materials_notes",
2559                     className: "materials",
2560                     searchable: true,
2561                     orderable: true,
2562                     render: function (data, type, row, meta) {
2563                         return escape_str(row.materials_notes);
2564                     }
2565                 },
2566                 {
2567                     data: "me.public_notes",
2568                     className: "itemnotes",
2569                     searchable: true,
2570                     orderable: true,
2571                     render: function (data, type, row, meta) {
2572                         return row.public_notes ? escape_str(row.public_notes).replaceAll('\n', '<br />') : '';
2573                     }
2574                 },
2575                 {
2576                     data: "me.internal_notes",
2577                     className: "nonpublicnote",
2578                     searchable: true,
2579                     orderable: true,
2580                     render: function (data, type, row, meta) {
2581                         return escape_str(row.internal_notes);
2582                     }
2583                 },
2584                 [% IF ( hostrecords ) %]
2585                 {
2586                     data: "biblio.biblio_id",
2587                     searchable: false, // FIXME
2588                     orderable: true,
2589                     render: function (data, type, row, meta) {
2590                         if ( row.biblio_id == [% biblio.biblionumber | html %] ) return "";
2591                         return '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=%s>%s</a>'.format(row.biblio_id, row.biblio.title);
2592                     }
2593                 },
2594                 [% END %]
2595                 [% IF ( analyze ) %]
2596                 {
2597                     data: "",
2598                     searchable: false, // FIXME
2599                     orderable: true,
2600                     render: function (data, type, row, meta) {
2601                         return ""; // FIXME Display analytic count + link
2602                     }
2603                 },
2604                 [% END %]
2605                 [% IF Koha.Preference('UseCourseReserves') %]
2606                 {
2607                     data: "course_item.course_reserves.course.course_name",
2608                     searchable: true,
2609                     orderable: true,
2610                     render: function (data, type, row, meta) {
2611                         let nodes = '';
2612                         if (!row.course_item) return nodes;
2613                         row.course_item.course_reserves.forEach((cr, i) => {
2614                             let c = cr.course;
2615                             if ( c.enabled != 'yes' ) return;
2616                             nodes += '<p>';
2617                             nodes += '<a href="/cgi-bin/koha/course_reserves/course-details.pl?course_id=%s">'.format(c.course_id);
2618                             nodes += escape_str(c.course_name);
2619                             if ( c.section ) {
2620                                 nodes += ' ' + escape_str(c.section);
2621                             }
2622                             if ( c.term ) {
2623                                 nodes += ' ' + av_courses_term.get(c.term.toString());
2624                             }
2625                             nodes += '</p>';
2626                         });
2627                         return nodes;
2628                     }
2629                 },
2630                 [% END %]
2631                 [% IF ( SpineLabelShowPrintOnBibDetails ) %]
2632                 {
2633                     data: "",
2634                     searchable: false,
2635                     orderable: false,
2636                     render: function (data, type, row, meta) {
2637                         return '<a class="btn btn-default btn-xs print-label" href="/cgi-bin/koha/labels/spinelabel-print.pl?barcode=%s"><i class="fa fa-print"></i> Print label</a>'.format(escape_str(row.external_id));
2638                     }
2639                 },
2640                 [% END %]
2641                 [% IF CAN_user_editcatalogue_edit_items %]
2642                 {
2643                     data: function( row, type, val, meta ) {
2644                         let nodes = '';
2645                         if ( can_edit_items_from[row.holding_library_id] ){
2646                             [% IF Koha.Preference('LocalCoverImages') OR Koha.Preference('OPACLocalCoverImages') %]
2647                                 nodes += '<div class="btn-group">';
2648                                 nodes += ' <a class="btn btn-default btn-xs" href="/cgi-bin/koha/cataloguing/additem.pl?op=edititem&biblionumber=%s&itemnumber=%s#edititem"><i class="fa-solid fa-pencil"></i> Edit</a><a class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></a>'.format(row.biblio_id, row.item_id);
2649                                 nodes += ' <ul class="dropdown-menu pull-right">';
2650                                 nodes += '  <li><a href="/cgi-bin/koha/tools/upload-cover-image.pl?itemnumber=%s&amp;filetype=image"><i class="fa fa-upload"></i> Upload image</a></li>'.format(row.item_id);
2651                                 nodes += ' </ul>';
2652                                 nodes += '</div>';
2653                             [% ELSE %]
2654                                 nodes += '<a class="btn btn-default btn-xs" href="/cgi-bin/koha/cataloguing/additem.pl?op=edititem&biblionumber=%s&itemnumber=%s#edititem"><i class="fa-solid fa-pencil"></i> Edit</a>'.format(row.biblio_id, row.item_id);
2655                             [% END %]
2656                         }
2657                         [% IF bundlesEnabled %]
2658                             // FIXME How do we handle that correctly?
2659                             //nodes += '<button class="btn btn-default btn-xs details-control"><i class="fa fa-folder"></i> Manage bundle (%s|%s)</button>'.format(escape_str(row.bundled), escape_str(row.bundled_lost));
2660                         [% END %]
2661
2662                         return nodes;
2663                     },
2664                     className: "actions",
2665                     searchable: false,
2666                     orderable: false
2667                 }
2668                 [% END %]
2669                 ],
2670                 initComplete: function( settings, json ){
2671                     let table = settings.oInstance.api();
2672                     table.columns().every(function(i){
2673                         let is_empty = true;
2674                         let nodes = this.nodes();
2675                         nodes.each((td, ii) => {
2676                             if ( $(td).html() !== '' ) {
2677                                 is_empty = false;
2678                                 return;
2679                             }
2680                         });
2681                         if ( is_empty ) {
2682                             table.columns(i).visible(false);
2683                         }
2684                     });
2685                     itemSelectionBuildActionLinks(tab_id);
2686                 },
2687                 [% IF StaffDetailItemSelection %]
2688                 drawCallback: function(settings){
2689                     var api = new $.fn.dataTable.Api(settings)
2690                     $.each(
2691                         $(this).find("tbody tr td:first-child"),
2692                         function (index, e) {
2693                             let tr = $(this).parent()
2694                             let row = api.row(tr).data()
2695                             if (!row) return // Happen if the table is empty
2696                             $(this).find("input[name='itemnumber'][type='checkbox']").on("change", function(){
2697                                 let itemnumber = parseInt($(this).val());
2698                                 if( $(this).prop("checked") ){
2699                                     items_selection[tab_id].push(itemnumber);
2700                                 } else {
2701                                     items_selection[tab_id] = items_selection[tab_id].filter( id => id != itemnumber );
2702                                 }
2703                                 itemSelectionBuildActionLinks(tab_id);
2704                             });
2705                         }
2706                     );
2707                 },
2708                 [% END %]
2709                 ...dt_options,
2710             },
2711             items_table_settings[tab_id],
2712             add_filters,
2713             default_filters,
2714             );
2715
2716             return items_table;
2717         }
2718     </script>
2719     [% CoverImagePlugins | $raw %]
2720 [% END %]
2721 [% INCLUDE 'intranet-bottom.inc' %]