View | Details | Raw Unified | Return to bug 33568
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc (+738 lines)
Line 0 Link Here
1
[% USE To %]
2
[% USE Koha %]
3
[% USE AuthorisedValues %]
4
[% USE raw %]
5
6
[% BLOCK items_table %]
7
    <div class="[% tab | html %]_table_table_controls">
8
        [% IF (StaffDetailItemSelection) %]
9
10
            <span class="show_hide_filters">
11
                <a href="#" class="show_filters" data-tab="[% tab | html %]"><i class="fa fa-filter"></i> Show filters</a>
12
                <a href="#" class="hide_filters" data-tab="[% tab | html %]" style="display: none;"><i class="fa fa-filter"></i> Hide filters</a>
13
            </span>
14
            | <a href="#" class="SelectAll" data-tab="[% tab | html %]"><i class="fa fa-check"></i> Select all</a>
15
            | <a href="#" class="ClearAll" data-tab="[% tab | html %]"><i class="fa fa-times"></i> Clear all</a>
16
            <span class="itemselection_actions">
17
              | Actions:
18
              [% IF CAN_user_tools_items_batchdel %]
19
                <a class="itemselection_action_delete"><i class="fa fa-trash-can"></i> Delete selected items</a>
20
              [% END %]
21
              [% IF CAN_user_tools_items_batchmod %]
22
                <a class="itemselection_action_modify"><i class="fa-solid fa-pencil"></i> Modify selected items</a>
23
              [% END %]
24
              [% IF CAN_user_editcatalogue_manage_item_groups && biblio.item_groups.count %]
25
                <a class="itemselection_action_item_group_set" href="#"><i class="fa fa-book"></i> Add/move to item group</a>
26
                <a class="itemselection_action_item_group_unset" href="#"><i class="fa fa-unlink"></i> Remove from item group</a>
27
              [% END %]
28
            </span>
29
        [% END %]
30
    </div>
31
32
    <table class="items_table" id="[% tab | html %]_table">
33
        <thead>
34
            [% IF (StaffDetailItemSelection) %]<th id="[% tab | html %]_checkbox" data-colname="[% tab | html %]_checkbox" class="NoSort"></th>[% END %]
35
            [% IF Koha.Preference('LocalCoverImages') %]
36
                <th id="[% tab | html %]_cover_image" data-colname="[% tab | html %]_cover_image">Cover image</th>
37
            [% END %]
38
            [% IF ( item_level_itypes ) %]<th id="[% tab | html %]_itype" data-colname="[% tab | html %]_itype">Item type</th>[% END %]
39
            <th id="[% tab | html %]_holdingbranch" data-colname="[% tab | html %]_holdingbranch">Current library</th>
40
            <th id="[% tab | html %]_homebranch" data-colname="[% tab | html %]_homebranch">Home library</th>
41
            <th id="[% tab | html %]_ccode" data-colname="[% tab | html %]_ccode">Collection</th>
42
            [% IF Koha.Preference('EnableItemGroups') %]
43
                <th id="[% tab | html %]_item_group" data-colname="[% tab | html %]_item_group">Item group</th>
44
            [% END %]
45
            <th id="[% tab | html %]_itemcallnumber" data-colname="[% tab | html %]_itemcallnumber">Call number</th>
46
            <th id="[% tab | html %]_enumchron" data-colname="[% tab | html %]_enumchron">Serial enumeration / chronology</th>
47
            <th id="[% tab | html %]_status" data-colname="[% tab | html %]_status">Status</th>
48
            <th id="[% tab | html %]_lastseen" data-colname="[% tab | html %]_lastseen">Last seen</th>
49
            <th id="[% tab | html %]_issues" data-colname="[% tab | html %]_issues">Checkouts</th>
50
            <th id="[% tab | html %]_renewals" data-colname="[% tab | html %]_renewals">Renewals</th>
51
            <th id="[% tab | html %]_dateaccessioned" data-colname="[% tab | html %]_dateaccessioned">Date accessioned</th>
52
            <th id="[% tab | html %]_datelastborrowed" data-colname="[% tab | html %]_datelastborrowed">Date last borrowed</th>
53
            <th id="[% tab | html %]_barcode" data-colname="[% tab | html %]_barcode">Barcode</th>
54
            <th id="[% tab | html %]_uri" data-colname="[% tab | html %]_uri">URL</th>
55
            <th id="[% tab | html %]_copynumber" data-colname="[% tab | html %]_copynumber">Copy number</th>
56
            <th id="[% tab | html %]_stocknumber" data-colname="[% tab | html %]_stocknumber">Inventory number</th>
57
            <th id="[% tab | html %]_materials" data-colname="[% tab | html %]_materials">Materials specified</th>
58
            <th id="[% tab | html %]_itemnotes" data-colname="[% tab | html %]_itemnotes">Public notes</th>
59
            <th id="[% tab | html %]_itemnotes_nonpublic" data-colname="[% tab | html %]_itemnotes_nonpublic">Non-public notes</th>
60
            <th id="[% tab | html %]_hostrecord" data-colname="[% tab | html %]_hostrecord">Host records</th>
61
            [% IF ( analyze ) %]<th id="[% tab | html %]_usedin" data-colname="[% tab | html %]_usedin">Used in</th><th></th>[% END %]
62
            [% IF Koha.Preference('UseCourseReserves') %]<th id="[% tab | html %]_course_reserves" data-colname="[% tab | html %]_course_reserves">Course reserves</th>[% END %]
63
            [% IF ( SpineLabelShowPrintOnBibDetails ) %]<th id="[% tab | html %]_spinelabel" data-colname="[% tab | html %]_spinelabel" class="NoSort">Spine label</th>[% END %]
64
            [% IF ( CAN_user_editcatalogue_edit_items ) %]<th id="[% tab | html %]_actions" data-colname="[% tab | html %]_actions"class="NoSort noExport">&nbsp;</th>[% END %]
65
            </tr>
66
        </thead>
67
    </table>
