UNPKG

ajax-table

Version:

Handles a table loading with AJAX

738 lines (632 loc) 34.9 kB
const _ajaxTable = []; (function ($) { $.fn.extend({ ajaxTable: function (options) { this.defaultOptions = { source: false, sourceContext: {}, printButtons: true, orderBy: 0, orderSort: 'desc', logging: false, contentType: 'application/x-www-form-urlencoded; charset=UTF-8', searchPlaceholders: null, onReady: function (table, data) { }, onStructureReady: function (table, data) { }, beforeAjax: function (table, data) { }, onUpdate: function (table, data) { } }; let settings = $.extend({}, this.defaultOptions, options); let lang = window.navigator.userLanguage || window.navigator.language; //UTILITIES function mergeSort(array, comparefn) { function merge(arr, aux, lo, mid, hi, comparefn) { var i = lo; var j = mid + 1; var k = lo; while (true) { var cmp = comparefn(arr[i], arr[j]); if (cmp <= 0) { aux[k++] = arr[i++]; if (i > mid) { do aux[k++] = arr[j++]; while (j <= hi); break; } } else { aux[k++] = arr[j++]; if (j > hi) { do aux[k++] = arr[i++]; while (i <= mid); break; } } } } function sortarrtoaux(arr, aux, lo, hi, comparefn) { if (hi < lo) return; if (hi == lo) { aux[lo] = arr[lo]; return; } var mid = Math.floor(lo + (hi - lo) / 2); sortarrtoarr(arr, aux, lo, mid, comparefn); sortarrtoarr(arr, aux, mid + 1, hi, comparefn); merge(arr, aux, lo, mid, hi, comparefn); } function sortarrtoarr(arr, aux, lo, hi, comparefn) { if (hi <= lo) return; var mid = Math.floor(lo + (hi - lo) / 2); sortarrtoaux(arr, aux, lo, mid, comparefn); sortarrtoaux(arr, aux, mid + 1, hi, comparefn); merge(aux, arr, lo, mid, hi, comparefn); } function merge_sort(arr, comparefn) { var aux = arr.slice(0); sortarrtoarr(arr, aux, 0, arr.length - 1, comparefn); return arr; } return merge_sort(array, comparefn); } function htmlToElement(html) { var template = document.createElement('template'); html = html.trim(); template.innerHTML = html; return template.content.firstChild; } function paginationDisplay(currentPage, pageCount) { let delta = 2, left = currentPage - delta, right = currentPage + delta + 1, result = []; result = Array.from({ length: pageCount }, (v, k) => k + 1) .filter(i => i && i >= left && i < right); if (result.length > 1) { // Add first page and dots if (result[0] > 1) { if (result[0] > 2) { result.unshift('...') } result.unshift(1) } // Add dots and last page if (result[result.length - 1] < pageCount) { if (result[result.length - 1] !== pageCount - 1) { result.push('...') } result.push(pageCount) } } return result; } function updateNav(utilities, targetedPage, pageCount, i) { //PAGINATION $('.pagination-page,.pagination-etc', utilities).remove(); if (targetedPage != 1) $('.pagination-prev', utilities).removeClass('disabled'); else $('.pagination-prev', utilities).addClass('disabled'); if (targetedPage < pageCount) $('.pagination-next', utilities).removeClass('disabled'); else $('.pagination-next', utilities).addClass('disabled'); for (li of paginationDisplay(_ajaxTable[i].page, pageCount)) { $('.pagination-next', utilities).before('<li class="' + (li == '...' ? 'pagination-etc' : 'pagination-page') + (li == targetedPage ? ' active' : '') + '" data-page="' + li + '">' + li + '</li>'); } _ajaxTable[i].page = targetedPage; //COUNT $('#ajax-table-item-start-id', utilities).text((_ajaxTable[i].page - 1) * 10 + 1 > _ajaxTable[i].filteredTotal ? _ajaxTable[i].filteredTotal : (_ajaxTable[i].page - 1) * 10 + 1); $('#ajax-table-item-end-id', utilities).text(_ajaxTable[i].page * 10 > _ajaxTable[i].filteredTotal ? _ajaxTable[i].filteredTotal : _ajaxTable[i].page * 10); $('#ajax-table-item-filtered-total', utilities).text(_ajaxTable[i].filteredTotal); $('#ajax-table-item-total', utilities).text(_ajaxTable[i].total); } function updateTable(table, i) { $('tbody', table).empty().append(_ajaxTable[i].filteredData.slice((_ajaxTable[i].page - 1) * 10, _ajaxTable[i].page * 10)); //Empty test if (!_ajaxTable[i].filteredData.slice((_ajaxTable[i].page - 1) * 10, _ajaxTable[i].page * 10).length) $('tbody', table).append('<tr><td class="empty" colspan="' + _ajaxTable[i].columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); let pageCount = Math.floor((_ajaxTable[i].filteredTotal - 1) / 10) + 1; updateNav($(table).next(), _ajaxTable[i].page, pageCount, i); } function paginationHandler(table, i, targetedPage, pagination, pageCount) { let dataGathering = new Promise((resolve, reject) => { // AJAX && NOT FULLY LOADED && (( NO FILTER && NOT STORED ) || FILTER ) if (settings.source && !_ajaxTable[i].dataFullyLoaded && ((!_ajaxTable[i].activeSearch && !_ajaxTable[i].silentData[targetedPage]) || _ajaxTable[i].activeSearch)) { settings.beforeAjax.call(undefined, table, _ajaxTable[i]); if (settings.logging) console.log('ajaxTable calling source...'); SlickLoader.enable(); const data = { page: targetedPage, orderBy: _ajaxTable[i].orderBy, order: _ajaxTable[i].orderSort, search: _ajaxTable[i].search, searchPatterns: _ajaxTable[i].searchPatterns, columns: _ajaxTable[i].columns, total: true, context: settings.sourceContext }; $.post({ url: settings.source, data: settings.contentType == 'application/json' ? JSON.stringify(data) : data, contentType: settings.contentType, dataType: 'json' }) .done(json => { $('tbody', table).empty(); for (tr of json.data) $('tbody', table).append(tr); //Empty test if (!json.data.length) $('tbody', table).append('<tr><td class="empty" colspan="' + _ajaxTable[i].columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); // NO FILTER && NO SORT if (!_ajaxTable[i].activeSearch && (_ajaxTable[i].orderBy == settings.orderBy && _ajaxTable[i].orderSort == settings.orderSort)) { _ajaxTable[i].silentData["" + targetedPage] = json.data.map(e => htmlToElement(e)); if (settings.logging) console.log('ajaxTable recieved ' + json.data.length + ' items.'); } else { if (settings.logging) console.log('ajaxTable temporally recieved ' + json.data.length + ' items.'); } SlickLoader.disable(); resolve(json.total); }) .fail((_, textStatus, error) => { let err = "Request Failed: " + textStatus + ", " + error; console.log(_); console.log(err); SlickLoader.disable(); reject(err); }); // AJAX && NOT FULLY LOADED && STORED } else if (settings.source && !_ajaxTable[i].dataFullyLoaded && _ajaxTable[i].silentData[targetedPage]) { $('tbody', table).empty().append(_ajaxTable[i].silentData[targetedPage]); //Empty test if (!_ajaxTable[i].silentData[targetedPage].length) $('tbody', table).append('<tr><td class="empty" colspan="' + _ajaxTable[i].columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); resolve(_ajaxTable[i].total); } else { $('tbody', table).empty().append(_ajaxTable[i].filteredData.slice((targetedPage - 1) * 10, targetedPage * 10)); //Empty test if (!_ajaxTable[i].filteredData.slice((targetedPage - 1) * 10, targetedPage * 10).length) $('tbody', table).append('<tr><td class="empty" colspan="' + _ajaxTable[i].columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); resolve(_ajaxTable[i].filteredData.length); } }); dataGathering.then(items => { _ajaxTable[i].page = targetedPage; updateNav(pagination.parent(), targetedPage, Math.floor((items - 1) / 10) + 1, i); settings.onUpdate.call(undefined, table, _ajaxTable[i]); }).catch(error => { console.warn(error); alert(error); }); } function silentLoad(page, i, table) { settings.beforeAjax.call(undefined, table, _ajaxTable[i]); if (settings.logging) console.log('ajaxTable calling source...'); const data = { page: page, context: settings.sourceContext }; $.post({ url: settings.source, data: settings.contentType == 'application/json' ? JSON.stringify(data) : data, contentType: settings.contentType, dataType: 'json' }) .done(json => { _ajaxTable[i].silentData["" + page] = json.data.map(e => htmlToElement(e)); if (settings.logging) console.log('ajaxTable silently recieved ' + json.data.length + ' items. (page ' + page + ')'); if (page < (Math.floor((_ajaxTable[i].total - 1) / 10) + 1)) silentLoad(page + 1, i, table); else { _ajaxTable[i].dataFullyLoaded = true; if (settings.printButtons) { table.nextElementSibling.querySelector('.ajax-table-buttons-loader').classList.add('loaded'); table.nextElementSibling.querySelector('.ajax-table-buttons').classList.add('available'); } _ajaxTable[i].data = [].concat(...Object.values(_ajaxTable[i].silentData)); _ajaxTable[i].filteredData = _ajaxTable[i].data; $('tfoot input', table).filter((_, e) => e.value).each(function () { let index = $(this).parent().index(); _ajaxTable[i].filteredData = _ajaxTable[i].filteredData.filter(tr => tr.children[index].hasAttribute('data-search') ? tr.children[index].attr('data-search').toLowerCase().includes(this.value.toLowerCase()) || tr.children[index].innerText.toLowerCase().includes(this.value) : tr.children[index].innerText.toLowerCase().includes(this.value)); }); _ajaxTable[i].total = _ajaxTable[i].data.length; _ajaxTable[i].filteredTotal = _ajaxTable[i].filteredData.length; //TABLE READY if (settings.logging) console.log('ajaxTable is done with AJAX tasks.'); if (settings.logging) console.log('ajaxTable ready.'); settings.onReady.call(undefined, table, _ajaxTable[i]); } }) .fail((_, textStatus, error) => { let err = "Request Failed: " + textStatus + ", " + error; console.log(_); console.log(err); silentLoad(page, i, table); }); } function saveState(i) { localStorage.setItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_search', JSON.stringify(_ajaxTable[i].search)); localStorage.setItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_orderBy', JSON.stringify(_ajaxTable[i].orderBy)); localStorage.setItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_order', JSON.stringify(_ajaxTable[i].orderSort)); localStorage.setItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_expires', new Date().getTime() + 1000 * 60 * 60); } //MAIN LOOP this.each(function (i) { let that = this; $(this).addClass('ajax-table-processed'); //Basic settings let bundle = { orderBy: settings.orderBy, orderSort: settings.orderSort, search: [], activeSearch: false, searchPatterns: [], columns: $('thead th', that).length, page: 1, total: 1, filteredTotal: 1, printButtons: settings.printButtons, data: [], filteredData: [], silentData: {}, dataFullyLoaded: false }; bundle.data = $('tbody>tr', this).get(); bundle.filteredData = [...bundle.data]; //Search fields display if (!$('tfoot', this).length) $(this).append('<tfoot><tr></tr></tfoot>'); $('tfoot', this).insertAfter($('thead', this)); $('tfoot tr', this).empty(); $('thead th', this).each(function (_i) { $('tfoot tr', that).append('<td><input type="text" placeholder="' + ((settings.searchPlaceholders && settings.searchPlaceholders[_i]) ? settings.searchPlaceholders[_i] : lang.toLowerCase().includes('fr') ? "Entrée pour chercher" : "Enter to search") + '"></td>') }); bundle.search = $('tfoot input', that).get().map(e => e.value); settings.onStructureReady.call(undefined, this, _ajaxTable[i]); if (settings.logging) console.log('ajaxTable structure ready...'); //Only keep 10 items shown if (bundle.data.length > 10) { $('tbody>tr:nth-of-type(n+11)', this).remove(); } let dataReady = new Promise((resolve, reject) => { //Load items from AJAX if (settings.source) { settings.beforeAjax.call(undefined, that, bundle); if (settings.logging) console.log('ajaxTable calling source...'); SlickLoader.enable(); const data = { total: true, context: settings.sourceContext }; $.post({ url: settings.source, data: settings.contentType == 'application/json' ? JSON.stringify(data) : data, dataType: 'json', contentType: settings.contentType }) .done(json => { $('tbody', this).empty(); for (tr of json.data) $('tbody', this).append(tr); //Empty test if (!json.data.length) $('tbody', this).append('<tr><td class="empty" colspan="' + bundle.columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); bundle.data = json.data.map(e => htmlToElement(e)); bundle.filteredData = [...bundle.data]; bundle.silentData["1"] = [...bundle.data]; bundle.total = json.total; bundle.filteredTotal = json.total; bundle.searchPatterns = $('tbody tr:nth-of-type(1) td', that).get().map(e => e.getAttribute('data-search-template')); if (settings.logging) console.log('ajaxTable recieved ' + json.data.length + ' items.'); SlickLoader.disable(); resolve(); }) .fail((_, textStatus, error) => { let err = "Request Failed: " + textStatus + ", " + error; console.log(_); console.log(err); SlickLoader.disable(); reject(err); }); } else { bundle.total = bundle.data.length; bundle.filteredTotal = bundle.filteredData.length; resolve(); } }); dataReady.then(_ => { //Store table bundle _ajaxTable.push(bundle); i = _ajaxTable.length - 1; //INITIAL SORTING DISPLAY let orderedColumn = $('thead th', that).eq(_ajaxTable[i].orderBy); orderedColumn.addClass('sorted'); if (_ajaxTable[i].orderSort == 'asc') orderedColumn.addClass('inverted'); //PAGINATION let pagination = $('<aside class="ajax-table-pagination"><ul><li class="pagination-prev disabled">&laquo;</li><li class="pagination-next">&raquo;</li></ul></aside>'); let pageCount = Math.floor((_ajaxTable[i].total - 1) / 10) + 1; //COUNT DISPLAY let count = $('<aside class="ajax-table-count"><div>' + (lang.toLowerCase().includes('fr') ? "Elements" : "Items") + ' <span id="ajax-table-item-start-id"></span> ' + (lang.toLowerCase().includes('fr') ? "à" : "to") + ' <span id="ajax-table-item-end-id"></span> ' + (lang.toLowerCase().includes('fr') ? "sur" : "of") + ' <span id="ajax-table-item-filtered-total"></span> (<span id="ajax-table-item-total"></span> ' + (lang.toLowerCase().includes('fr') ? "au total" : "total") + ')</div></aside>'); //PRINT BUTTONS let utilities = $('<div class="ajax-table-utilities"></div>'); if (settings.printButtons) utilities.append('<aside class="ajax-table-buttons-loader"><div></div></aside>'); if (settings.printButtons) utilities.append('<aside class="ajax-table-buttons"><ul><li class="export">Excel</li><li class="export">CSV</li><li class="export">PDF</li></ul></aside>'); utilities.append(count); utilities.append(pagination); $(this).after(utilities); updateNav(utilities, 1, pageCount, i); //Pagination click handlers pagination.on('click', 'li.pagination-page:not(.active)', function () { let targetedPage = +$(this).attr('data-page'); paginationHandler(that, i, targetedPage, pagination, pageCount); }); pagination.on('click', 'li.pagination-prev:not(.disabled),li.pagination-next:not(.disabled)', function () { let targetedPage = +$(this).siblings('.active').attr('data-page'); if ($(this).is('.pagination-prev')) targetedPage--; else targetedPage++; paginationHandler(that, i, targetedPage, pagination, pageCount); }); //Print click handlers if (settings.printButtons) { utilities.on('click', '.ajax-table-buttons li', function () { SlickLoader.enable(); const table = document.createElement('table'), tbody = document.createElement('tbody'); table.appendChild($('thead', that).clone()[0]); table.appendChild(tbody); _ajaxTable[i].filteredData.forEach(line => { tbody.appendChild($(line).clone()[0]); }); switch ($(this).index()) { case 0: $(table).excelExport(); break; case 1: $(table).csvExport(); break; case 2: let iframe = $('<iframe class="excel-export" style="visibility: hidden; position: absolute; top:0; right:0;"></iframe>').appendTo('body'); iframe.contents().find('body').append(table); iframe.contents().find('head').append('<link rel="stylesheet" href="https://unpkg.com/ajax-table/ajaxTable.min.css">'); if (typeof window.onafterprint == 'undefined') { setTimeout(() => { iframe.remove(); }, 500) } else { iframe[0].contentWindow.onafterprint = () => { iframe.remove(); }; } iframe[0].contentWindow.print(); break; default: break; } SlickLoader.disable(); }); } //Sorting handler $('thead th', this).on('click', function () { if ($(this).is('.sorted')) { $(this).toggleClass('inverted'); } else { $(this).addClass('sorted').siblings().removeClass('sorted inverted'); } let order = $(this).hasClass('inverted') ? 1 : -1; _ajaxTable[i].orderBy = $(this).index(); _ajaxTable[i].orderSort = order == 1 ? 'asc' : 'desc'; _ajaxTable[i].page = 1; let sortingPromise = new Promise((resolve, reject) => { if (settings.source && !_ajaxTable[i].dataFullyLoaded) { settings.beforeAjax.call(undefined, that, _ajaxTable[i]); if (settings.logging) console.log('ajaxTable calling source...'); SlickLoader.enable(); const data = { page: _ajaxTable[i].page, orderBy: _ajaxTable[i].orderBy, order: _ajaxTable[i].orderSort, search: _ajaxTable[i].search, searchPatterns: _ajaxTable[i].searchPatterns, columns: _ajaxTable[i].columns, context: settings.sourceContext }; $.post({ url: settings.source, data: settings.contentType == 'application/json' ? JSON.stringify(data) : data, contentType: settings.contentType, dataType: 'json' }) .done(json => { $('tbody', that).empty(); for (tr of json.data) $('tbody', that).append(tr); //Empty test if (!json.data.length) $('tbody', that).append('<tr><td class="empty" colspan="' + _ajaxTable[i].columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); if (settings.logging) console.log('ajaxTable temporally recieved ' + json.data.length + ' items.'); updateNav(utilities, 1, pageCount, i); SlickLoader.disable(); resolve(); }) .fail((_, textStatus, error) => { let err = "Request Failed: " + textStatus + ", " + error; console.log(_); console.log(err); SlickLoader.disable(); reject(err); }); } else { let index = $(this).index(); _ajaxTable[i].filteredData = mergeSort(_ajaxTable[i].filteredData, (a, b) => { let $a_dataOrder = a.children[index].getAttribute('data-order'); let $b_dataOrder = b.children[index].getAttribute('data-order'); let $a_text = a.children[index].innerText; let $b_text = b.children[index].innerText; return a.children[index].hasAttribute('data-order') ? !isNaN($a_dataOrder) ? (+$a_dataOrder > +$b_dataOrder ? order : +$a_dataOrder == +$b_dataOrder ? 0 : -order) : $a_dataOrder.localeCompare($b_dataOrder) * order : !isNaN($a_text) ? (+$a_text > +$b_text ? order : +$a_text == +$b_text ? 0 : -order) : $a_text.localeCompare($b_text) * order; }); updateTable(that, i); resolve(); } }); sortingPromise.then(() => { saveState(i); settings.onUpdate.call(undefined, that, _ajaxTable[i]); }).catch(error => { console.warn(error); alert(error); }); }); //Search handler $('tfoot input', this).on('keyup blur', function (e) { if ((e.keyCode == 13 || e.type == 'blur') && this.value != _ajaxTable[i].search[$(this).parent().index()]) { _ajaxTable[i].search[$(this).parent().index()] = this.value; _ajaxTable[i].activeSearch = !!_ajaxTable[i].search.filter(e => e.length).length; _ajaxTable[i].page = 1; let searchPromise = new Promise((resolve, reject) => { if (settings.source && !_ajaxTable[i].dataFullyLoaded) { settings.beforeAjax.call(undefined, that, _ajaxTable[i]); if (settings.logging) console.log('ajaxTable calling source...'); SlickLoader.enable(); const data = { page: _ajaxTable[i].page, orderBy: _ajaxTable[i].orderBy, order: _ajaxTable[i].orderSort, search: _ajaxTable[i].search, searchPatterns: _ajaxTable[i].searchPatterns, columns: _ajaxTable[i].columns, total: true, context: settings.sourceContext }; $.post({ url: settings.source, data: settings.contentType == 'application/json' ? JSON.stringify(data) : data, contentType: settings.contentType, dataType: 'json' }) .done(json => { $('tbody', that).empty(); for (tr of json.data) $('tbody', that).append(tr); //Empty test if (!json.data.length) $('tbody', that).append('<tr><td class="empty" colspan="' + _ajaxTable[i].columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); if (settings.logging) console.log('ajaxTable temporally recieved ' + json.data.length + ' items.'); _ajaxTable[i].filteredTotal = json.total; updateNav(utilities, _ajaxTable[i].page, Math.floor((json.total - 1) / 10) + 1, i); SlickLoader.disable(); resolve(); }) .fail((_, textStatus, error) => { let err = "Request Failed: " + textStatus + ", " + error; console.log(_); console.log(err); SlickLoader.disable(); reject(err); }); } else { _ajaxTable[i].filteredData = _ajaxTable[i].data; Array.from(that.querySelectorAll('tfoot input')).filter(search => search.value).forEach(filter => { let index = Array.from(filter.parentElement.parentElement.children).indexOf(filter.parentElement); // Wildcard search if (filter.value.includes('*')) { let regex = new RegExp(filter.value.toLowerCase().split('*').map(s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('.*').replace(/\s+/g, '\\s+'), 's'); _ajaxTable[i].filteredData = _ajaxTable[i].filteredData.filter(tr => tr.children[index].hasAttribute('data-search') ? regex.test(tr.children[index].attr('data-search').toLowerCase()) || regex.test(tr.children[index].innerText.toLowerCase()) : regex.test(tr.children[index].innerText.toLowerCase())); } else { _ajaxTable[i].filteredData = _ajaxTable[i].filteredData.filter(tr => tr.children[index].hasAttribute('data-search') ? tr.children[index].attr('data-search').toLowerCase().includes(filter.value.toLowerCase()) || tr.children[index].innerText.toLowerCase().includes(filter.value.toLowerCase()) : tr.children[index].innerText.toLowerCase().includes(filter.value.toLowerCase())); } }); _ajaxTable[i].filteredTotal = _ajaxTable[i].filteredData.length; updateTable(that, i); resolve(); } }); searchPromise.then(() => { saveState(i); settings.onUpdate.call(undefined, that, _ajaxTable[i]); }).catch(error => { console.warn(error); alert(error); }); } }); settings.onUpdate.call(undefined, that, _ajaxTable[i]); //Reuse user's last sort + filter let storageExpiresAt = localStorage.getItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_expires'); if (storageExpiresAt) { if (new Date().getTime() < storageExpiresAt) { _ajaxTable[i].search = JSON.parse(localStorage.getItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_search')); _ajaxTable[i].orderBy = +JSON.parse(localStorage.getItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_orderBy')); _ajaxTable[i].orderSort = JSON.parse(localStorage.getItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_order')); //Displays searches $('tfoot input', that).each(function (j) { this.value = _ajaxTable[i].search[j] ? _ajaxTable[i].search[j] : ''; }); _ajaxTable[i].activeSearch = !!_ajaxTable[i].search.filter(e => e.length).length; //Displays sorting $('thead th', that).removeClass('sorted inverted'); let orderedColumn = $('thead th', that).eq(_ajaxTable[i].orderBy); orderedColumn.addClass('sorted'); if (_ajaxTable[i].orderSort == 'asc') orderedColumn.addClass('inverted'); if (settings.source && !_ajaxTable[i].dataFullyLoaded) { settings.beforeAjax.call(undefined, that, _ajaxTable[i]); if (settings.logging) console.log('ajaxTable calling source...'); SlickLoader.enable(); const data = { page: _ajaxTable[i].page, orderBy: _ajaxTable[i].orderBy, order: _ajaxTable[i].orderSort, search: _ajaxTable[i].search, searchPatterns: _ajaxTable[i].searchPatterns, columns: _ajaxTable[i].columns, total: true, context: settings.sourceContext }; $.post({ url: settings.source, data: settings.contentType == 'application/json' ? JSON.stringify(data) : data, contentType: settings.contentType, dataType: 'json' }) .done(json => { $('tbody', that).empty(); for (tr of json.data) $('tbody', that).append(tr); //Empty test if (!json.data.length) $('tbody', that).append('<tr><td class="empty" colspan="' + _ajaxTable[i].columns + '">' + (lang.toLowerCase().includes('fr') ? "Aucune donnée disponible dans le tableau" : "No data available") + '</td></tr>'); if (settings.logging) console.log('ajaxTable temporally recieved ' + json.data.length + ' items.'); _ajaxTable[i].page = 1; _ajaxTable[i].filteredTotal = json.total; updateNav(utilities, _ajaxTable[i].page, Math.floor((json.total - 1) / 10) + 1, i); SlickLoader.disable(); settings.onUpdate.call(undefined, that, _ajaxTable[i]); }) .fail((_, textStatus, error) => { let err = "Request Failed: " + textStatus + ", " + error; console.log(_); console.log(err); SlickLoader.disable(); }); } else { _ajaxTable[i].filteredData = _ajaxTable[i].data; _ajaxTable[i].page = 1; $('tfoot input', that).filter((_, e) => e.value).each(function () { let index = $(this).parent().index(); _ajaxTable[i].filteredData = _ajaxTable[i].filteredData.filter(tr => tr.children[index].hasAttribute('data-search') ? tr.children[index].attr('data-search').toLowerCase().includes(this.value.toLowerCase()) || tr.children[index].innerText.toLowerCase().includes(this.value) : tr.children[index].innerText.toLowerCase().includes(this.value)); }); _ajaxTable[i].filteredTotal = _ajaxTable[i].filteredData.length; updateTable(that, i); settings.onUpdate.call(undefined, that, _ajaxTable[i]); } } else { localStorage.removeItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_search'); localStorage.removeItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_orderBy'); localStorage.removeItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_order'); localStorage.removeItem(window.location.hostname + window.location.pathname + '_ajaxTable_' + i + '_expires'); storageExpiresAt = null; } } if (Math.floor((_ajaxTable[i].total - 1) / 10) + 1 > 1 && settings.source) silentLoad(2, i, that); else { _ajaxTable[i].dataFullyLoaded = true; if (settings.printButtons) { utilities[0].querySelector('.ajax-table-buttons').classList.add('available'); utilities[0].querySelector('.ajax-table-buttons-loader').classList.add('loaded'); } //TABLE READY if (settings.logging) console.log('ajaxTable ready.'); settings.onReady.call(undefined, that, _ajaxTable[i]); } }).catch(error => { console.warn(error); alert(error); }); }); return this; } }); })(jQuery);