1(function($) { 2 'use strict'; 3 4 $(document).ready(function() { 5 $('.type-approval-devices-wrapper').each(function() { 6 var wrapper = $(this); 7 var table = wrapper.find('table'); 8 var tbody = table.find('tbody'); 9 var allRows = tbody.find('tr'); 10 11 // If no data, exit 12 if (allRows.length === 0) { 13 return; 14 } 15 16 // Store all rows 17 var allData = []; 18 allRows.each(function() { 19 var $row = $(this); 20 var rowData = []; 21 $row.find('td').each(function() { 22 rowData.push($(this).text().trim().toLowerCase()); 23 }); 24 allData.push({ 25 element: $row.clone(), 26 data: rowData 27 }); 28 }); 29 30 // Search functionality 31 wrapper.find('.search-input').on('keyup', function() { 32 var searchTerm = $(this).val().toLowerCase().trim(); 33 filterTable(searchTerm); 34 }); 35 36 // Show entries functionality 37 wrapper.find('.entries-select').on('change', function() { 38 var perPage = parseInt($(this).val()); 39 wrapper.data('per-page', perPage); 40 filterTable(wrapper.data('search-term') || ''); 41 }); 42 43 // Sort functionality 44 table.find('thead th.sortable').on('click', function() { 45 var columnIndex = $(this).index(); 46 var currentSort = $(this).data('sort') || 'asc'; 47 48 // Reset all 49 table.find('thead th').removeClass('sort-asc sort-desc'); 50 51 if (currentSort === 'asc') { 52 $(this).data('sort', 'desc'); 53 $(this).addClass('sort-desc'); 54 } else { 55 $(this).data('sort', 'asc'); 56 $(this).addClass('sort-asc'); 57 } 58 59 wrapper.data('sort-column', columnIndex); 60 wrapper.data('sort-direction', $(this).data('sort')); 61 filterTable(wrapper.data('search-term') || ''); 62 }); 63 64 // Download functionality 65 wrapper.find('.download-btn').on('click', function(e) { 66 e.preventDefault(); 67 68 var dataType = wrapper.data('type') || 'data'; 69 var csv = []; 70 71 // Headers 72 var headers = []; 73 table.find('thead tr th').each(function() { 74 var text = $(this).text().trim().replace(/[âââ]/g, '').trim(); 75 headers.push(text); 76 }); 77 csv.push(headers.join(',')); 78 79 // Data 80 allData.forEach(function(item) { 81 var row = []; 82 item.element.find('td').each(function() { 83 var text = $(this).text().trim(); 84 if (text.indexOf(',') > -1 || text.indexOf('"') > -1) { 85 text = '"' + text.replace(/"/g, '""') + '"'; 86 } 87 row.push(text); 88 }); 89 csv.push(row.join(',')); 90 }); 91 92 // Download 93 var blob = new Blob(["\uFEFF" + csv.join('\n')], { type: 'text/csv;charset=utf-8;' }); 94 var link = document.createElement('a'); 95 link.href = URL.createObjectURL(blob); 96 link.download = 'type_approval_' + dataType + '_' + new Date().toISOString().slice(0,10) + '.csv'; 97 document.body.appendChild(link); 98 link.click(); 99 document.body.removeChild(link); 100 }); 101 102 // Filter function 103 function filterTable(searchTerm) { 104 var perPage = parseInt(wrapper.data('per-page')) || 25; 105 var sortColumn = wrapper.data('sort-column'); 106 var sortDirection = wrapper.data('sort-direction'); 107 108 // Filter 109 var filteredData = allData; 110 if (searchTerm) { 111 filteredData = allData.filter(function(item) { 112 return item.data.some(function(value) { 113 return value.indexOf(searchTerm) !== -1; 114 }); 115 }); 116 } 117 118 // Sort 119 if (sortColumn !== undefined && sortDirection) { 120 filteredData.sort(function(a, b) { 121 var valA = a.data[sortColumn] || ''; 122 var valB = b.data[sortColumn] || ''; 123 return sortDirection === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA); 124 }); 125 } 126 127 // Paginate 128 var totalRecords = filteredData.length; 129 var totalPages = Math.ceil(totalRecords / perPage); 130 var currentPage = 1; 131 var startIndex = 0; 132 var endIndex = Math.min(perPage, totalRecords); 133 var pageData = filteredData.slice(startIndex, endIndex); 134 135 // Update table 136 tbody.empty(); 137 if (pageData.length === 0) { 138 var colCount = table.find('thead th').length; 139 tbody.append('<tr><td colspan="' + colCount + '" style="text-align:center;padding:20px;">
139No matching records found</td></tr>'); 140 } else { 141 pageData.forEach(function(item) { 142 tbody.append(item.element.clone()); 143 }); 144 } 145 146 // Update pagination info 147 var infoText = wrapper.find('.pagination-info'); 148 if (totalRecords > 0) { 149 infoText.html('Showing <strong>1</strong> to <strong>' + Math.min(perPage, totalRecords) + '</strong> of <strong>' + totalRecords + '</strong> entries'); 150 } else { 151 infoText.html('Showing <strong>0</strong> to <strong>0</strong> of <strong>0</strong> entries'); 152 } 153 154 // Simple pagination links 155 var paginationContainer = wrapper.find('.pagination-links'); 156 paginationContainer.empty(); 157 158 if (totalPages > 1) { 159 // Previous 160 var prevLink = $('<a>').addClass('page-link prev disabled').html('Previous'); 161 paginationContainer.append(prevLink); 162 163 // Page 1 164 var pageLink = $('<a>').addClass('page-link active').text('1'); 165 paginationContainer.append(pageLink); 166 167 if (totalPages > 1) { 168 var ellipsis = $('<span>').addClass('pagination-ellipsis').text('...'); 169 paginationContainer.append(ellipsis); 170 171 var lastLink = $('<a>').addClass('page-link').text(totalPages); 172 lastLink.on('click', function(e) { 173 e.preventDefault(); 174 // Simple: just show all data on last page 175 tbody.empty(); 176 filteredData.forEach(function(item) { 177 tbody.append(item.element.clone()); 178 }); 179 wrapper.find('.pagination-info').html('Showing <strong>' + ((totalPages-1) * perPage + 1) + '</strong> to <strong>' + totalRecords + '</strong> of <strong>' + totalRecords + '</strong> entries'); 180 $(this).addClass('active'); 181 pageLink.removeClass('active'); 182 }); 183 paginationContainer.append(lastLink); 184 } 185 186 // Next 187 var nextLink = $('<a>').addClass('page-link next').html('Next'); 188 nextLink.on('click', function(e) { 189 e.preventDefault(); 190 // Show last page 191 var start = (totalPages - 1) * perPage; 192 var pageData = filteredData.slice(start); 193 tbody.empty(); 194 pageData.forEach(function(item) { 195 tbody.append(item.element.clone()); 196 }); 197 wrapper.find('.pagination-info').html('Showing <strong>' + (start + 1) + '</strong> to <strong>' + totalRecords + '</strong> of <strong>' + totalRecords + '</strong> entries'); 198 paginationContainer.find('.page-link').removeClass('active'); 199 paginationContainer.find('.page-link:last').addClass('active'); 200 }); 201 paginationContainer.append(nextLink); 202 } 203 } 204 205 // Initialize 206 wrapper.data('per-page', 25); 207 wrapper.data('search-term', ''); 208 filterTable(''); 209 }); 210 }); 211})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.