68
[% END %][%# end of block items_table %]
69
70
71
[% BLOCK build_items_table_js %]
72
<script>
73
74
    [% IF StaffDetailItemSelection %]
75
76
        let items_selection = {};
77
        function itemSelectionBuildDeleteLink(tab_id) {
78
            var itemnumbers = items_selection[tab_id];
79
            if (itemnumbers.length > 0) {
80
                var url = '/cgi-bin/koha/tools/batchMod.pl?op=show&del=1';
81
                url += '&itemnumber=' + itemnumbers.join('&itemnumber=');
82
                url += '&biblionumber=[% biblionumber | uri %]';
83
                url += '&src=CATALOGUING';
84
                $('a.itemselection_action_delete').attr('href', url);
85
            } else {
86
                return false;
87
            }
88
            return true
89
        }
90
91
        function itemSelectionBuildModifyLink(tab_id) {
92
            var itemnumbers = items_selection[tab_id];
93
            if (itemnumbers.length > 0) {
94
                var url = '/cgi-bin/koha/tools/batchMod.pl?op=show';
95
                url += '&itemnumber=' + itemnumbers.join('&itemnumber=');
96
                url += '&biblionumber=[% biblionumber | uri %]';
97
                url += '&src=CATALOGUING';
98
                $('a.itemselection_action_modify').attr('href', url);
99
            } else {
100
                return false;
101
            }
102
            return true;
103
        }
104
105
        function itemSelectionBuildActionLinks(tab_id) {
106
            var delete_link_ok = itemSelectionBuildDeleteLink(tab_id);
107
            var modify_link_ok = itemSelectionBuildModifyLink(tab_id);
108
            var div = $("#" + tab_id);
109
            if (modify_link_ok || delete_link_ok) {
110
                $('.itemselection_actions', div).show();
111
            } else {
112
                $('.itemselection_actions', div).hide();
113
            }
114
        }
115
116
        $(document).ready(function() {
117
118
            $(".SelectAll").on("click",function(e){
119
                e.preventDefault();
120
                var tab = $(this).data("tab");
121
                $("input[name='itemnumber'][type='checkbox']", $("#"+tab)).prop('checked', true);
122
                itemSelectionBuildActionLinks(tab);
123
            });
124
125
            $(".ClearAll").on("click",function(e){
126
                e.preventDefault();
127
                var tab = $(this).data("tab");
128
                $("input[name='itemnumber'][type='checkbox']", $("#"+tab)).prop('checked', false);
129
                itemSelectionBuildActionLinks(tab);
130
            });
131
132
            $(".show_filters").on("click",function(e){
133
                e.preventDefault();
134
                let tab_id = $(this).data("tab");
135
                let tab = $("#"+tab_id);
136
                tab.find(".show_filters").hide();
137
                tab.find(".hide_filters").show();
138
                $("#"+tab_id+"_table thead tr:eq(1)").remove();
139
                build_items_table(tab_id, true, { dom: dataTablesDefaults.dom, destroy: true } );
140
            });
141
142
            $(".hide_filters").on("click",function(e){
143
                e.preventDefault();
144
                let tab_id = $(this).data("tab");
145
                let tab = $("#"+tab_id);
146
                tab.find(".hide_filters").hide();
147
                tab.find(".show_filters").show();
148
                $("#"+tab_id+"_table thead tr:eq(1)").remove();
149
                build_items_table(tab_id, false, { dom: '<"dt-info"i><"top pager"lpfB><"#filter_c">tr<"bottom pager"ip>', destroy: true } );
150
            });
151
        });
152
    [% END %]
153
154
155
    const can_edit_items_from = [% To.json(can_edit_items_from || {}) | $raw %];
156
    const item_type_image_locations = [% To.json(item_type_image_locations) | $raw %];
157
    const av_loc = new Map([% To.json(AuthorisedValues.Get('LOC')) | $raw %].map( av => [av.authorised_value, av.lib]));
158
    const av_lost = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.itemlost' })) | $raw %].map( av => [av.authorised_value, av.lib]));
159
    const av_withdrawn = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.withdrawn' })) | $raw %].map( av => [av.authorised_value, av.lib]));
160
    const av_damaged = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.damaged' })) | $raw %].map( av => [av.authorised_value, av.lib]));
161
    const av_not_for_loan= new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.notforloan' })) | $raw %].map( av => [av.authorised_value, av.lib]));
162
    const av_restricted = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.restricted' })) | $raw %].map( av => [av.authorised_value, av.lib]));
163
    [% IF Koha.Preference('UseCourseReserves') %]
164
        const av_courses_term = new Map([% To.json(AuthorisedValues.Get('TERM')) | $raw %].map( av => [av.authorised_value, av.lib]));
165
    [% END %]
166
    [% IF Koha.Preference('URLLinkText') %]
167
        const url_link_text = "[% Koha.Preference('URLLinkText') | html %]";
168
    [% ELSE %]
169
        const url_link_text = _("Link to resource");
170
    [% END %]
171
    [%# FIXME The X-Base-Total-Count will be the number of items of the biblios %]
172
    [%# In case or SeparateHoldings we may need to display the number of biblios in each tab %]
173
    [%# Do we need separate/new endpoints or do we hack the somewhere client-side? %]
174
    let item_table_url = "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?";
175
    let embed = ["+strings,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,first_hold.desk,item_type"];
176
    [% IF Koha.Preference('LocalCoverImages') %]
177
        embed.push('cover_image_ids');
178
    [% END %]
179
    [% IF Koha.Preference('EnableItemGroups') %]
180
        embed.push('item_group_item.item_group.description');
181
    [% END %]
182
    [% IF biblio.serial %]
183
        embed.push('serialitem.serial');
184
    [% END %]
185
    [% IF Koha.Preference('UseRecalls') %]
186
        embed.push('recall', 'recall+strings', 'recall.patron')
187
    [% END %]
188
    [% IF bundlesEnabled %]
189
        embed.push('in_bundle', 'bundle_host', 'bundle_items_lost+count', 'bundle_items_not_lost+count');
190
    [% END %]
191
    [% IF Koha.Preference('UseCourseReserves') %]
192
        embed.push('course_item.course_reserves.course');
193
    [% END %]
194
195
    // For host records
196
    embed.push('biblio.title');
197
198
    [% IF analyze %]
199
        embed.push('analytics_count');
200
    [% END %]
201
202
    let items_table_settings = {
203
        holdings: [% TablesSettings.GetTableSettings('catalogue', 'detail','holdings_table','json') | $raw %],
204
        otherholdings: [% TablesSettings.GetTableSettings('catalogue', 'detail','otherholdings_table','json')  | $raw %],
205
    };
206
207
    function build_items_table (tab_id, add_filters, dt_options) {
208
209
        let default_filters = {};
210
        [% IF Koha.Preference('SeparateHoldings') %]
211
            [% SET SeparateHoldingsBranch = Koha.Preference('SeparateHoldingsBranch') || 'homebranch' %];
212
            let branch = '[% IF SeparateHoldingsBranch == 'homebranch' %]me.home_library_id[% ELSE %]me.holding_library_id[% END %]';
213
            if ( tab_id == 'holdings' ) {
214
                default_filters[branch] = '[% Branches.GetLoggedInBranchcode() | html %]';
215
            } else {
216
                default_filters[branch] = { '!=': '[% Branches.GetLoggedInBranchcode() | html  %]' };
217
            }
218
        [% END %]
219
220
        [% IF hidden_count %]
221
            default_filters.lost_status = "0";
222
        [% END %]
223
        if ( !items_selection.hasOwnProperty(tab_id) ){
224
            items_selection[tab_id] = [];
225
        }
226
        var items_table = $("#" + tab_id + '_table').kohaTable({
227
            ajax: { url: item_table_url },
228
            order: [[ 0, "asc" ]],
229
            embed,
230
            autoWidth: false,
231
            bKohaColumnsUseNames: true,
232
            columns: [
233
            [% IF (StaffDetailItemSelection) %]
234
            {
235
                data: "me.item_id",
236
                searchable: false,
237
                orderable: false,
238
                render: function (data, type, row, meta) {
239
                    if ( can_edit_items_from[row.holding_library_id] ){
240
                        if ( items_selection[tab_id].includes(row.item_id) ) {
241
                            return '<input type="checkbox" value="%s" name="itemnumber" checked />'.format(row.item_id);
242
                        } else {
243
                            return '<input type="checkbox" value="%s" name="itemnumber" />'.format(row.item_id);
244
                        }
245
                    } else {
246
                        return ''
247
                    }
248
                }
249
            },
250
            [% END %]
251
            [% IF Koha.Preference('LocalCoverImages') %]
252
            {
253
                data: "",
254
                className: "cover",
255
                searchable: false,
256
                orderable: false,
257
                render: function (data, type, row, meta) {
258
                    if ( !row.cover_image_ids.length > 0 ) {
259
                        return '';
260
                    }
261
                    let node = '<div class="bookcoverimg">';
262
                    node += '<div class="cover-slider">';
263
                    row.cover_image_ids.forEach(id => {
264
                        node += '<div class="cover-image local-coverimg">';
265
                        node += '<a href="/cgi-bin/koha/catalogue/image.pl?itemnumber=%s&amp;imagenumber=%s" title="Local cover image">'.format(id, id);
266
                        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);
267
                        node += '</a>';
268
                        node += '</div>';
269
                    });
270
                    node += '</div>';
271
                    node += '</div>';
272
                    return node;
273
                }
274
            },
275
            [% END %]
276
            [% IF ( item_level_itypes ) %]
277
            {
278
                data: "me.itype:biblioitem.itemtype",
279
                className: "itype",
280
                searchable: true,
281
                orderable: true,
282
                render: function (data, type, row, meta) {
283
                    let node = '';
284
                    [% UNLESS noItemTypeImages %]
285
                        let image_location = item_type_image_locations[row.item_type_id];
286
                        let item_type_description = row._strings.item_type_id.str;
287
                        node += image_location
288
                            ? '<img src="%s" alt="%s" title="%s" /> '.format(escape_str(image_location), escape_str(item_type_description), escape_str(item_type_description))
289
                            : '';
290
                    [% END %]
291
                    node += '<span class="itypedesc itypetext">%s</span>'.format(escape_str(item_type_description));
292
                    return node;
293
                }
294
            },
295
            [% END %]
296
            {
297
                data: "me.holding_library_id",
298
                className: "location",
299
                searchable: true,
300
                orderable: true,
301
                render: function (data, type, row, meta) {
302
                    return escape_str(row._strings.holding_library_id.str);
303
                }
304
            },
305
            {
306
                data: "me.home_library_id",
307
                className: "homebranch",
308
                searchable: true,
309
                orderable: true,
310
                render: function (data, type, row, meta) {
311
                    let nodes = '<span class="homebranchdesc">%s</span>'.format(escape_str(row._strings.home_library_id.str));
312
                    nodes += '<span class="shelvingloc">'
313
                    [%# If permanent location is defined, show description or code and             %]
314
                    [%# display current location in parentheses. If not, display current location. %]
315
                    [%# Note that permanent location is a code, and location may be an authval.    %]
316
                    let loc_str = row._strings.location.str;
317
                    if ( row.permanent_location && row.permanent_location != row.location ) {
318
                        let permanent_loc_str = av_loc.get(row.permanent_location);
319
                        nodes += '%s (%s)'.format(escape_str(permanent_loc_str), escape_str(loc_str));
320
                    } else {
321
                        nodes += escape_str(loc_str);
322
                    }
323
                    nodes += '</span>';
324
                    return nodes;
325
                }
326
            },
327
            {
328
                data: "me.collection_code",
329
                searchable: true,
330
                orderable: true,
331
                render: function (data, type, row, meta) {
332
                    return escape_str(row._strings.collection_code.str);
333
                }
334
            },
335
            [% IF Koha.Preference('EnableItemGroups') %]
336
            {
337
                data: "item_group_item.item_group.description",
338
                className: "item_group",
339
                searchable: true,
340
                orderable: true,
341
                render: function (data, type, row, meta) {
342
                    if ( row.item_group_item ) {
343
                        return escape_str(row.item_group_item.item_group.description);
344
                    } else {
345
                        return "";
346
                    }
347
                }
348
            },
349
            [% END %]
350
            {
351
                data: "me.callnumber",
352
                className: "itemcallnumber",
353
                searchable: true,
354
                orderable: true,
355
                render: function (data, type, row, meta) {
356
                    return escape_str(row.callnumber);
357
                }
358
359
            },
360
            {
361
                data: "me.serial_issue_number",
362
                className: "enumchron",
363
                searchable: true,
364
                orderable: true,
365
                render: function (data, type, row, meta) {
366
                    let nodes = "";
367
                    [%# 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? %]
368
                    let serial = row.serialitem ? row.serialitem.serial : null;
369
                    if ( row.serial_issue_number && serial && serial.serialseq ) {
370
                        nodes += '<span class="enum">%s</span>'.format(escape_str(row.serial_issue_number));
371
                        if ( serial.serialseq && row.serial_issue_number != serial.serialseq ) {
372
                            nodes += ' <span class="sep"> -- </span>'
373
                            nodes += ' <span class="serialseq">%s</span>'.format(escape_str(serial.serialseq));
374
                        }
375
                    } else if ( row.serial_issue_number ) {
376
                        nodes += ' <span class="enum">%s</span>'.format(escape_str(row.serial_issue_number));
377
                    } else if ( serial && serial.serialseq ) {
378
                        nodes += '<span class="serialseq">%s</span>'.format(escape_str(serial.serialseq));
379
                    }
380
                    if ( serial && serial.publisheddate ) {
381
                        nodes += ' <span class="pubdate">(%s)</span>'.format($date(serial.publisheddate));
382
                    }
383
                    return nodes;
384
                }
385
            },
386
            {
387
                data: "me.lost_status",
388
                className: "status",
389
                searchable: false, // FIXME We are losing the ability to search on the status
390
                orderable: false,
391
                render: function (data, type, row, meta) {
392
                    let nodes = "";
393
                    if ( row.checkout ) {
394
                        nodes += '<span>';
395
                        if ( row.checkout.onsite_checkout ) {
396
                            let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
397
                            nodes += _("Currently in local use by %s").format(patron_to_html);
398
                        } else {
399
                            nodes += '<span class="datedue">';
400
                            let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
401
                            nodes += _("Checked out to %s").format(patron_to_html);
402
                        }
403
                        nodes += ': ';
404
                        nodes += _("due %s").format($date(row.checkout.due_date, { as_due_date: true }));
405
                        nodes += "</span>"
406
                    } else if ( row.transfer ) {
407
                        if ( row.transfer.datesent ) {
408
                            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)));
409
                        } else {
410
                            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)));
411
                        }
412
                    }
413
414
                    if ( row.lost_status ) {
415
                        let lost_lib = av_lost.get(row.lost_status.toString()) || _("Unavailable (lost or missing");
416
                        nodes += '<span class="lost">%s</span>'.format(escape_str(lost_lib));
417
                    }
418
419
                    if ( row.withdrawn ) {
420
                        let withdrawn_lib = av_withdrawn.get(row.withdrawn.toString()) || _("Withdrawn");
421
                        nodes += '<span class="wdn">%s</span>'.format(escape_str(withdrawn_lib));
422
                    }
423
424
                    if ( row.damaged ) {
425
                        let damaged_lib = av_damaged.get(row.damaged.toString()) || _("Damaged");
426
                        nodes += '<span class="dmg">%s</span>'.format(escape_str(damaged_lib));
427
                    }
428
429
                    if ( row.not_for_loan_status || row.item_type.notforloan ) {
430
                        let not_for_loan_lib = av_not_for_loan.get(row.not_for_loan_status.toString());
431
                        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>';
432
                    }
433
434
                    if ( row.first_hold ) {
435
                        if ( row.first_hold.waiting_date ) {
436
                            if ( row.first_hold.desk ) {
437
                                nodes += '<span class="waitingat">%s</span>'.format(_("Waiting at %s, %s since %s.".format(row.first_hold._strings.pickup_library_id.str, row.first_hold.desk.desk_name, $date(row.first_hold.waiting_date))));
438
                            } else {
439
                                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))));
440
                            }
441
                            [% IF Koha.Preference('canreservefromotherbranches') %]
442
                                if ( row.first_hold.waiting_date || row.first_hold.priority == 1 ) {
443
                                    let patron_to_html = $patron_to_html(row.first_hold.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
444
                                    nodes += ' <span class="heldfor">%s</span>'.format(_("Hold for: %s").format(patron_to_html));
445
                                }
446
                            [% END %]
447
                        } else {
448
                            nodes += ' <span class="holdonitem">%s</span>'.format(_("There is an item level hold on this item (priority = %s).").format(row.first_hold.priority));
449
                        }
450
                    }
451
452
                    [% IF Koha.Preference('UseRecalls') %]
453
                        if ( row.recall ) {
454
                            if ( row.recall.waiting_date ) {
455
                                nodes += '<span>%s</span>'.format(_("Waiting at %s since %s").format(escape_str(row.recall.pickup_library_id.str), $date(row.recall.waiting_date)));
456
                            } else {
457
                                let patron_to_html = $patron_to_html(row.recall.patron);
458
                                nodes += '<span>%s</span>'.format(_("recalled by %s on %s").format(patron_to_html, $date(row.recall.created_date)))
459
                            }
460
                        }
461
                    [% END %]
462
463
                    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 ) ) {
464
                        nodes += ' <span>%s</span>'.format(_("Available"))
465
                    }
466
467
                    if ( row.restricted_status ) {
468
                        nodes += '<span class="restricted">(%s)</span>'.format(escape_str(av_restricted.get(row.restricted_status.toString())));
469
                    }
470
471
                    [% IF bundlesEnabled %]
472
                        if ( row.in_bundle ) {
473
                            nodes += '<span class="bundled">%s</span>'.format(_("In bundle: %s").format($biblio_to_html(row.bundle_host.biblio, { link: true })));
474
                        }
475
                    [% END %]
476
                    return nodes;
477
                }
478
            },
