# blockenberg/2.0.7/blocks/data-table/frontend.js

Blockenberg — 600+ Advanced Gutenberg Blocks &amp; AI Agent for WordPress Block Editor, version 2.0.7. 273 lines.

- Page: https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/data-table/frontend.js
- Raw: https://pluginprobe.com/plugins/blockenberg/2.0.7/raw/blocks/data-table/frontend.js
- Modified: 2026-03-06T12:32:40+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/data-table/frontend.js#L10-L20`.

```javascript
(function () {
    'use strict';

    function toArray(nl) {
        return Array.prototype.slice.call(nl || []);
    }

    function initDataTable(wrap) {
        var searchInput = wrap.querySelector('[data-search]');
        var table = wrap.querySelector('.bkbg-dt-table');
        var thead = table ? table.querySelector('.bkbg-dt-thead') : null;
        var tbody = table ? table.querySelector('.bkbg-dt-tbody') : null;
        var headers = thead ? toArray(thead.querySelectorAll('.bkbg-dt-th')) : [];
        var allRows = tbody ? toArray(tbody.querySelectorAll('.bkbg-dt-tr')) : [];

        var sortable = wrap.getAttribute('data-sortable') === '1';
        var paginate = wrap.getAttribute('data-paginate') === '1';
        var perPage = parseInt(wrap.getAttribute('data-per-page'), 10) || 10;

        var currentSort = { col: -1, dir: 'asc' };
        var currentPage = 1;
        var filteredRows = allRows.slice();

        // Search functionality
        function filterRows(query) {
            query = (query || '').toLowerCase().trim();
            if (!query) {
                filteredRows = allRows.slice();
            } else {
                filteredRows = allRows.filter(function (row) {
                    var text = row.textContent.toLowerCase();
                    return text.indexOf(query) !== -1;
                });
            }
            currentPage = 1;
            render();
        }

        // Sort functionality
        function sortRows(colIndex) {
            if (currentSort.col === colIndex) {
                currentSort.dir = currentSort.dir === 'asc' ? 'desc' : 'asc';
            } else {
                currentSort.col = colIndex;
                currentSort.dir = 'asc';
            }

            // Update header UI
            headers.forEach(function (th, i) {
                th.removeAttribute('data-sort');
                if (i === colIndex) {
                    th.setAttribute('data-sort', currentSort.dir);
                }
            });

            filteredRows.sort(function (a, b) {
                var cellA = a.children[colIndex];
                var cellB = b.children[colIndex];
                if (!cellA || !cellB) return 0;

                var valA = cellA.textContent.trim();
                var valB = cellB.textContent.trim();

                // Try numeric sort
                var numA = parseFloat(valA.replace(/[^0-9.-]/g, ''));
                var numB = parseFloat(valB.replace(/[^0-9.-]/g, ''));

                if (!isNaN(numA) && !isNaN(numB)) {
                    return currentSort.dir === 'asc' ? numA - numB : numB - numA;
                }

                // String sort
                var cmp = valA.localeCompare(valB);
                return currentSort.dir === 'asc' ? cmp : -cmp;
            });

            currentPage = 1;
            render();
        }

        // Pagination
        function renderPagination() {
            var existing = wrap.querySelector('.bkbg-dt-pagination');
            if (existing) existing.remove();

            if (!paginate || filteredRows.length <= perPage) return;

            var totalPages = Math.ceil(filteredRows.length / perPage);
            var pagination = document.createElement('div');
            pagination.className = 'bkbg-dt-pagination';

            // Previous button
            var prevBtn = document.createElement('button');
            prevBtn.className = 'bkbg-dt-page-btn';
            prevBtn.textContent = '←';
            prevBtn.disabled = currentPage === 1;
            prevBtn.addEventListener('click', function () {
                if (currentPage > 1) {
                    currentPage--;
                    render();
                }
            });
            pagination.appendChild(prevBtn);

            // Page buttons
            var startPage = Math.max(1, currentPage - 2);
            var endPage = Math.min(totalPages, startPage + 4);
            if (endPage - startPage < 4) {
                startPage = Math.max(1, endPage - 4);
            }

            for (var i = startPage; i <= endPage; i++) {
                (function (page) {
                    var btn = document.createElement('button');
                    btn.className = 'bkbg-dt-page-btn' + (page === currentPage ? ' is-active' : '');
                    btn.textContent = page;
                    btn.addEventListener('click', function () {
                        currentPage = page;
                        render();
                    });
                    pagination.appendChild(btn);
                })(i);
            }

            // Next button
            var nextBtn = document.createElement('button');
            nextBtn.className = 'bkbg-dt-page-btn';
            nextBtn.textContent = '→';
            nextBtn.disabled = currentPage === totalPages;
            nextBtn.addEventListener('click', function () {
                if (currentPage < totalPages) {
                    currentPage++;
                    render();
                }
            });
            pagination.appendChild(nextBtn);

            // Info
            var info = document.createElement('span');
            info.className = 'bkbg-dt-page-info';
            var start = (currentPage - 1) * perPage + 1;
            var end = Math.min(currentPage * perPage, filteredRows.length);
            info.textContent = start + '-' + end + ' of ' + filteredRows.length;
            pagination.appendChild(info);

            wrap.appendChild(pagination);
        }

        // Render visible rows
        function render() {
            if (!tbody) return;

            // Reorder DOM elements to match sorted order
            filteredRows.forEach(function (row) {
                tbody.appendChild(row);
            });

            // Hide all rows first
            allRows.forEach(function (row) {
                row.style.display = 'none';
            });

            // Show filtered & paginated
            var start = paginate ? (currentPage - 1) * perPage : 0;
            var end = paginate ? start + perPage : filteredRows.length;

            for (var i = start; i < end && i < filteredRows.length; i++) {
                filteredRows[i].style.display = '';
            }

            // Empty state
            var emptyEl = wrap.querySelector('.bkbg-dt-empty');
            if (filteredRows.length === 0) {
                if (!emptyEl) {
                    emptyEl = document.createElement('div');
                    emptyEl.className = 'bkbg-dt-empty';
                    emptyEl.textContent = 'No results found';
                    wrap.querySelector('.bkbg-dt-container').appendChild(emptyEl);
                }
                emptyEl.style.display = '';
            } else if (emptyEl) {
                emptyEl.style.display = 'none';
            }

            renderPagination();
        }

        // Export to CSV
        function exportCsv() {
            function csvCell(text) {
                var s = String(text == null ? '' : text);
                // Normalize whitespace/newlines for CSV rows.
                s = s.replace(/\r?\n/g, ' ').trim();
                // Prevent Excel/Sheets formula injection when opening CSV.
                // See: values starting with = + - @ can be treated as formulas.
                if (/^[=+\-@]/.test(s)) {
                    s = "'" + s;
                }
                s = s.replace(/"/g, '""');
                return '"' + s + '"';
            }

            var headerRow = headers.map(function (th) {
                return csvCell(th.textContent);
            }).join(',');

            var dataRows = filteredRows.map(function (row) {
                return toArray(row.children).map(function (td) {
                    return csvCell(td.textContent);
                }).join(',');
            });

            var csv = [headerRow].concat(dataRows).join('\n');
            var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
            var url = URL.createObjectURL(blob);
            var link = document.createElement('a');
            link.href = url;
            link.download = 'table-data.csv';
            link.click();
            URL.revokeObjectURL(url);
        }

        // Event listeners
        if (searchInput) {
            var debounceTimer;
            searchInput.addEventListener('input', function () {
                clearTimeout(debounceTimer);
                debounceTimer = setTimeout(function () {
                    filterRows(searchInput.value);
                }, 200);
            });
        }

        if (sortable) {
            headers.forEach(function (th, index) {
                th.addEventListener('click', function () {
                    sortRows(index);
                });
                th.style.cursor = 'pointer';
            });
        }

        var exportBtn = wrap.querySelector('[data-export="csv"]');
        if (exportBtn) {
            exportBtn.addEventListener('click', function (e) {
                e.preventDefault();
                exportCsv();
            });
        }

        // Initial render
        render();
    }

    function init() {
        var tables = document.querySelectorAll('.bkbg-dt-wrap:not([data-initialized])');
        for (var i = 0; i < tables.length; i++) {
            tables[i].setAttribute('data-initialized', '1');
            initDataTable(tables[i]);
        }
    }

    // Initialize on DOMContentLoaded
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    // Also try on window load as fallback
    window.addEventListener('load', init);
})();

```
