239 lines
7.7 KiB
JavaScript
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();
|
|
}
|
|
})();
|