479
            {
480
                data: "me.last_seen_date",
481
                className: "datelastseen",
482
                searchable: true,
483
                orderable: true,
484
                render: function (data, type, row, meta) {
485
                    return $date(row.last_seen_date);
486
                }
487
            },
488
            {
489
                data: "me.checkouts_count",
490
                className: "issues",
491
                searchable: true,
492
                orderable: true,
493
                render: function (data, type, row, meta) {
494
                    return row.checkouts_count || 0;
495
                }
496
            },
497
            {
498
                data: "me.renewals_count",
499
                className: "renewals",
500
                searchable: true,
501
                orderable: true,
502
                render: function (data, type, row, meta) {
503
                    return row.renewals_count || 0;
504
                }
505
            },
506
            {
507
                data: "me.acquisition_date",
508
                className: "dateaccessioned",
509
                searchable: true,
510
                orderable: true,
511
                render: function (data, type, row, meta) {
512
                    return $date(row.acquisition_date);
513
                }
514
            },
515
            {
516
                data: "me.last_checkout_date",
517
                className: "datelastborrowed",
518
                searchable: true,
519
                orderable: true,
520
                render: function (data, type, row, meta) {
521
                    return $date(row.last_checkout_date);
522
                }
523
            },
524
            {
525
                data: "me.external_id",
526
                className: "",
527
                searchable: true,
528
                orderable: true,
529
                render: function (data, type, row, meta) {
530
                    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);
531
                }
