Updated
This commit is contained in:
@@ -1,8 +1,156 @@
|
|||||||
/* assoc_profile — v0.1.0 */
|
/* 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 () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
function init() {
|
|
||||||
// TODO: progressive enhancement for profile edit form if needed
|
// ----------------------------------------------------------------
|
||||||
|
// 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();
|
||||||
}
|
}
|
||||||
document.addEventListener('DOMContentLoaded', init);
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user