1window.tablelayout = window.tablelayout || {};
2
3jQuery(window).on('load', function () {
4    'use strict';
5
6    /**
7     *
8     * @param {jQuery} $secedit_form jQuery object of the section edit form associated with the table
9     *
10     * @return {void}
11     */
12    function addPrintButtonToTable($secedit_form) {
13        var range = $secedit_form.find('input[name="range"]').val();
14        var target = $secedit_form.closest('form').attr('action');
15        var layout = $secedit_form.find('input[name="tablelayout"]').val();
16        var params = [
17            'do=tablelayout_printtable',
18            'range=' + encodeURIComponent(range),
19            'id=' + encodeURIComponent(window.JSINFO.id)
20        ];
21
22        if (typeof layout !== 'undefined' && layout.length > 0) {
23            var json = JSON.parse(layout);
24            var colwidth = json.colwidth;
25            params.push('colwidth=' + colwidth);
26        }
27
28        var href = target + '?' + params.join('&');
29        var $link = jQuery('<a>' + window.LANG.plugins.tablelayout.print + '</a>').attr({
30            'href': href,
31            'target': '_blank'
32        }).addClass('button print');
33        $secedit_form.closest('div.secedit').append($link);
34    }
35
36    /**
37     * Add a row for the search fields and filter buttons below the table header
38     *
39     * @param {JQuery} $table jQuery-object of the table
40     * @param {int} numHeaderRows the number of rows in the header of the table
41     * @param {int} columnCount the number of columns in the table
42     * @return {JQuery} the searchSortRow object, that has been added to the table
43     */
44    function addSearchSortRow($table, numHeaderRows, columnCount) {
45        var $searchSortRow = jQuery('<tr class="searchSortRow">' + '<th><div></div></th>'.repeat(columnCount) + '</tr>');
46        var $lastHeaderRow;
47        if ($table.hasClass('tablelayout_body')) {
48            $lastHeaderRow = $table.closest('.table').find('table.tablelayout_head tr').last();
49            $lastHeaderRow.after($searchSortRow);
50        } else if(numHeaderRows === 0) {
51            $table.find('tr').first().before($searchSortRow);
52        } else {
53            $lastHeaderRow = $table.find('tr').slice(numHeaderRows - 1).first();
54            $lastHeaderRow.after($searchSortRow);
55        }
56        return $searchSortRow;
57    }
58
59    /**
60     *
61     * @param {JQuery} $table jQuery-object of the table
62     * @param {JQuery} $searchSortRow the special row where the sort-buttons will be placed
63     * @param {int} numHeaderRows the number of rows in the header of the table
64     *
65     * @return {void}
66     */
67    function addSortFunctionality($table, $searchSortRow, numHeaderRows) {
68        var $rowsToBeSorted;
69        if ($table.hasClass('tablelayout_body')) {
70            $rowsToBeSorted = $table.find('tr');
71        } else {
72            $rowsToBeSorted = $table.find('tr').slice(parseInt(numHeaderRows) + 1);
73        }
74        var $tableSortRowCells = $searchSortRow.find('td > div,th > div');
75        $tableSortRowCells.append(jQuery('<button>'));
76        var $tableSortRowCellsButtons = $tableSortRowCells.find('button');
77        $tableSortRowCellsButtons.addClass('sortable unsorted');
78        $tableSortRowCellsButtons.click(function () {
79            window.tablelayout.splitMerges($rowsToBeSorted);
80            var $this = jQuery(this);
81            var sortDirection = $this.hasClass('sorted_asc') ? 'desc' : 'asc';
82            $tableSortRowCellsButtons.removeClass('sorted_asc sorted_desc').addClass('unsorted');
83            $this.addClass('sorted_' + sortDirection).removeClass('unsorted');
84            var colIndex = $this.closest('td,th').prevAll('td,th').length;
85            var sortedRows = window.tablelayout.sortTable($rowsToBeSorted.detach(), colIndex, sortDirection);
86            $table.append(sortedRows);
87            return false;
88        });
89    }
90
91    /**
92     *
93     * @param {JQuery} $table jQuery-object of the table
94     * @param {JQuery} $searchSortRow the special row where the sort-buttons will be placed
95     * @param {int} numHeaderRows the number of rows in the header of the table
96     *
97     * @return {void}
98     */
99    function addSearchFunctionality($table, $searchSortRow, numHeaderRows) {
100        var $rowsToBeSearched;
101        var $container = $searchSortRow.closest('.table');
102        $container.addClass('hasSearch');
103        if ($table.hasClass('tablelayout_body')) {
104            $rowsToBeSearched = $table.find('tr');
105        } else {
106            $rowsToBeSearched = $table.find('tr').slice(parseInt(numHeaderRows) + 1);
107        }
108
109        $searchSortRow.find('td > div,th > div').prepend(jQuery('<input>'));
110        var $globalSearch = jQuery('<div class="globalSearch"><label><span>' + window.LANG.plugins.tablelayout.search + '</span><input name="globalSearch" type="text"></label></div>');
111        $container.prepend($globalSearch);
112        var $searchInputs = $searchSortRow.find('input').add($globalSearch.find('input'));
113        $searchInputs.on('input', function () {
114            window.tablelayout.splitMerges($rowsToBeSearched);
115            var globalSearchText = $globalSearch.find('input').val().trim().toLowerCase();
116            $rowsToBeSearched.each(function (index, row) {
117                var globalRowShow = false;
118                var hideRow = jQuery(row).find('td,th').toArray().some(function (cell, index) {
119                    var $this = jQuery(cell);
120                    var cellText = $this.text().trim().toLowerCase();
121                    globalRowShow = globalRowShow || (cellText.indexOf(globalSearchText) !== -1);
122                    var colFilterIndex = index + 1;
123                    var searchText = $searchInputs.eq(colFilterIndex).val().trim().toLowerCase();
124                    return cellText.indexOf(searchText) === -1;
125                });
126                jQuery(row).css('display', (globalRowShow && !hideRow) ? 'table-row' : 'none');
127            });
128        });
129    }
130
131    /**
132     *
133     * @param {JQuery} $table jQuery-object of the table
134     * @param {JQuery} $secedit_form the section edit form element for the table
135     * @param {object} layoutdata the configuration object
136     *
137     * @return {void}
138     */
139    function applyFunctionalityToTable($table, $secedit_form, layoutdata) {
140        if (layoutdata.tablePrint) {
141            addPrintButtonToTable($secedit_form);
142        }
143
144        if (layoutdata.tableSort || layoutdata.tableSearch) {
145            var columnCount = $table.find('tr').toArray().reduce(function (max, row) {
146                return Math.max(max, jQuery(row).find('td,th').length);
147            }, 0);
148            var searchSortRow = addSearchSortRow($table, layoutdata.rowsHeader, columnCount);
149        }
150
151        if (layoutdata.tableSort) {
152            addSortFunctionality($table, searchSortRow, layoutdata.rowsHeader);
153        }
154
155        if (layoutdata.tableSearch) {
156            addSearchFunctionality($table, searchSortRow, layoutdata.rowsHeader)
157        }
158    }
159
160    var allowedModes = ['mode_show', 'mode_preview', 'mode_tablelayout_printtable', 'act_show', 'act_preview'];
161    if (!allowedModes.some(function (allowedModeClass) {return jQuery('.dokuwiki').hasClass(allowedModeClass)})) {
162        return;
163    }
164
165    jQuery('.page .table').each(function (index, element) {
166        var $table = jQuery(element).find('table');
167        var layoutdata = jQuery(element).prev().data('tablelayout');
168        if (typeof layoutdata === 'undefined') {
169            var featureDefault = Boolean(window.JSINFO.plugins.tablelayout.features_active_by_default);
170            layoutdata = {
171                rowsHeaderSource: 'Auto',
172                tableSearch: featureDefault,
173                tableSort: featureDefault,
174                tablePrint: featureDefault
175            };
176        }
177        var numHeaderRowsAuto = $table.find('thead tr').length;
178        layoutdata.rowsHeader = layoutdata.rowsHeaderSource === 'Auto' ? numHeaderRowsAuto : layoutdata.rowsHeaderSource;
179
180        var $secedit_form = jQuery(element).next('.secedit').find('form div.no');
181        if ($secedit_form.length) {
182            var $input = jQuery('<input name="tablelayout" type="hidden">').val(JSON.stringify(layoutdata));
183            $secedit_form.prepend($input);
184        }
185        applyFunctionalityToTable($table, $secedit_form, layoutdata);
186
187        if (layoutdata.colwidth || layoutdata.rowsVisible) {
188            window.tablelayout.applyStylesToTable($table, layoutdata);
189        }
190
191    });
192
193    if (jQuery('#tablelayout_printthis').length) {
194        window.print();
195    }
196});
197