532
            },
533
            {
534
                data: "me.uri",
535
                className: "uri",
536
                searchable: true,
537
                orderable: true,
538
                render: function (data, type, row, meta) {
539
                    if ( !row.uri ) return "";
540
541
                    let nodes = '';
542
                    if ( row.uri.split(' \| ').length > 1 ) {
543
                        row.uri.split(' \| ').forEach((uri, i) => {
544
                            nodes += '<a href="%s">%s</a><br/>'.format(escape_str(uri), escape_str(uri));
545
                        });
546
                    } else {
547
                        nodes += '<a href="%s">%s</a><br/>'.format(escape_str(row.uri), escape_str(url_link_text));
548
                    }
549
                    return nodes;
550
                }
551
            },
552
            {
553
                data: "me.copy_number",
554
                className: "copynumber",
555
                searchable: true,
556
                orderable: true,
557
                render: function (data, type, row, meta) {
558
                    return escape_str(row._strings.copy_number ? row._strings.copy_number.str : row.copy_number);
559
                }
560
            },
561
            {
562
                data: "me.inventory_number",
563
                className: "stocknumber",
564
                searchable: true,
565
                orderable: true,
566
                render: function (data, type, row, meta) {
567
                    return escape_str(row.inventory_number);
568
                }
569
            },
570
            {
571
                data: "me.materials_notes",
572
                className: "materials",
573
                searchable: true,
574
                orderable: true,
575
                render: function (data, type, row, meta) {
576
                    return escape_str(row.materials_notes);
577
                }
578
            },
579
            {
580
                data: "me.public_notes",
581
                className: "itemnotes",
582
                searchable: true,
583
                orderable: true,
584
                render: function (data, type, row, meta) {
585
                    return row.public_notes ? escape_str(row.public_notes).replaceAll('\n', '<br />') : '';
586
                }
587
            },
588
            {
589
                data: "me.internal_notes",
590
                className: "nonpublicnote",
591
                searchable: true,
592
                orderable: true,
593
                render: function (data, type, row, meta) {
594
                    return escape_str(row.internal_notes);
595
                }
596
            },
597
            {
598
                data: "biblio.title",
599
                searchable: false,
600
                orderable: true,
601
                render: function (data, type, row, meta) {
602
                    if ( row.biblio_id == [% biblio.biblionumber | html %] ) return "";
603
                    return '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=%s">%s</a>'.format(row.biblio_id, row.biblio.title);
604
                }
605
            },
606
            [% IF analyze %]
607
            {
608
                data: "analytics_count",
609
                searchable: false,
610
                orderable: false,
611
                render: function (data, type, row, meta) {
612
                    if (row.analytics_count == 0) return ""
613
                    return '<a href="/cgi-bin/koha/catalogue/search.pl?idx=hi&amp;q=%s">%s analytics</a>'.format(row.item_id, row.analytics_count);
614
                }
615
            },
616
            {
617
                data: "analytics_count", // create analytics link
618
                searchable: false,
619
                orderable: false,
620
                render: function (data, type, row, meta) {
621
                    return '<a href="/cgi-bin/koha/cataloguing/addbiblio.pl?hostbiblionumber=%s&amp;hostitemnumber=%s">Create analytics</a>'.format(row.biblio_id, row.item_id);
622
                }
623
            },
624
            [% END %]
625
            [% IF Koha.Preference('UseCourseReserves') %]
626
            {
627
                data: "course_item.course_reserves.course.course_name",
628
                searchable: true,
629
                orderable: true,
630
                render: function (data, type, row, meta) {
631
                    let nodes = '';
632
                    if (!row.course_item) return nodes;
633
                    row.course_item.course_reserves.forEach((cr, i) => {
634
                        let c = cr.course;
635
                        if ( c.enabled != 'yes' ) return;
636
                        nodes += '<p>';
637
                        nodes += '<a href="/cgi-bin/koha/course_reserves/course-details.pl?course_id=%s">'.format(c.course_id);
638
                        nodes += escape_str(c.course_name);
639
                        if ( c.section ) {
640
                            nodes += ' ' + escape_str(c.section);
641
                        }
642
                        if ( c.term ) {
643
                            nodes += ' ' + av_courses_term.get(c.term.toString());
644
                        }
645
                        nodes += '</p>';
646
                    });
647
                    return nodes;
648
                }
649
            },
650
            [% END %]
651
            [% IF ( SpineLabelShowPrintOnBibDetails ) %]
652
            {
653
                data: "",
654
                searchable: false,
655
                orderable: false,
656
                render: function (data, type, row, meta) {
657
                    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));
658
                }
659
            },
