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

(-)a/Koha/Illrequest/Availability.pm (+120 lines)
Line 0 Link Here
1
package Koha::Illrequest::Availability;
2
3
# Copyright 2019 PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use JSON;
23
use MIME::Base64 qw( encode_base64 );
24
use URI::Escape qw ( uri_escape );
25
26
use Koha::Plugins;
27
28
=head1 NAME
29
30
Koha::Illrequest::Availability - Koha ILL Availability Searching
31
32
=head1 SYNOPSIS
33
34
Object-oriented class that provides availability searching via
35
availability plugins
36
37
=head1 DESCRIPTION
38
39
This class provides the ability to identify and fetch API services
40
that can be used to search for item availability
41
42
=head1 API
43
44
=head2 Class Methods
45
46
=head3 new
47
48
    my $availability = Koha::Illrequest::Logger->new($metadata);
49
50
Create a new Koha::Illrequest::Availability object.
51
We also store the metadata to be used for searching
52
53
=cut
54
55
sub new {
56
    my ( $class, $metadata ) = @_;
57
    my $self  = {};
58
59
    $self->{metadata} = $metadata;
60
61
    bless $self, $class;
62
63
    return $self;
64
}
65
66
=head3 get_services
67
68
    my $services = Koha::Illrequest::Availability->get_services();
69
70
Given our metadata, iterate plugins with the right method and
71
check if they can service our request and, if so, return an arrayref
72
of services
73
74
=cut
75
76
sub get_services {
77
    my ( $self, $metadata ) = @_;
78
79
    my $params = {
80
        method => 'ill_availability_services'
81
    };
82
83
    if ($metadata) {
84
        $params->{metadata} = $metadata;
85
    }
86
87
    my @candidates = Koha::Plugins->new()->GetPlugins($params);
88
    my @services = ();
89
    foreach my $plugin(@candidates) {
90
        my $valid_service = $plugin->ill_availability_services(
91
            $self->{metadata}
92
        );
93
        push @services, $valid_service if $valid_service;
94
    }
95
96
    return \@services;
97
}
98
99
=head3 prep_metadata
100
101
    my $prepared = Koha::Illrequest::Availability->prep_metadata($metadata);
