/* assoc_profile — v0.2.0 Client-side search, filter, pagination, and bulk select for the manage index. No dependencies beyond Bootstrap 5 (already loaded by Hubzilla). */ (function () { 'use strict'; // ---------------------------------------------------------------- // MANAGE INDEX — search, filter, paginate, bulk select // ---------------------------------------------------------------- var PAGE_SIZE = 25; function initManageIndex() { var table = document.getElementById('assoc-manage-table'); if (!table) return; var rows = Array.from(table.querySelectorAll('tbody tr[data-slug]')); var searchInput = document.getElementById('assoc-search'); var filterCounty = document.getElementById('assoc-filter-county'); var filterType = document.getElementById('assoc-filter-type'); var filterStatus = document.getElementById('assoc-filter-status'); var pageInfo = document.getElementById('assoc-page-info'); var prevBtn = document.getElementById('assoc-page-prev'); var nextBtn = document.getElementById('assoc-page-next'); var selectAll = document.getElementById('assoc-select-all'); var bulkBar = document.getElementById('assoc-bulk-bar'); var bulkCount = document.getElementById('assoc-bulk-count'); var exportBtn = document.getElementById('assoc-export-selected'); var currentPage = 1; var filtered = rows.slice(); function getRowText(row) { return (row.dataset.slug + ' ' + row.dataset.name + ' ' + (row.dataset.county || '')).toLowerCase(); } function applyFilters() { var q = searchInput ? searchInput.value.toLowerCase().trim() : ''; var county = filterCounty ? filterCounty.value : ''; var type = filterType ? filterType.value : ''; var status = filterStatus ? filterStatus.value : ''; filtered = rows.filter(function (row) { if (q && getRowText(row).indexOf(q) === -1) return false; if (county && row.dataset.county !== county) return false; if (type && row.dataset.type !== type) return false; if (status && row.dataset.status !== status) return false; return true; }); currentPage = 1; render(); } function render() { var total = filtered.length; var pages = Math.max(1, Math.ceil(total / PAGE_SIZE)); currentPage = Math.min(currentPage, pages); var start = (currentPage - 1) * PAGE_SIZE; var end = Math.min(start + PAGE_SIZE, total); rows.forEach(function (row) { row.style.display = 'none'; }); filtered.slice(start, end).forEach(function (row) { row.style.display = ''; }); if (pageInfo) { pageInfo.textContent = total === 0 ? 'No associations found' : 'Showing ' + (start + 1) + '–' + end + ' of ' + total; } if (prevBtn) prevBtn.disabled = currentPage <= 1; if (nextBtn) nextBtn.disabled = currentPage >= pages; } function updateBulkBar() { if (!bulkBar) return; var checked = table.querySelectorAll('tbody input[name="assoc_select[]"]:checked'); var n = checked.length; bulkBar.style.display = n > 0 ? 'flex' : 'none'; if (bulkCount) bulkCount.textContent = n + ' selected'; } // Event wiring if (searchInput) searchInput.addEventListener('input', applyFilters); if (filterCounty) filterCounty.addEventListener('change', applyFilters); if (filterType) filterType.addEventListener('change', applyFilters); if (filterStatus) filterStatus.addEventListener('change', applyFilters); if (prevBtn) prevBtn.addEventListener('click', function () { if (currentPage > 1) { currentPage--; render(); } }); if (nextBtn) nextBtn.addEventListener('click', function () { var pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE)); if (currentPage < pages) { currentPage++; render(); } }); if (selectAll) { selectAll.addEventListener('change', function () { var visible = table.querySelectorAll('tbody tr[data-slug]:not([style*="none"]) input[name="assoc_select[]"]'); visible.forEach(function (cb) { cb.checked = selectAll.checked; }); updateBulkBar(); }); } table.addEventListener('change', function (e) { if (e.target.name === 'assoc_select[]') updateBulkBar(); }); if (exportBtn) { exportBtn.addEventListener('click', function () { var checked = Array.from(table.querySelectorAll('tbody input[name="assoc_select[]"]:checked')); var slugs = checked.map(function (cb) { return cb.value; }); if (!slugs.length) return; var form = document.getElementById('assoc-export-form'); if (!form) return; document.getElementById('assoc-export-slugs').value = slugs.join(','); form.submit(); }); } render(); } // ---------------------------------------------------------------- // DIFF VIEW — confirm/skip per entry // ---------------------------------------------------------------- function initDiffView() { var container = document.getElementById('assoc-diff-container'); if (!container) return; container.addEventListener('change', function (e) { if (e.target.name === 'diff_action[]') { var entry = e.target.closest('.assoc-diff-entry'); if (!entry) return; if (e.target.value === 'skip') { entry.style.opacity = '0.45'; } else { entry.style.opacity = '1'; } } }); } // ---------------------------------------------------------------- // INIT // ---------------------------------------------------------------- document.addEventListener('DOMContentLoaded', function () { initManageIndex(); initDiffView(); }); })();