660
            [% END %]
661
            [% IF CAN_user_editcatalogue_edit_items %]
662
            {
663
                data: function( row, type, val, meta ) {
664
                    let nodes = '';
665
                    if ( can_edit_items_from[row.holding_library_id] ){
666
                        [% IF Koha.Preference('LocalCoverImages') OR Koha.Preference('OPACLocalCoverImages') %]
667
                            nodes += '<div class="btn-group">';
668
                            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);
669
                            nodes += ' <ul class="dropdown-menu pull-right">';
670
                            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);
671
                            nodes += ' </ul>';
672
                            nodes += '</div>';
673
                        [% ELSE %]
674
                            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);
675
                        [% END %]
676
                    }
677
                    [% IF bundlesEnabled %]
678
                        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.bundle_items_not_lost_count), escape_str(row.bundle_items_lost_count));
679
                    [% END %]
680
681
                    return nodes;
682
                },
683
                className: "actions",
684
                searchable: false,
685
                orderable: false
686
            }
687
            [% END %]
688
            ],
689
            initComplete: function( settings, json ){
690
                let table = settings.oInstance.api();
691
                table.columns().every(function(i){
692
                    let is_empty = true;
693
                    let nodes = this.nodes();
694
                    nodes.each((td, ii) => {
695
                        if ( $(td).html() !== '' ) {
696
                            is_empty = false;
697
                            return;
698
                        }
699
                    });
700
                    if ( is_empty ) {
701
                        table.columns(i).visible(false);
702
                    }
703
                });
704
                itemSelectionBuildActionLinks(tab_id);
705
            },
706
            [% IF StaffDetailItemSelection %]
707
            drawCallback: function(settings){
708
                var api = new $.fn.dataTable.Api(settings)
709
                $.each(
710
                    $(this).find("tbody tr td:first-child"),
711
                    function (index, e) {
712
                        let tr = $(this).parent()
713
                        let row = api.row(tr).data()
714
                        if (!row) return // Happen if the table is empty
715
                        $(this).find("input[name='itemnumber'][type='checkbox']").on("change", function(){
716
                            let itemnumber = parseInt($(this).val());
717
                            if( $(this).prop("checked") ){
718
                                items_selection[tab_id].push(itemnumber);
719
                            } else {
720
                                items_selection[tab_id] = items_selection[tab_id].filter( id => id != itemnumber );
721
                            }
722
                            itemSelectionBuildActionLinks(tab_id);
723
                        });
724
                    }
725
                );
726
            },
727
            [% END %]
728
            ...dt_options,
729
        },
730
        items_table_settings[tab_id],
731
        add_filters,
732
        default_filters,
733
        );
734
735
        return items_table;
736
    }
737
</script>
738
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt (-726 / +5 lines)
Lines 11-16 Link Here
11
[% USE Price %]
11
[% USE Price %]
12
[% USE TablesSettings %]
12
[% USE TablesSettings %]
13
[% PROCESS 'i18n.inc' %]
13
[% PROCESS 'i18n.inc' %]
14
[% PROCESS 'html_helpers/tables/items/catalogue_detail.inc' %]
14
[% SET CoverImagePlugins = KohaPlugins.get_plugins_intranet_cover_images %]
15
[% SET CoverImagePlugins = KohaPlugins.get_plugins_intranet_cover_images %]
15
16
16
[% IF Koha.Preference('AmazonAssocTag') %]
17
[% IF Koha.Preference('AmazonAssocTag') %]
Lines 313-383 Link Here
313
</ul>
314
</ul>
314
315
315
<div class="tab-content">
316
<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
            <th id="[% tab | html %]_hostrecord" data-colname="[% tab | html %]_hostrecord">Host records</th>
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') %]
317
[% IF Koha.Preference('EnableItemGroups') %]
382
    <div role="tabpanel" class="tab-pane" id="item_groups">
318
    <div role="tabpanel" class="tab-pane" id="item_groups">
383
        [% IF CAN_user_editcatalogue_manage_item_groups %]
319
        [% IF CAN_user_editcatalogue_manage_item_groups %]
Lines 1331-1415 Link Here
1331
            $('#images').html(no_images_msg);
1267
            $('#images').html(no_images_msg);
1332
        }
1268
        }
1333
1269
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
1270
1414
        $(document).ready(function() {
1271
        $(document).ready(function() {
1415
            // Pick details tab to display by default
1272
            // Pick details tab to display by default
Lines 2154-2743 Link Here
2154
2011
2155
            });
2012
            });
2156
        [% END %]
2013
        [% END %]
2157
        const can_edit_items_from = [% To.json(can_edit_items_from || {}) | $raw %];
2158
        const item_type_image_locations = [% To.json(item_type_image_locations) | $raw %];
2159
        const av_loc = new Map([% To.json(AuthorisedValues.Get('LOC')) | $raw %].map( av => [av.authorised_value, av.lib]));
2160
        const av_lost = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.itemlost' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2161
        const av_withdrawn = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.withdrawn' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2162
        const av_damaged = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.damaged' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2163
        const av_not_for_loan= new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.notforloan' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2164
        const av_restricted = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.restricted' })) | $raw %].map( av => [av.authorised_value, av.lib]));
2165
        [% IF Koha.Preference('UseCourseReserves') %]
2166
            const av_courses_term = new Map([% To.json(AuthorisedValues.Get('TERM')) | $raw %].map( av => [av.authorised_value, av.lib]));
2167
        [% END %]
2168
        [% IF Koha.Preference('URLLinkText') %]
2169
            const url_link_text = "[% Koha.Preference('URLLinkText') | html %]";
2170
        [% ELSE %]
2171
            const url_link_text = _("Link to resource");
2172
        [% END %]