102
103
Given our metadata, return a string representing that metadata that can be
104
passed in a URL (encoded in JSON then Base64 encoded)
105
106
=cut
107
108
sub prep_metadata {
109
    my ( $self, $metadata ) = @_;
110
111
    return uri_escape(encode_base64(encode_json($metadata)));
112
}
113
114
=head1 AUTHOR
115
116
Andrew Isherwood <andrew.isherwood@ptfs-europe.com>
117
118
=cut
119
120
1;
(-)a/ill/ill-requests.pl (-6 / +71 lines)
Lines 26-36 use C4::Output; Link Here
26
use Koha::AuthorisedValues;
26
use Koha::AuthorisedValues;
27
use Koha::Illcomment;
27
use Koha::Illcomment;
28
use Koha::Illrequests;
28
use Koha::Illrequests;
29
use Koha::Illrequest::Availability;
29
use Koha::Libraries;
30
use Koha::Libraries;
30
use Koha::Token;
31
use Koha::Token;
31
32
32
use Try::Tiny;
33
use Try::Tiny;
33
use URI::Escape;
34
use URI::Escape;
35
use JSON;
34
36
35
our $cgi = CGI->new;
37
our $cgi = CGI->new;
36
my $illRequests = Koha::Illrequests->new;
38
my $illRequests = Koha::Illrequests->new;
Lines 81-92 if ( $backends_available ) { Link Here
81
    } elsif ( $op eq 'create' ) {
83
    } elsif ( $op eq 'create' ) {
82
        # We're in the process of creating a request
84
        # We're in the process of creating a request
83
        my $request = Koha::Illrequest->new->load_backend( $params->{backend} );
85
        my $request = Koha::Illrequest->new->load_backend( $params->{backend} );
84
        my $backend_result = $request->backend_create($params);
86
        # Does this backend enable us to insert an availability stage and should
85
        $template->param(
87
        # we? If not, proceed as normal.
86
            whole   => $backend_result,
88
        if (
87
            request => $request
89
            C4::Context->preference("ILLCheckAvailability") &&
88
        );
90
            $request->_backend_capability(
89
        handle_commit_maybe($backend_result, $request);
91
                'should_display_availability',
92
                $params
93
            ) &&
94
            # If the user has elected to continue with the request despite
95
            # having viewed availability info, this flag will be set
96
            !$params->{checked_availability}
97
        ) {
98
            # Establish which of the installed availability providers
99
            # can service our metadata
100
            my $availability = Koha::Illrequest::Availability->new($params);
101
            my $services = $availability->get_services();
102
            if (scalar @{$services} > 0) {
103
                # Modify our method so we use the correct part of the
104
                # template
105
                $op = 'availability';
106
                $params->{method} = 'availability';
107
                delete $params->{stage};
108
                # Prepare the metadata we're sending them
109
                my $metadata = $availability->prep_metadata($params);
110
                $template->param(
111
                    whole         => $params,
112
                    metadata      => $metadata,
113
                    services_json => scalar encode_json($services),
114
                    services      => $services
115
                );
116
            } else {
117
                # No services can process this metadata, so continue as normal
118
                my $backend_result = $request->backend_create($params);
119
                $template->param(
120
                    whole   => $backend_result,
121
                    request => $request
122
                );
123
                handle_commit_maybe($backend_result, $request);
124
            }
125
        } else {
126
            my $backend_result = $request->backend_create($params);
127
            $template->param(
128
                whole   => $backend_result,
129
                request => $request
130
            );
131
            handle_commit_maybe($backend_result, $request);
132
        }
90
133
91
    } elsif ( $op eq 'migrate' ) {
134
    } elsif ( $op eq 'migrate' ) {
92
        # We're in the process of migrating a request
135
        # We're in the process of migrating a request
Lines 239-248 if ( $backends_available ) { Link Here
239
            $request = Koha::Illrequests->find($params->{illrequest_id});
282
            $request = Koha::Illrequests->find($params->{illrequest_id});
240
            $params->{current_branchcode} = C4::Context->mybranch;
283
            $params->{current_branchcode} = C4::Context->mybranch;
241
            $backend_result = $request->generic_confirm($params);
284
            $backend_result = $request->generic_confirm($params);
285
242
            $template->param(
286
            $template->param(
243
                whole => $backend_result,
287
                whole => $backend_result,
244
                request => $request,
288
                request => $request,
245
            );
289
            );
290
291
            # Prepare availability searching, if required
292
            # Get the definition for the z39.50 plugin
293
            my $availability = Koha::Illrequest::Availability->new($request->metadata);
294
            my $services = $availability->get_services({
295
                name => 'ILL availability - z39.50'
296
            });
297
            # Only pass availability searching stuff to the template if
298
            # appropriate
299
            if (
300
                C4::Context->preference('ILLCheckAvailability') &&
301
                scalar @{$services} > 0
302
            ) {
303
                my $metadata = $availability->prep_metadata($request->metadata);
304
                $template->param( metadata => $metadata );
305
                $template->param(
306
                    services_json => scalar encode_json($services)
307
                );
308
                $template->param( services => $services );
309
            }
310
246
            $template->param( error => $params->{error} )
311
            $template->param( error => $params->{error} )
247
                if $params->{error};
312
                if $params->{error};
248
        }
313
        }
(-)a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss (+19 lines)
Lines 3671-3676 input.renew { Link Here
3671
        top: 50%;
3671
        top: 50%;
3672
        transform: translateY(-50%);
3672
        transform: translateY(-50%);
3673
    }
3673
    }
3674
    
3675
    #generic_confirm_search {
3676
        display: block;
3677
        visibility: hidden;
3678
        margin: 1em 0 1em 10em;
3679
    }
3680
3681
    #partnerSearch {
3682
        .modal-dialog {
3683
            width: 50vw;
3684
        }
3685
        .modal-body {
3686
            max-height: 70vh;
3687
        }
3688
    }
