Files

239 lines
7.7 KiB
JavaScript

(() => {
function init() {
const table = document.getElementById('asset-table');
if (!table || table.dataset.columnManagerReady === '1') return;
table.dataset.columnManagerReady = '1';
const scroll = document.getElementById('asset-table-scroll');
const topScroll = document.getElementById('asset-table-scroll-top');
const topInner = topScroll?.firstElementChild;
const dialog = document.getElementById('column-settings-dialog');
const list = document.getElementById('column-settings-list');
const openButton = document.getElementById('column-settings-button');
const showAllButton = document.getElementById('show-all-columns');
const resetButton = document.getElementById('reset-columns');
const menu = document.getElementById('column-context-menu');
const hideMenuButton = document.getElementById('context-hide-column');
const openMenuButton = document.getElementById('context-open-columns');
const keyBase = table.dataset.storageKey || 'asset-columns-all';
const hiddenKey = `${keyBase}-hidden`;
const styleId = `asset-column-visibility-${keyBase.replace(/[^a-zA-Z0-9_-]/g, '-')}`;
let contextField = null;
let resizeFrame = 0;
let lastContainerWidth = -1;
const headers = () =>
[...table.querySelectorAll('thead tr:first-child th[data-field]')];
const fieldLabel = field => {
const th = table.querySelector(
`thead tr:first-child th[data-field="${CSS.escape(field)}"]`
);
return th?.dataset.label || th?.textContent?.trim() || field;
};
const allFields = () => headers().map(th => th.dataset.field);
function getHidden() {
try {
const value = JSON.parse(window.AssetBrowserState?.get(hiddenKey) || '[]');
return Array.isArray(value) ? value : [];
} catch (_) {
return [];
}
}
function setHidden(fields) {
window.AssetBrowserState?.set(hiddenKey, JSON.stringify([...new Set(fields)]));
}
function columnWidth(header) {
const configured = Number.parseInt(header.dataset.columnWidth || '', 10);
return Number.isFinite(configured) && configured > 0 ? configured : 180;
}
function visibleTableWidth(hidden) {
const fieldWidth = headers().reduce(
(sum, header) =>
hidden.has(header.dataset.field) ? sum : sum + columnWidth(header),
0
);
const fixedWidth = Number.parseInt(table.dataset.fixedColumnWidth || '224', 10);
return Math.max(640, fieldWidth + fixedWidth);
}
function updateTopScrollbar(tableWidth) {
if (!scroll || !topScroll || !topInner) return;
topInner.style.width = `${tableWidth}px`;
topScroll.hidden = tableWidth <= scroll.clientWidth + 1;
}
function buildList() {
if (!list) return;
const hidden = new Set(getHidden());
const fragment = document.createDocumentFragment();
allFields().forEach(field => {
const label = document.createElement('label');
label.className = 'checkbox-option';
const input = document.createElement('input');
input.type = 'checkbox';
input.checked = !hidden.has(field);
input.addEventListener('change', () =>
input.checked ? showField(field) : hideField(field)
);
const span = document.createElement('span');
span.textContent = fieldLabel(field);
label.append(input, span);
fragment.appendChild(label);
});
list.replaceChildren(fragment);
}
function applyHidden() {
const hidden = new Set(getHidden());
let style = document.getElementById(styleId);
if (!style) {
style = document.createElement('style');
style.id = styleId;
document.head.appendChild(style);
}
style.textContent = [...hidden]
.map(field =>
`#asset-table [data-field="${CSS.escape(field)}"]{display:none!important}`
)
.join('\n');
const tableWidth = visibleTableWidth(hidden);
table.style.width = `${tableWidth}px`;
table.style.minWidth = `${tableWidth}px`;
table.dataset.calculatedWidth = String(tableWidth);
buildList();
requestAnimationFrame(() => updateTopScrollbar(tableWidth));
window.dispatchEvent(new Event('asset-table-columns-changed'));
}
function hideField(field) {
if (!field) return;
const hidden = getHidden();
const visibleFields = allFields().filter(item => !hidden.includes(item));
if (visibleFields.length <= 1 || hidden.includes(field)) return;
hidden.push(field);
setHidden(hidden);
applyHidden();
}
function showField(field) {
setHidden(getHidden().filter(item => item !== field));
applyHidden();
}
let syncing = false;
scroll?.addEventListener('scroll', () => {
if (syncing || !topScroll) return;
syncing = true;
topScroll.scrollLeft = scroll.scrollLeft;
syncing = false;
}, { passive: true });
topScroll?.addEventListener('scroll', () => {
if (syncing || !scroll) return;
syncing = true;
scroll.scrollLeft = topScroll.scrollLeft;
syncing = false;
}, { passive: true });
headers().forEach(th => {
th.addEventListener('contextmenu', event => {
event.preventDefault();
contextField = th.dataset.field;
if (!menu) return;
menu.hidden = false;
const maxX = window.innerWidth - menu.offsetWidth - 8;
const maxY = window.innerHeight - menu.offsetHeight - 8;
menu.style.left = `${Math.max(8, Math.min(event.clientX, maxX))}px`;
menu.style.top = `${Math.max(8, Math.min(event.clientY, maxY))}px`;
});
});
hideMenuButton?.addEventListener('click', () => {
hideField(contextField);
menu.hidden = true;
});
openMenuButton?.addEventListener('click', () => {
menu.hidden = true;
buildList();
dialog?.showModal();
});
document.addEventListener('click', event => {
if (menu && !menu.contains(event.target)) menu.hidden = true;
});
document.addEventListener('keydown', event => {
if (event.key === 'Escape' && menu) menu.hidden = true;
});
openButton?.addEventListener('click', () => {
buildList();
dialog?.showModal();
});
showAllButton?.addEventListener('click', () => {
setHidden([]);
applyHidden();
});
resetButton?.addEventListener('click', () => {
setHidden([]);
window.AssetBrowserState?.remove?.(keyBase);
applyHidden();
window.location.reload();
});
function scheduleScrollbarUpdate() {
cancelAnimationFrame(resizeFrame);
resizeFrame = requestAnimationFrame(() => {
const tableWidth = Number.parseInt(table.dataset.calculatedWidth || '0', 10);
if (tableWidth) updateTopScrollbar(tableWidth);
});
}
window.addEventListener('resize', scheduleScrollbarUpdate, { passive: true });
if ('ResizeObserver' in window && scroll) {
const resizeObserver = new ResizeObserver(entries => {
const width = Math.round(entries[0]?.contentRect?.width || 0);
if (width === lastContainerWidth) return;
lastContainerWidth = width;
scheduleScrollbarUpdate();
});
resizeObserver.observe(scroll);
}
window.addEventListener('asset-table-content-reloaded', event => {
if (!event.detail?.table || event.detail.table === table) {
applyHidden();
}
});
applyHidden();
window.dispatchEvent(new CustomEvent('asset-table-columns-ready', {
detail: { table }
}));
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init, { once: true });
} else {
init();
}
})();