2173
        [%# FIXME The X-Base-Total-Count will be the number of items of the biblios %]
2174
        [%# In case or SeparateHoldings we may need to display the number of biblios in each tab %]
2175
        [%# Do we need separate/new endpoints or do we hack the somewhere client-side? %]
2176
        let item_table_url = "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?";
2177
        let embed = ["+strings,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,first_hold.desk,item_type"];
2178
        [% IF Koha.Preference('LocalCoverImages') %]
2179
            embed.push('cover_image_ids');
2180
        [% END %]
2181
        [% IF Koha.Preference('EnableItemGroups') %]
2182
            embed.push('item_group_item.item_group.description');
2183
        [% END %]
2184
        [% IF biblio.serial %]
2185
            embed.push('serialitem.serial');
2186
        [% END %]
2187
        [% IF Koha.Preference('UseRecalls') %]
2188
            embed.push('recall', 'recall+strings', 'recall.patron')
2189
        [% END %]
2190
        [% IF bundlesEnabled %]
2191
            embed.push('in_bundle', 'bundle_host', 'bundle_items_lost+count', 'bundle_items_not_lost+count');
2192
        [% END %]
2193
        [% IF Koha.Preference('UseCourseReserves') %]
2194
            embed.push('course_item.course_reserves.course');
2195
        [% END %]
2196
2197
        // For host records
2198
        embed.push('biblio.title');
2199
2200
        [% IF analyze %]
2201
            embed.push('analytics_count');
2202
        [% END %]
2203
2204
        let items_table_settings = {
2205
            holdings: [% TablesSettings.GetTableSettings('catalogue', 'detail','holdings_table','json') | $raw %],
2206
            otherholdings: [% TablesSettings.GetTableSettings('catalogue', 'detail','otherholdings_table','json')  | $raw %],
2207
        };
2208
2209
        function build_items_table (tab_id, add_filters, dt_options) {
2210
2211
            let default_filters = {};
2212
            [% IF Koha.Preference('SeparateHoldings') %]
2213
                [% SET SeparateHoldingsBranch = Koha.Preference('SeparateHoldingsBranch') || 'homebranch' %];
2214
                let branch = '[% IF SeparateHoldingsBranch == 'homebranch' %]me.home_library_id[% ELSE %]me.holding_library_id[% END %]';
2215
                if ( tab_id == 'holdings' ) {
2216
                    default_filters[branch] = '[% Branches.GetLoggedInBranchcode() | html %]';
2217
                } else {
2218
                    default_filters[branch] = { '!=': '[% Branches.GetLoggedInBranchcode() | html  %]' };
2219
                }
2220
            [% END %]
2221
2222
            [% IF hidden_count %]
2223
                default_filters.lost_status = "0";
2224
            [% END %]
2225
            if ( !items_selection.hasOwnProperty(tab_id) ){
2226
                items_selection[tab_id] = [];
2227
            }
2228
            var items_table = $("#" + tab_id + '_table').kohaTable({
2229
                ajax: { url: item_table_url },
2230
                order: [[ 0, "asc" ]],
2231
                embed,
2232
                autoWidth: false,
2233
                bKohaColumnsUseNames: true,
2234
                columns: [
2235
                [% IF (StaffDetailItemSelection) %]
2236
                {
2237
                    data: "me.item_id",
2238
                    searchable: false,
2239
                    orderable: false,
2240
                    render: function (data, type, row, meta) {
2241
                        if ( can_edit_items_from[row.holding_library_id] ){
2242
                            if ( items_selection[tab_id].includes(row.item_id) ) {
2243
                                return '<input type="checkbox" value="%s" name="itemnumber" checked />'.format(row.item_id);
2244
                            } else {
2245
                                return '<input type="checkbox" value="%s" name="itemnumber" />'.format(row.item_id);
2246
                            }
2247
                        } else {
2248
                            return ''
2249
                        }
2250
                    }
2251
                },
2252
                [% END %]
2253
                [% IF Koha.Preference('LocalCoverImages') %]
2254
                {
2255
                    data: "",
2256
                    className: "cover",
2257
                    searchable: false,
2258
                    orderable: false,
2259
                    render: function (data, type, row, meta) {
2260
                        if ( !row.cover_image_ids.length > 0 ) {
2261
                            return '';
2262
                        }
2263
                        let node = '<div class="bookcoverimg">';
2264
                        node += '<div class="cover-slider">';
2265
                        row.cover_image_ids.forEach(id => {
2266
                            node += '<div class="cover-image local-coverimg">';
2267
                            node += '<a href="/cgi-bin/koha/catalogue/image.pl?itemnumber=%s&amp;imagenumber=%s" title="Local cover image">'.format(id, id);
2268
                            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);
2269
                            node += '</a>';
2270
                            node += '</div>';
2271
                        });
2272
                        node += '</div>';
2273
                        node += '</div>';
2274
                        return node;
2275
                    }
2276
                },
2277
                [% END %]
2278
                [% IF ( item_level_itypes ) %]
2279
                {
2280
                    data: "me.itype:biblioitem.itemtype",
2281
                    className: "itype",
2282
                    searchable: true,
2283
                    orderable: true,
2284
                    render: function (data, type, row, meta) {
2285
                        let node = '';
2286
                        [% UNLESS noItemTypeImages %]
2287
                            let image_location = item_type_image_locations[row.item_type_id];
2288
                            let item_type_description = row._strings.item_type_id.str;
2289
                            node += image_location
2290
                                ? '<img src="%s" alt="%s" title="%s" /> '.format(escape_str(image_location), escape_str(item_type_description), escape_str(item_type_description))
2291
                                : '';
2292
                        [% END %]
2293
                        node += '<span class="itypedesc itypetext">%s</span>'.format(escape_str(item_type_description));
2294
                        return node;
2295
                    }
2296
                },
2297
                [% END %]
2298
                {
2299
                    data: "me.holding_library_id",
2300
                    className: "location",
2301
                    searchable: true,
2302
                    orderable: true,
2303
                    render: function (data, type, row, meta) {
2304
                        return escape_str(row._strings.holding_library_id.str);
2305
                    }
2306
                },
2307
                {
2308
                    data: "me.home_library_id",
2309
                    className: "homebranch",
2310
                    searchable: true,
2311
                    orderable: true,
2312
                    render: function (data, type, row, meta) {
2313
                        let nodes = '<span class="homebranchdesc">%s</span>'.format(escape_str(row._strings.home_library_id.str));
2314
                        nodes += '<span class="shelvingloc">'
2315
                        [%# If permanent location is defined, show description or code and             %]
2316
                        [%# display current location in parentheses. If not, display current location. %]
2317
                        [%# Note that permanent location is a code, and location may be an authval.    %]
2318
                        let loc_str = row._strings.location.str;
2319
                        if ( row.permanent_location && row.permanent_location != row.location ) {
2320
                            let permanent_loc_str = av_loc[row.permanent_location];
2321
                            nodes += '%s (%s)'.format(escape_str(permanent_loc_str), escape_str(loc_str));
2322
                        } else {
2323
                            nodes += escape_str(loc_str);
2324
                        }
2325
                        nodes += '</span>';
2326
                        return nodes;
2327
                    }
2328
                },
2329
                {
2330
                    data: "me.collection_code",
2331
                    searchable: true,
2332
                    orderable: true,
2333
                    render: function (data, type, row, meta) {
2334
                        return escape_str(row._strings.collection_code.str);
2335
                    }
2336
                },
2337
                [% IF Koha.Preference('EnableItemGroups') %]
2338
                {
2339
                    data: "item_group_item.item_group.description",
2340
                    className: "item_group",
2341
                    searchable: true,
2342
                    orderable: true,
2343
                    render: function (data, type, row, meta) {
2344
                        if ( row.item_group_item ) {
2345
                            return escape_str(row.item_group_item.item_group.description);
2346
                        } else {
2347
                            return "";
2348
                        }
2349
                    }
2350
                },
2351
                [% END %]
2352
                {
2353
                    data: "me.callnumber",
2354
                    className: "itemcallnumber",
2355
                    searchable: true,
2356
                    orderable: true,
2357
                    render: function (data, type, row, meta) {
2358
                        return escape_str(row.callnumber);
2359
                    }
2360
2014
2361
                },
2015
    </script>
2362
                {
2363
                    data: "me.serial_issue_number",
2364
                    className: "enumchron",
2365
                    searchable: true,
2366
                    orderable: true,
2367
                    render: function (data, type, row, meta) {
2368
                        let nodes = "";
2369
                        [%# 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? %]
2370
                        let serial = row.serialitem ? row.serialitem.serial : null;
2371
                        if ( row.serial_issue_number && serial && serial.serialseq ) {
2372
                            nodes += '<span class="enum">%s</span>'.format(escape_str(row.serial_issue_number));
2373
                            if ( serial.serialseq && row.serial_issue_number != serial.serialseq ) {
2374
                                nodes += ' <span class="sep"> -- </span>'
2375
                                nodes += ' <span class="serialseq">%s</span>'.format(escape_str(serial.serialseq));
2376
                            }
2377
                        } else if ( row.serial_issue_number ) {
2378
                            nodes += ' <span class="enum">%s</span>'.format(escape_str(row.serial_issue_number));
2379
                        } else if ( serial && serial.serialseq ) {
2380
                            nodes += '<span class="serialseq">%s</span>'.format(escape_str(serial.serialseq));
2381
                        }
2382
                        if ( serial && serial.publisheddate ) {
2383
                            nodes += ' <span class="pubdate">(%s)</span>'.format($date(serial.publisheddate));
2384
                        }
2385
                        return nodes;
2386
                    }
2387
                },
2388
                {
2389
                    data: "me.lost_status",
2390
                    className: "status",
2391
                    searchable: false, // FIXME We are losing the ability to search on the status
2392
                    orderable: false,
2393
                    render: function (data, type, row, meta) {
2394
                        let nodes = "";
2395
                        if ( row.checkout ) {
2396
                            nodes += '<span>';
2397
                            if ( row.checkout.onsite_checkout ) {
2398
                                let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
2399
                                nodes += _("Currently in local use by %s").format(patron_to_html);
2400
                            } else {
2401
                                nodes += '<span class="datedue">';
2402
                                let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
2403
                                nodes += _("Checked out to %s").format(patron_to_html);
2404
                            }
2405
                            nodes += ': ';
2406
                            nodes += _("due %s").format($date(row.checkout.due_date, { as_due_date: true }));
2407
                            nodes += "</span>"
2408
                        } else if ( row.transfer ) {
2409
                            if ( row.transfer.datesent ) {
2410
                                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)));
2411
                            } else {
2412
                                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)));
2413
                            }
2414
                        }
2415
2416
                        if ( row.lost_status ) {
2417
                            let lost_lib = av_lost.get(row.lost_status.toString()) || _("Unavailable (lost or missing");
2418
                            nodes += '<span class="lost">%s</span>'.format(escape_str(lost_lib));
2419
                        }
2420
2421
                        if ( row.withdrawn ) {
2422
                            let withdrawn_lib = av_withdrawn.get(row.withdrawn.toString()) || _("Withdrawn");
2423
                            nodes += '<span class="wdn">%s</span>'.format(escape_str(withdrawn_lib));
2424
                        }
2425
2426
                        if ( row.damaged ) {
2427
                            let damaged_lib = av_damaged.get(row.damaged.toString()) || _("Damaged");
2428
                            nodes += '<span class="dmg">%s</span>'.format(escape_str(damaged_lib));
2429
                        }
2430
2431
                        if ( row.not_for_loan_status || row.item_type.notforloan ) {
2432
                            let not_for_loan_lib = av_not_for_loan.get(row.not_for_loan_status.toString());
2433
                            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>';
2434
                        }
2435
2436
                        if ( row.first_hold ) {
2437
                            if ( row.first_hold.waiting_date ) {
2438
                                if ( row.first_hold.desk ) {
2439
                                    nodes += '<span class="waitingat">%s</span>'.format(_("Waiting at %s, %s since %s.".format(row.first_hold._strings.pickup_library_id.str, row.first_hold.desk.desk_name, $date(row.first_hold.waiting_date))));
2440
                                } else {
2441
                                    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))));
2442
                                }
2443
                                [% IF Koha.Preference('canreservefromotherbranches') %]
2444
                                    if ( row.first_hold.waiting_date || row.first_hold.priority == 1 ) {
2445
                                        let patron_to_html = $patron_to_html(row.first_hold.patron); [%# FIXME What about hide_patron_infos_if_needed?? %]
2446
                                        nodes += ' <span class="heldfor">%s</span>'.format(_("Hold for: %s").format(patron_to_html));
2447
                                    }
2448
                                [% END %]
2449
                            } else {
2450
                                nodes += '<span class="holdonitem">%s</span>'.format(_("There is an item level hold on this item (priority = %s).").format(row.first_hold.priority));
2451
                            }
2452
                        }
2453
2454
                        [% IF Koha.Preference('UseRecalls') %]
2455
                            if ( row.recall ) {
2456
                                if ( row.recall.waiting_date ) {
2457
                                    nodes += '<span>%s</span>'.format(_("Waiting at %s since %s").format(escape_str(row.recall.pickup_library_id.str), $date(row.recall.waiting_date)));
2458
                                } else {
2459
                                    let patron_to_html = $patron_to_html(row.recall.patron);
2460
                                    nodes += '<span>%s</span>'.format(_("recalled by %s on %s").format(patron_to_html, $date(row.recall.created_date)))
2461
                                }
2462
                            }
2463
                        [% END %]
2464
2465
                        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 ) ) {
2466
                            nodes += ' <span>%s</span>'.format(_("Available"))
2467
                        }
2468
2469
                        if ( row.restricted_status ) {
2470
                            nodes += '<span class="restricted">(%s)</span>'.format(escape_str(av_restricted.get(row.restricted_status.toString())));
2471
                        }
2472
2473
                        [% IF bundlesEnabled %]
2474
                            if ( row.in_bundle ) {
2475
                                nodes += '<span class="bundled">%s</span>'.format(_("In bundle: %s").format($biblio_to_html(row.bundle_host.biblio, { link: true })));
2476
                            }
2477
                        [% END %]
2478
                        return nodes;
2479
                    }