3674
}
3689
}
3675
3690
3676
.ill-view-panel {
3691
.ill-view-panel {
Lines 3703-3708 input.renew { Link Here
3703
    }
3718
    }
3704
}
3719
}
3705
3720
3721
.ill_availability_sourcename {
3722
    margin-top: 20px;
3723
}
3724
3706
#stockrotation {
3725
#stockrotation {
3707
    h3 {
3726
    h3 {
3708
        margin: 30px 0 10px 0;
3727
        margin: 30px 0 10px 0;
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/ill-availability-table.inc (+17 lines)
Line 0 Link Here
1
<div>
2
    <div>[% service.name %]</div>
3
    <table class="ill-availability" id="[% service.id %]">
4
        <thead id="[% service.id %]-header">
5
            <tr>
6
                <th>Source</th>
7
                <th>Title</th>
8
                <th>Author</th>
9
                <th>ISBN</th>
10
                <th>ISSN</th>
11
                <th>Date</th>
12
            </tr>
13
        </thead>
14
        <tbody id="[% service.id %]-body">
15
        </tbody>
16
    </table>
17
</div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt (-2 / +82 lines)
Lines 144-155 Link Here
144
                                        <label for="partners" class="required">Select partner libraries:</label>
144
                                        <label for="partners" class="required">Select partner libraries:</label>
145
                                        <select size="5" multiple="true" id="partners" name="partners" required="required">
145
                                        <select size="5" multiple="true" id="partners" name="partners" required="required">
146
                                            [% FOREACH partner IN whole.value.partners %]
146
                                            [% FOREACH partner IN whole.value.partners %]
147
                                                <option value=[% partner.email | html %]>
147
                                                <option data-partner-id="[% partner.id | html %]" value=[% partner.email | html %]>
148
                                                    [% partner.branchcode _ " - " _ partner.surname %]
148
                                                    [% partner.branchcode _ " - " _ partner.surname %]
149
                                                </option>
149
                                                </option>
150
                                            [% END %]
150
                                            [% END %]
151
                                        </select>
151
                                        </select>
152
152
                                        [% IF Koha.Preference('ILLCheckAvailability') %]
153
                                            <button type="button" id="generic_confirm_search">Search selected partners</button>
154
                                        [% END %]
153
                                    </li>
155
                                    </li>
154
                                    <li>
156
                                    <li>
155
                                        <label for="subject" class="required">Subject line:</label>
157
                                        <label for="subject" class="required">Subject line:</label>
Lines 169-174 Link Here
169
                                <span><a href="[% ill_url | url %]" title="Return to request details">Cancel</a></span>
171
                                <span><a href="[% ill_url | url %]" title="Return to request details">Cancel</a></span>
170
                            </fieldset>
172
                            </fieldset>
171
                        </form>
173
                        </form>
174
                        [% IF Koha.Preference('ILLCheckAvailability') %]
175
                            <div id="partnerSearch" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="partnerSearchLabel" aria-hidden="true">
176
                                <div class="modal-dialog">
177
                                    <div class="modal-content">
178
                                        <div class="modal-header">
179
                                            <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
180
                                            <h3 id="partnerSearchLabel"> Search partners</h3>
181
                                        </div>
182
                                        <div class="modal-body">
183
                                            [% FOR service IN services %]
184
                                                <h4 class="ill_availability_sourcename">[% service.plugin %]</h4>
185
                                                [% INCLUDE 'ill-availability-table.inc' service=service %]
186
                                            [% END %]
187
                                            <span id="service_id_restrict" data-service_id_restrict_plugin="ILL availability - z39.50" data-service_id_restrict_ids=""></span>
188
                                        </div>
189
                                        <div class="modal-footer">
190
                                            <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
191
                                        </div>
192
                                    </div>
193
                                </div>
194
                            </div>
195
                        [% END %]
196
172
                    [% ELSE %]
197
                    [% ELSE %]
173
                        <fieldset class="rows">
198
                        <fieldset class="rows">
174
                            <legend>Interlibrary loan request details</legend>
199
                            <legend>Interlibrary loan request details</legend>
Lines 518-523 Link Here
518
                        [% INCLUDE 'ill-list-table.inc' %]
543
                        [% INCLUDE 'ill-list-table.inc' %]
519
544
520
                    </div> <!-- /#results -->
545
                    </div> <!-- /#results -->
546
                [% ELSIF query_type == 'availability' %]
547
                    <!-- availability -->
548
                    <h1>Availability</h1>
549
                    <div id="results">
550
                        <h3>Displaying availability results</h3>
551
                        <form method="POST" action="/cgi-bin/koha/ill/ill-requests.pl">
552
                            [% FOREACH key IN whole.keys %]
553
                                [% value = whole.$key %]
554
                                [% IF key != 'method' && key != 'custom_key' && key != 'custom_value' %]
555
                                <input type="hidden" name="[% key | html %]" value="[% value | html %]">
556
                                [% END %]
557
                            [% END %]
558
                            [% custom_keys = whole.custom_key.split('\0') %]
559
                            [% custom_values = whole.custom_value.split('\0') %]
560
                            [% i = 0 %]
561
                            [% FOREACH custom_key IN custom_keys %]
562
                                <input type="hidden" name="custom_key" value="[% custom_key %]">
563
                                <input type="hidden" name="custom_value" value="[% custom_values.$i %]">
564
                            [% i = i + 1 %]
565
                            [% END %]
566
                            <input type="hidden" name="method" value="create">
567
                            <input type="hidden" name="stage" value="form">
568
                            <input type="hidden" name="checked_availability" value="1">
569
                            <div id="continue-request-row" class="alert">
570
                                If you can't find what you are looking for, you can
571
                                <button class="button" type="submit">continue creating your request</button> or
572
                                <a href="/cgi-bin/koha/ill/ill-requests.pl">cancel your request</a>
573
                            </div>
574
                        </form>
575
                        [% FOR service IN services %]
576
                            <h4 class="ill_availability_sourcename">[% service.plugin %]</h4>
577
                            [% INCLUDE 'ill-availability-table.inc' service=service %]
578
                        [% END %]
579
                    </div>
521
                [% ELSE %]
580
                [% ELSE %]
522
                <!-- Custom Backend Action -->
581
                <!-- Custom Backend Action -->
523
                [% PROCESS $whole.template %]
582
                [% PROCESS $whole.template %]
Lines 539-549 Link Here
539
        var prefilters = '[% prefilters | $raw %]';
598
        var prefilters = '[% prefilters | $raw %]';
540
        // Set column settings
599
        // Set column settings
541
        var columns_settings = [% ColumnsSettings.GetColumns( 'illrequests', 'ill-requests', 'ill-requests', 'json' ) %];
600
        var columns_settings = [% ColumnsSettings.GetColumns( 'illrequests', 'ill-requests', 'ill-requests', 'json' ) %];
601
        [% IF services_json.length > 0 %]
602
        var services = [% services_json | $raw %];
603
        [% ELSE %]
604
        var services = [];
605
        [% END %]
606
        [% IF metadata.length > 0 %]
607
        var metadata = "[% metadata | $raw %]";
608
        [% END %]
542
    </script>
609
    </script>
543
    [% IF query_type == 'illlist' %]
610
    [% IF query_type == 'illlist' %]
544
        [% INCLUDE 'ill-list-table-strings.inc' %]
611
        [% INCLUDE 'ill-list-table-strings.inc' %]
545
        [% Asset.js("js/ill-list-table.js") | $raw %]
612
        [% Asset.js("js/ill-list-table.js") | $raw %]
546
    [% END %]
613
    [% END %]
614
    [% IF (query_type == 'availability' || query_type == 'generic_confirm') && Koha.Preference('ILLCheckAvailability') %]
615
        [% Asset.js("js/ill-availability.js") | $raw %]
616
    [% END %]
617
    [% IF query_type == 'availability' && Koha.Preference('ILLCheckAvailability') %]
618
        <script>
619
            $(document).ready(function() {
620
                window.doSearch();
621
            });
622
        </script>
623
    [% END %]
624
    [% IF query_type == 'generic_confirm' && Koha.Preference('ILLCheckAvailability') %]
625
        [% Asset.js("js/ill-availability-partner.js") | $raw %]
626
    [% END %]
547
[% END %]
627
[% END %]
548
628
549
[% TRY %]
629
[% TRY %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/plugins/plugins-home.tt (+1 lines)
Lines 36-41 Link Here
36
                                    <li><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=to_marc">View MARC conversion plugins</a></li>
36
                                    <li><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=to_marc">View MARC conversion plugins</a></li>
37
                                    <li><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=opac_online_payment">View online payment plugins</a></li>
37
                                    <li><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=opac_online_payment">View online payment plugins</a></li>
38
                                    <li><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=intranet_catalog_biblio_enhancements">View intranet catalog biblio enhancement plugins</a></li>
38
                                    <li><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=intranet_catalog_biblio_enhancements">View intranet catalog biblio enhancement plugins</a></li>
39
                                    <li><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=ill_availability_services">View ILL availability plugins</a></li>
39
                                </ul>
40
                                </ul>
40
                            </div>
41
                            </div>
41
                        </div>
42
                        </div>
(-)a/koha-tmpl/intranet-tmpl/prog/js/ill-availability-partner.js (+24 lines)
Line 0 Link Here
1
$(document).ready(function() {
2
    $('#partners').change(function() {
3
        var selected = [];
4
        $('#partners option:selected').each(function() {
5
            selected.push($(this).data('partner-id'));
6
        });
7
        if (selected.length > 0) {
8
            $('#generic_confirm_search').css('visibility', 'initial');
9
        } else {
10
            $('#generic_confirm_search').css('visibility', 'hidden');
11
        }
12
        $('#service_id_restrict').
13
            attr('data-service_id_restrict_ids', selected.join('|'));
14
    });
15
    $('#generic_confirm_search').click(function(e) {
16
        $('#partnerSearch').modal({show:true});
17
    });
18
    $('#partnerSearch').on('show.bs.modal', function() {
19
        doSearch();
20
    });
21
    $('#partnerSearch').on('hide.bs.modal', function() {
22
        $.fn.dataTable.tables({ api: true }).destroy();
23
    });
24
});
(-)a/koha-tmpl/intranet-tmpl/prog/js/ill-availability.js (+171 lines)
Line 0 Link Here
1
$(document).ready(function() {
2
3
    window.doSearch = function() {
4
        // In case the source doesn't supply data required for DT to calculate
5
        // pagination, we need to do it ourselves
6
        var ownPagination = false;
7
        var directionSet = false;
8
        var start = 0;
9
        var forward = true; // true == forward, false == backwards
10
        // Arbitrary starting value, it will be corrected by the first
11
        // page of results
12
        var pageSize = 20;
13
14
        var tableTmpl = {
15
            ajax: {
16
                cache: true, // Prevent DT appending a "_" cache param
17
            },
18
            columns: [
19
                // defaultContent prevents DT from choking if
20
                // the API response doesn't return a column
21
                {
22
                    title: 'Source',
23
                    data: 'source',
24
                    defaultContent: ''
25
                },
26
                {
27
                    data: 'title',
28
                    defaultContent: ''
29
                },
30
                {
31
                    data: 'author',
32
                    defaultContent: ''
33
                },
34
                {
35
                    data: 'isbn',
36
                    defaultContent: ''
37
                },
38
                {
39
                    data: 'issn',
40
                    defaultContent: ''
41
                },
42
                {
43
                    data: 'date',
44
                    defaultContent: ''
45
                }
46
            ]
47
        };
48
49
        // render functions don't get copied across when we make a dereferenced
50
        // copy of them, so we have to reattach them once we have a copy
51
        // Here we store them
52
        var renders = {
53
            title: function(data, type, row) {
54
                return row.url ?
55
                    '<a href="'+row.url+'" target="_blank">'+row.title+'</a>' :
56
                    row.title;
57
            }
58
        };
59
60
        services.forEach(function(service) {
61
            // Create a deferenced copy of our table definition object
62
            var tableDef = JSON.parse(JSON.stringify(tableTmpl));
63
            // Iterate the table's columns array and add render functions
64
            // as necessary
65
            tableDef.columns.forEach(function(column) {
66
                if (renders[column.data]) {
67
                    column.render = renders[column.data];
68
                }
69
            });
70
            tableDef.ajax.dataSrc = function(data) {
71
                var results = data.results.search_results;
72
                // The source appears to be returning it's own pagination
73
                // data
74
                if (
75
                    results.hasOwnProperty('recordsFiltered') ||
76
                    results.hasOwnProperty('recordsTotal')
77
                ) {
78
                    return results;
79
                }
80
                // Set up our own pagination values based on what we just
81
                // got back
82
                ownPagination = true;
83
                directionSet = false;
84
                pageSize = results.length;
85
                // These values are completely arbitrary, but they enable
86
                // us to display pagination links
87
                data.recordsFiltered = 5000,
88
                data.recordsTotal = 5000;
89
90
                return results;
91
            };
92
            tableDef.ajax.data = function(data) {
93
                // Datatables sends a bunch of superfluous params
94
                // that we don't want to litter our API schema
95
                // with, so just remove them from the request
96
                if (data.hasOwnProperty('columns')) {
97
                    delete data.columns;
98
                }
99
                if (data.hasOwnProperty('draw')) {
100
                    delete data.draw;
101
                }
102
                if (data.hasOwnProperty('order')) {
103
                    delete data.order;
104
                }
105
                if (data.hasOwnProperty('search')) {
106
                    delete data.search;
107
                }
108
                // If we're handling our own pagination, set the properties
109
                // that DT will send in the request
110
                if (ownPagination) {
111
                    start = forward ? start + pageSize : start - pageSize;
112
                    data.start = start;
113
                    data.length = pageSize;
114
                }
115
                // We may need to restrict the service IDs being queries, this
116
                // needs to be handled in the plugin's API module
117
                var restrict = $('#service_id_restrict').
118
                    attr('data-service_id_restrict_ids');
119
                if (restrict && restrict.length > 0) {
120
                    data.restrict = restrict;
121
                }
122
            };
123
            // Add any datatables config options passed from the service
124
            // to the table definition
125
            tableDef.ajax.url = service.endpoint + metadata;
126
            if (service.hasOwnProperty('datatablesConfig')) {
127
                var conf = service.datatablesConfig;
128
                for (var key in conf) {
129
                    // The config from the service definition comes from a Perl
130
                    // hashref, therefore can't contain true/false, so we
131
                    // special case it
132
                    if (conf.hasOwnProperty(key)) {
133
                        if (conf[key] == 'false') {
134
                            // Special case false values
135
                            tableDef[key] = false;
136
                        } else if (conf[key] == 'true') {
137
                            // Special case true values
138
                            tableDef[key] = true;
139
                        } else {
140
                            // Copy the property value
141
                            tableDef[key] = conf[key];
142
                        }
143
                    }
144
                }
145
            }
146
            // Create event watchers for the "next" and "previous" pagination
147
            // links, this enables us to set the direction the next request is
148
            // going in when we're doing our own pagination. We use "hover"
149
            // because the click event is caught after the request has been
150
            // sent
151
            tableDef.drawCallback = function() {
152
                $('.paginate_button.next:not(.disabled)',
153
                    this.api().table().container()
154
                ).on('hover', function() {
155
                    forward = true;
156
                    directionSet = true;
157
                });
158
                $('.paginate_button.previous:not(.disabled)',
159
                    this.api().table().container()
160
                ).on('hover', function() {
161
                    forward = false;
162
                    directionSet = true;
163
                });
164
            }
165
            // Initialise the table
166
            KohaTable(service.id, tableDef);
167
        });
168
    }
169
170
171
});
(-)a/koha-tmpl/opac-tmpl/bootstrap/css/src/opac.scss (+9 lines)
Lines 3038-3043 button.closebtn { Link Here
3038
    .dropdown:hover .dropdown-menu.nojs {
3038
    .dropdown:hover .dropdown-menu.nojs {
3039
        display: block;
3039
        display: block;
3040
    }
3040
    }
3041
3042
}
3043
3044
.ill_availability_sourcename {
3045
    margin-top: 20px;
3046
}
3047
3048
#continue-request-row {
3049
    text-align: center;
3041
}
3050
}
3042
3051
3043
#dc_fieldset {
3052
#dc_fieldset {
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/includes/ill-availability-table.inc (+17 lines)
Line 0 Link Here
1
<div>
2
    <div>[% service.name %]</div>
3
    <table class="ill-availability table table-bordered table-striped" id="[% service.id %]">
4
        <thead id="[% service.id %]-header">
5
            <tr>
6
                <th>Source</th>
7
                <th>Title</th>
8
                <th>Author</th>
9
                <th>ISBN</th>
10
                <th>ISSN</th>
11
                <th>Date</th>
12
            </tr>
13
        </thead>
14
        <tbody id="[% service.id %]-body">
15
        </tbody>
16
    </table>
17
</div>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt (+40 lines)
Lines 224-229 Link Here
224
                                <span class="cancel"><a href="/cgi-bin/koha/opac-illrequests.pl">Cancel</a></span>
224
                                <span class="cancel"><a href="/cgi-bin/koha/opac-illrequests.pl">Cancel</a></span>
225
                            </fieldset>
225
                            </fieldset>
226
                        </form>
226
                        </form>
227
                    [% ELSIF method == 'availability' %]
228
                        <h2>Interlibrary loan item availability</h2>
229
                        <div id="results">
230
                            <h3>Displaying availability results</h3>
231
                            <form method="POST" action="/cgi-bin/koha/opac-illrequests.pl">
232
                                [% FOREACH key IN whole.keys %]
233
                                    [% value = whole.$key %]
234
                                    [% IF key != 'custom_key' && key != 'custom_value' %]
235
                                    <input type="hidden" name="[% key | html %]" value="[% value | html %]">
236
                                    [% END %]
237
                                [% END %]
238
                                [% custom_keys = whole.custom_key.split('\0') %]
239
                                [% custom_values = whole.custom_value.split('\0') %]
240
                                [% i = 0 %]
241
                                [% FOREACH custom_key IN custom_keys %]
242
                                    <input type="hidden" name="custom_key" value="[% custom_key %]">
243
                                    <input type="hidden" name="custom_value" value="[% custom_values.$i %]">
244
                                [% i = i + 1 %]
245
                                [% END %]
246
                                <input type="hidden" name="checked_availability" value="1">
247
                                <div id="continue-request-row" class="alert">
248
                                    If you can't find what you are looking for, you can
249
                                    <button class="button" type="submit">continue creating your request</button> or
250
                                    <a href="/cgi-bin/koha/opac-illrequests.pl">cancel your request</a>
251
                                </div>
252
                            </form>
253
                            [% FOR service IN services %]
254
                                <h4 class="ill_availability_sourcename">[% service.plugin %]</h4>
255
                                [% INCLUDE 'ill-availability-table.inc' service=service %]
256
                            [% END %]
257
                        </div>
227
                    [% END %]
258
                    [% END %]
228
                </div> <!-- / .maincontent -->
259
                </div> <!-- / .maincontent -->
229
          [% END %]
260
          [% END %]
Lines 247-254 Link Here
247
            "deferRender": true
278
            "deferRender": true
248
        }));
