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

(-)a/koha-tmpl/opac-tmpl/bootstrap/en/includes/columns_settings.inc (-2 / +4 lines)
Lines 1-5 Link Here
1
[% USE TablesSettings %]
1
[% USE TablesSettings %]
2
2
[% Asset.js("js/datatables_buttons_shim.js") | $raw %]
3
<script>
3
<script>
4
4
5
function _dt_visibility(table_settings, table_dt){
5
function _dt_visibility(table_settings, table_dt){
Lines 47-52 function KohaTable(selector, dt_parameters, table_settings) { Link Here
47
        }
47
        }
48
    }
48
    }
49
49
50
    const export_format_spreadsheet = ButtonsShim.export_format_spreadsheet;
51
50
    // Add a "Clear filter" button to table filter form field
52
    // Add a "Clear filter" button to table filter form field
51
    dt_parameters[ "buttons" ] = [
53
    dt_parameters[ "buttons" ] = [
52
        {
54
        {
Lines 65-71 function KohaTable(selector, dt_parameters, table_settings) { Link Here
65
            text: _("CSV"),
67
            text: _("CSV"),
66
            exportOptions: {
68
            exportOptions: {
67
                columns: exportColumns,
69
                columns: exportColumns,
68
                format: export_format
70
                format: export_format_spreadsheet
69
            },
71
            },
70
        },
72
        },
71
        {
73
        {
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/includes/datatables.inc (+1 lines)
Lines 1-4 Link Here
1
[% USE raw %]
1
[% USE raw %]
2
[% USE Asset %]
2
[% USE Asset %]
3
[% Asset.js("js/datatables_buttons_shim.js") | $raw %]
3
[% Asset.js("lib/datatables/datatables.min.js") | $raw %]
4
[% Asset.js("lib/datatables/datatables.min.js") | $raw %]
4
[% Asset.js("js/datatables.js") | $raw %]
5
[% Asset.js("js/datatables.js") | $raw %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt (-1 / +4 lines)
Lines 1200-1205 Link Here
1200
                );
1200
                );
1201
            });
1201
            });
1202
1202
1203
            const export_format_spreadsheet = ButtonsShim.export_format_spreadsheet;
1204
1203
            var dTables = $("#checkoutst,#holdst,#overduest,#opac-user-relative-issues-table");
1205
            var dTables = $("#checkoutst,#holdst,#overduest,#opac-user-relative-issues-table");
1204
            dTables.each(function(){
1206
            dTables.each(function(){
1205
                var thIndex = $(this).find("th.psort").index();
1207
                var thIndex = $(this).find("th.psort").index();
Lines 1239-1245 Link Here
1239
                            extend: "csv",
1241
                            extend: "csv",
1240
                            exportOptions: {
1242
                            exportOptions: {
1241
                                /* CSV export should include all columns (even invisible ones) unless they are .noExport */
1243
                                /* CSV export should include all columns (even invisible ones) unless they are .noExport */
1242
                                columns: ":not(.noExport)"
1244
                                columns: ":not(.noExport)",
1245
                                format:  export_format_spreadsheet
1243
                            }
1246
                            }
1244
                        }
1247
                        }
1245
                    ]
1248
                    ]
(-)a/koha-tmpl/opac-tmpl/bootstrap/js/datatables_buttons_shim.js (-1 / +112 lines)
Line 0 Link Here
0
- 
1
window.ButtonsShim = {};
2
3
ButtonsShim.export_format_spreadsheet = {
4
    body: function (data, row, column, node) {
5
        const newnode = node.cloneNode(true);
6
        const no_export_nodes = newnode.querySelectorAll(".no-export");
7
        no_export_nodes.forEach(child => {
8
            child.parentNode.removeChild(child);
9
        });
10
        //Note: innerHTML is the same thing as the data variable,
11
        //minus the ".no-export" nodes that we've removed
12
        //Note: See dataTables.buttons.js for original function usage
13
        const str = ButtonsShim.stripData(newnode.innerHTML, {
14
            decodeEntities: false,
15
            stripHtml: true,
16
            stripNewlines: true,
17
            trim: true,
18
            escapeExcelFormula: true
19
        });
20
        return str;
21
    },
22
};
23
24
ButtonsShim._stripHtml = function (input) {
25
    var _max_str_len = Math.pow(2, 28);
26
    var _re_html = /<([^>]*>)/g;
27
    if (! input || typeof input !== 'string') {
28
        return input;
29
    }
30
    // Irrelevant check to workaround CodeQL's false positive on the regex
31
    if (input.length > _max_str_len) {
32
        throw new Error('Exceeded max str len');
33
    }
34
    var previous;
35
    input = input.replace(_re_html, ''); // Complete tags
36
    // Safety for incomplete script tag - use do / while to ensure that
37
    // we get all instances
38
    do {
39
        previous = input;
40
        input = input.replace(/<script/i, '');
41
    } while (input !== previous);
42
    return previous;
43
};
44
45
ButtonsShim.stripHtml = function (mixed) {
46
    var type = typeof mixed;
47
48
    if (type === 'function') {
49
        ButtonsShim._stripHtml = mixed;
50
        return;
51
    }
52
    else if (type === 'string') {
53
        return ButtonsShim._stripHtml(mixed);
54
    }
55
    return mixed;
56
};
57
ButtonsShim.stripHtmlScript = function (input) {
58
    var previous;
59
    do {
60
        previous = input;
61
        input = input.replace(/<script\b[^<]*(?:(?!<\/script[^>]*>)<[^<]*)*<\/script[^>]*>/gi, '');
62
    } while (input !== previous);
63
    return input;
64
};
65
ButtonsShim.stripHtmlComments = function (input) {
66
    var previous;
67
    do {
68
        previous = input;
69
        input = input.replace(/(<!--.*?--!?>)|(<!--[\S\s]+?--!?>)|(<!--[\S\s]*?$)/g, '');
70
    } while (input !== previous);
71
    return input;
72
};
73
ButtonsShim.stripData = function (str, config) {
74
    // If the input is an HTML element, we can use the HTML from it (HTML might be stripped below).
75
    if (str !== null && typeof str === 'object' && str.nodeName && str.nodeType) {
76
        str = str.innerHTML;
77
    }
78
79
    if (typeof str !== 'string') {
80
        return str;
81
    }
82
83
    // Always remove script tags
84
    //str = Buttons.stripHtmlScript(str);
85
    str = ButtonsShim.stripHtmlScript(str);
86
87
    // Always remove comments
88
    //str = Buttons.stripHtmlComments(str);
89
    str = ButtonsShim.stripHtmlComments(str);
90
91
    if (!config || config.stripHtml) {
92
        //str = DataTable.util.stripHtml(str);
93
        str = ButtonsShim.stripHtml(str);
94
    }
95
96
    if (!config || config.trim) {
97
        str = str.trim();
98
    }
99
100
    if (!config || config.stripNewlines) {
101
        str = str.replace(/\n/g, ' ');
102
    }
103
104
    // Prevent Excel from running a formula
105
    if (!config || config.escapeExcelFormula) {
106
        if (str.match(/^[=@\t\r]/)) {
107
            str = "'" + str;
108
        }
109
    }
110
111
    return str;
112
};

Return to bug 40525