2480
                },
2481
                {
2482
                    data: "me.last_seen_date",
2483
                    className: "datelastseen",
2484
                    searchable: true,
2485
                    orderable: true,
2486
                    render: function (data, type, row, meta) {
2487
                        return $date(row.last_seen_date);
2488
                    }
2489
                },
2490
                {
2491
                    data: "me.checkouts_count",
2492
                    className: "issues",
2493
                    searchable: true,
2494
                    orderable: true,
2495
                    render: function (data, type, row, meta) {
2496
                        return row.checkouts_count || 0;
2497
                    }
2498
                },
2499
                {
2500
                    data: "me.renewals_count",
2501
                    className: "renewals",
2502
                    searchable: true,
2503
                    orderable: true,
2504
                    render: function (data, type, row, meta) {
2505
                        return row.renewals_count || 0;
2506
                    }
2507
                },
2508
                {
2509
                    data: "me.acquisition_date",
2510
                    className: "dateaccessioned",
2511
                    searchable: true,
2512
                    orderable: true,
2513
                    render: function (data, type, row, meta) {
2514
                        return $date(row.acquisition_date);
2515
                    }
2516
                },
2517
                {
2518
                    data: "me.last_checkout_date",
2519
                    className: "datelastborrowed",
2520
                    searchable: true,
2521
                    orderable: true,
2522
                    render: function (data, type, row, meta) {
2523
                        return $date(row.last_checkout_date);
2524
                    }
2525
                },
2526
                {
2527
                    data: "me.external_id",
2528
                    className: "",
2529
                    searchable: true,
2530
                    orderable: true,
2531
                    render: function (data, type, row, meta) {
2532
                        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);
2533
                    }
2534
                },
2535
                {
2536
                    data: "me.uri",
2537
                    className: "uri",
2538
                    searchable: true,
2539
                    orderable: true,
2540
                    render: function (data, type, row, meta) {
2541
                        if ( !row.uri ) return "";
2542
2543
                        let nodes = '';
2544
                        if ( row.uri.split(' \| ').length > 1 ) {
2545
                            row.uri.split(' \| ').forEach((uri, i) => {
2546
                                nodes += '<a href="%s">%s</a><br/>'.format(escape_str(uri), escape_str(uri));
2547
                            });
2548
                        } else {
2549
                            nodes += '<a href="%s">%s</a><br/>'.format(escape_str(row.uri), escape_str(url_link_text));
2550
                        }
2551
                        return nodes;
2552
                    }
2553
                },
2554
                {
2555
                    data: "me.copy_number",
2556
                    className: "copynumber",
2557
                    searchable: true,
2558
                    orderable: true,
2559
                    render: function (data, type, row, meta) {
2560
                        return escape_str(row._strings.copy_number ? row._strings.copy_number.str : row.copy_number);
2561
                    }
2562
                },