279
        }));
249
        $("#backend-dropdown-options").removeClass("nojs");
280
        $("#backend-dropdown-options").removeClass("nojs");
281
        [% IF services_json.length > 0 %]
282
        var services = [% services_json | $raw %];
283
        [% ELSE %]
284
        var services = [];
285
        [% END %]
286
        [% IF metadata.length > 0 %]
287
        var metadata = "[% metadata | $raw %]";
288
        [% END %]
250
    //]]>
289
    //]]>
251
</script>
290
</script>
291
[% Asset.js("js/ill-availability.js") | $raw %]
252
[% TRY %]
292
[% TRY %]
253
[% PROCESS backend_jsinclude %]
293
[% PROCESS backend_jsinclude %]
254
[% CATCH %]
294
[% CATCH %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/js/ill-availability.js (+163 lines)
Line 0 Link Here
1
$(document).ready(function() {
2
3
    // In case the source doesn't supply data required for DT to calculate
4
    // pagination, we need to do it ourselves
5
    var ownPagination = false;
6
    var directionSet = false;
7
    var start = 0;
8
    var forward = true; // true == forward, false == backwards
9
    // Arbitrary starting value, it will be corrected by the first
10
    // page of results
11
    var pageSize = 20;
12
13
    var tableTmpl = {
14
        ajax: {
15
            cache: true, // Prevent DT appending a "_" cache param
16
        },
17
        columns: [
18
            // defaultContent prevents DT from choking if
19
            // the API response doesn't return a column
20
            {
21
                title: 'Source',
22
                data: 'source',
23
                defaultContent: ''
24
            },
25
            {
26
                data: 'title',
27
                defaultContent: ''
28
            },
29
            {
30
                data: 'author',
31
                defaultContent: ''
32
            },
33
            {
34
                data: 'isbn',
35
                defaultContent: ''
36
            },
37
            {
38
                data: 'issn',
39
                defaultContent: ''
40
            },
41
            {
42
                data: 'date',
43
                defaultContent: ''
44
            }
45
        ]
46
    };
47
48
    // render functions don't get copied across when we make a dereferenced
49
    // copy of them, so we have to reattach them once we have a copy
50
    // Here we store them
51
    var renders = {
52
        title: function(data, type, row) {
53
            return row.url ?
54
                '<a href="'+row.url+'" target="_blank">'+row.title+'</a>' :
55
                row.title;
56
        }
57
    };
58
59
    services.forEach(function(service) {
60
        // Create a deferenced copy of our table definition object
61
        var tableDef = JSON.parse(JSON.stringify(tableTmpl));
62
        // Iterate the table's columns array and add render functions
63
        // as necessary
64
        tableDef.columns.forEach(function(column) {
65
            if (renders[column.data]) {
66
                column.render = renders[column.data];
67
            }
68
        });
69
        tableDef.ajax.dataSrc = function(data) {
70
            var results = data.results.search_results;
71
            // The source appears to be returning it's own pagination
72
            // data
73
            if (
74
                results.hasOwnProperty('recordsFiltered') ||
75
                results.hasOwnProperty('recordsTotal')
76
            ) {
77
                return results;
78
            }
79
            // Set up our own pagination values based on what we just
80
            // got back
81
            ownPagination = true;
82
            directionSet = false;
83
            pageSize = results.length;
84
            // These values are completely arbitrary, but they enable
85
            // us to display pagination links
86
            data.recordsFiltered = 5000,
87
            data.recordsTotal = 5000;
88
89
            return results;
90
        };
91
        tableDef.ajax.data = function(data) {
92
            // Datatables sends a bunch of superfluous params
93
            // that we don't want to litter our API schema
94
            // with, so just remove them from the request
95
            if (data.hasOwnProperty('columns')) {
96
                delete data.columns;
97
            }
98
            if (data.hasOwnProperty('draw')) {
99
                delete data.draw;
100
            }
101
            if (data.hasOwnProperty('order')) {
102
                delete data.order;
103
            }
104
            if (data.hasOwnProperty('search')) {
105
                delete data.search;
106
            }
107
            // If we're handling our own pagination, set the properties
108
            // that DT will send in the request
109
            if (ownPagination) {
110
                start = forward ? start + pageSize : start - pageSize;
111
                data.start = start;
112
                data.length = pageSize;
113
            }
114
        };
115
        // Add any datatables config options passed from the service
116
        // to the table definition
117
        tableDef.ajax.url = service.endpoint + metadata;
118
        if (service.hasOwnProperty('datatablesConfig')) {
119
            var conf = service.datatablesConfig;
120
            for (var key in conf) {
121
                // The config from the service definition comes from a Perl
122
                // hashref, therefore can't contain true/false, so we
123
                // special case it
124
                if (conf.hasOwnProperty(key)) {
125
                    if (conf[key] == 'false') {
126
                        // Special case false values
127
                        tableDef[key] = false;
128
                    } else if (conf[key] == 'true') {
129
                        // Special case true values
130
                        tableDef[key] = true;
131
                    } else {
132
                        // Copy the property value
133
                        tableDef[key] = conf[key];
134
                    }
135
                }
136
            }
137
        }
138
        // Create event watchers for the "next" and "previous" pagination
139
        // links, this enables us to set the direction the next request is
140
        // going in when we're doing our own pagination. We use "hover"
141
        // because the click event is caught after the request has been
142
        // sent
143
        tableDef.drawCallback = function() {
144
            $('.paginate_button.next:not(.disabled)',
145
                this.api().table().container()
146
            ).on('hover', function() {
147
                forward = true;
148
                directionSet = true;
149
            });
150
            $('.paginate_button.previous:not(.disabled)',
151
                this.api().table().container()
152
             ).on('hover', function() {
153
                forward = false;
154
                directionSet = true;
155
            });
156
        }
157
        // Initialise the table
158
        $('#'+service.id ).dataTable(
159
            $.extend(true, {}, dataTablesDefaults, tableDef)
160
        );
161
    });
162
163
});
(-)a/opac/opac-illrequests.pl (-1 / +41 lines)
Lines 19-24 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use JSON qw( encode_json );
23
22
use CGI qw ( -utf8 );
24
use CGI qw ( -utf8 );
23
use C4::Auth;
25
use C4::Auth;
24
use C4::Koha;
26
use C4::Koha;
Lines 28-33 use Koha::Illrequest::Config; Link Here
28
use Koha::Illrequests;
30
use Koha::Illrequests;
29
use Koha::Libraries;
31
use Koha::Libraries;
30
use Koha::Patrons;
32
use Koha::Patrons;
33
use Koha::Illrequest::Availability;
31
34
32
my $query = new CGI;
35
my $query = new CGI;
33
36
Lines 110-115 if ( $op eq 'list' ) { Link Here
110
    } else {
113
    } else {
111
        my $request = Koha::Illrequest->new
114
        my $request = Koha::Illrequest->new
112
            ->load_backend($params->{backend});
115
            ->load_backend($params->{backend});
116
117
        # Does this backend enable us to insert an availability stage and should
118
        # we? If not, proceed as normal.
119
        if (
120
            C4::Context->preference("ILLCheckAvailability") &&
121
            $request->_backend_capability(
122
                'should_display_availability',
123
                $params
124
            ) &&
125
            # If the user has elected to continue with the request despite
126
            # having viewed availability info, this flag will be set
127
            !$params->{checked_availability}
128
        ) {
129
            # Establish which of the installed availability providers
130
            # can service our metadata, if so, jump in
131
            my $availability = Koha::Illrequest::Availability->new($params);
132
            my $services = $availability->get_services();
133
            if (scalar @{$services} > 0) {
134
                # Modify our method so we use the correct part of the
135
                # template
136
                $op = 'availability';
137
                # Prepare the metadata we're sending them
138
                my $metadata = $availability->prep_metadata($params);
139
                $template->param(
140
                    metadata        => $metadata,
141
                    services_json   => encode_json($services),
142
                    services        => $services,
143
                    illrequestsview => 1,
144
                    message         => $params->{message},
145
                    method          => $op,
146
                    whole           => $params
147
                );
148
                output_html_with_http_headers $query, $cookie,
149
                    $template->output, undef, { force_no_caching => 1 };
150
                exit;
151
            }
152
        }
153
113
        $params->{cardnumber} = Koha::Patrons->find({
154
        $params->{cardnumber} = Koha::Patrons->find({
114
            borrowernumber => $loggedinuser
155
            borrowernumber => $loggedinuser
115
        })->cardnumber;
156
        })->cardnumber;
116
- 

Return to bug 23173