2563
                {
2564
                    data: "me.inventory_number",
2565
                    className: "stocknumber",
2566
                    searchable: true,
2567
                    orderable: true,
2568
                    render: function (data, type, row, meta) {
2569
                        return escape_str(row.inventory_number);
2570
                    }
2571
                },
2572
                {
2573
                    data: "me.materials_notes",
2574
                    className: "materials",
2575
                    searchable: true,
2576
                    orderable: true,
2577
                    render: function (data, type, row, meta) {
2578
                        return escape_str(row.materials_notes);
2579
                    }
2580
                },
2581
                {
2582
                    data: "me.public_notes",
2583
                    className: "itemnotes",
2584
                    searchable: true,
2585
                    orderable: true,
2586
                    render: function (data, type, row, meta) {
2587
                        return row.public_notes ? escape_str(row.public_notes).replaceAll('\n', '<br />') : '';
2588
                    }
2589
                },
2590
                {
2591
                    data: "me.internal_notes",
2592
                    className: "nonpublicnote",
2593
                    searchable: true,
2594
                    orderable: true,
2595
                    render: function (data, type, row, meta) {
2596
                        return escape_str(row.internal_notes);
2597
                    }
2598
                },
2599
                {
2600
                    data: "biblio.title",
2601
                    searchable: false,
2602
                    orderable: true,
2603
                    render: function (data, type, row, meta) {
2604
                        if ( row.biblio_id == [% biblio.biblionumber | html %] ) return "";
2605
                        return '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=%s">%s</a>'.format(row.biblio_id, row.biblio.title);
2606
                    }
2607
                },
2608
                [% IF analyze %]
2609
                {
2610
                    data: "analytics_count",
2611
                    searchable: false,
2612
                    orderable: false,
2613
                    render: function (data, type, row, meta) {
2614
                        if (row.analytics_count == 0) return ""
2615
                        return '<a href="/cgi-bin/koha/catalogue/search.pl?idx=hi&amp;q=%s">%s analytics</a>'.format(row.item_id, row.analytics_count);
2616
                    }
2617
                },
2618
                {
2619
                    data: "analytics_count", // create analytics link
2620
                    searchable: false,
2621
                    orderable: false,
2622
                    render: function (data, type, row, meta) {
2623
                        return '<a href="/cgi-bin/koha/cataloguing/addbiblio.pl?hostbiblionumber=%s&amp;hostitemnumber=%s">Create analytics</a>'.format(row.biblio_id, row.item_id);
2624
                    }
2625
                },
2626
                [% END %]
2627
                [% IF Koha.Preference('UseCourseReserves') %]
2628
                {
2629
                    data: "course_item.course_reserves.course.course_name",
2630
                    searchable: true,
2631
                    orderable: true,
2632
                    render: function (data, type, row, meta) {
2633
                        let nodes = '';
2634
                        if (!row.course_item) return nodes;
2635
                        row.course_item.course_reserves.forEach((cr, i) => {
2636
                            let c = cr.course;
2637
                            if ( c.enabled != 'yes' ) return;
2638
                            nodes += '<p>';
2639
                            nodes += '<a href="/cgi-bin/koha/course_reserves/course-details.pl?course_id=%s">'.format(c.course_id);
2640
                            nodes += escape_str(c.course_name);
2641
                            if ( c.section ) {
2642
                                nodes += ' ' + escape_str(c.section);
2643
                            }
2644
                            if ( c.term ) {
2645
                                nodes += ' ' + av_courses_term.get(c.term.toString());
2646
                            }
2647
                            nodes += '</p>';
2648
                        });
2649
                        return nodes;
2650
                    }
2651
                },
2652
                [% END %]
2653
                [% IF ( SpineLabelShowPrintOnBibDetails ) %]
2654
                {
2655
                    data: "",
2656
                    searchable: false,
2657
                    orderable: false,
2658
                    render: function (data, type, row, meta) {
2659
                        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));
2660
                    }
2661
                },
2662
                [% END %]
2663
                [% IF CAN_user_editcatalogue_edit_items %]
2664
                {
2665
                    data: function( row, type, val, meta ) {
2666
                        let nodes = '';
2667
                        if ( can_edit_items_from[row.holding_library_id] ){
2668
                            [% IF Koha.Preference('LocalCoverImages') OR Koha.Preference('OPACLocalCoverImages') %]
2669
                                nodes += '<div class="btn-group">';
2670
                                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);
2671
                                nodes += ' <ul class="dropdown-menu pull-right">';
2672
                                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);
2673
                                nodes += ' </ul>';
2674
                                nodes += '</div>';
2675
                            [% ELSE %]
2676
                                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);
2677
                            [% END %]
2678
                        }
2679
                        [% IF bundlesEnabled %]
2680
                            // FIXME How do we handle that correctly?
2681
                            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.bundle_items_not_lost_count), escape_str(row.bundle_items_lost_count));
2682
                        [% END %]
2683
2016
2684
                        return nodes;
2017
    [%# The following PROCESS needs: %]
2685
                    },
2018
    [%# can_edit_items_from item_type_image_locations %]
2686
                    className: "actions",
2019
    [% PROCESS build_items_table_js biblio => biblio %]
2687
                    searchable: false,
2688
                    orderable: false
2689
                }
2690
                [% END %]
2691
                ],
2692
                initComplete: function( settings, json ){
2693
                    let table = settings.oInstance.api();
2694
                    table.columns().every(function(i){
2695
                        let is_empty = true;
2696
                        let nodes = this.nodes();
2697
                        nodes.each((td, ii) => {
2698
                            if ( $(td).html() !== '' ) {
2699
                                is_empty = false;
2700
                                return;
2701
                            }
2702
                        });
2703
                        if ( is_empty ) {
2704
                            table.columns(i).visible(false);
2705
                        }
2706
                    });
2707
                    itemSelectionBuildActionLinks(tab_id);
2708
                },
2709
                [% IF StaffDetailItemSelection %]
2710
                drawCallback: function(settings){
2711
                    var api = new $.fn.dataTable.Api(settings)
2712
                    $.each(
2713
                        $(this).find("tbody tr td:first-child"),
2714
                        function (index, e) {
2715
                            let tr = $(this).parent()
2716
                            let row = api.row(tr).data()
2717
                            if (!row) return // Happen if the table is empty
2718
                            $(this).find("input[name='itemnumber'][type='checkbox']").on("change", function(){
2719
                                let itemnumber = parseInt($(this).val());
2720
                                if( $(this).prop("checked") ){
2721
                                    items_selection[tab_id].push(itemnumber);
2722
                                } else {
2723
                                    items_selection[tab_id] = items_selection[tab_id].filter( id => id != itemnumber );
2724
                                }
2725
                                itemSelectionBuildActionLinks(tab_id);
2726
                            });
2727
                        }
2728
                    );
2729
                },
2730
                [% END %]
2731
                ...dt_options,
2732
            },
2733
            items_table_settings[tab_id],
2734
            add_filters,
2735
            default_filters,
2736
            );
2737
2020
2738
            return items_table;
2739
        }
2740
    </script>
2741
    [% CoverImagePlugins | $raw %]
2021
    [% CoverImagePlugins | $raw %]
2742
[% END %]
2022
[% END %]
2743
[% INCLUDE 'intranet-bottom.inc' %]
2023
[% INCLUDE 'intranet-bottom.inc' %]
2744
- 

Return to bug 33568