almost functional
This commit is contained in:
@@ -16,19 +16,51 @@
|
||||
function initSidebarToggle() {
|
||||
const toggleBtn = document.querySelector('[data-action="toggle-sidebar"]');
|
||||
const sidebar = document.querySelector('.ots-sidebar');
|
||||
const closeBtn = document.querySelector('.ots-sidebar-close');
|
||||
const collapseBtn = document.querySelector('.sidebar-collapse-btn');
|
||||
const body = document.body;
|
||||
|
||||
if (!toggleBtn || !sidebar) return;
|
||||
if (!sidebar) return;
|
||||
|
||||
toggleBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
sidebar.classList.toggle('active');
|
||||
});
|
||||
// Handle sidebar close button
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
sidebar.classList.remove('active');
|
||||
});
|
||||
}
|
||||
|
||||
if (toggleBtn) {
|
||||
toggleBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
sidebar.classList.toggle('active');
|
||||
});
|
||||
}
|
||||
|
||||
if (collapseBtn) {
|
||||
const isCollapsed = localStorage.getItem(STORAGE_KEYS.sidebarCollapsed) === 'true';
|
||||
if (isCollapsed) {
|
||||
sidebar.classList.add('collapsed');
|
||||
body.classList.add('ots-sidebar-collapsed');
|
||||
}
|
||||
|
||||
collapseBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const nowCollapsed = !sidebar.classList.contains('collapsed');
|
||||
sidebar.classList.toggle('collapsed');
|
||||
body.classList.toggle('ots-sidebar-collapsed', nowCollapsed);
|
||||
localStorage.setItem(STORAGE_KEYS.sidebarCollapsed, nowCollapsed ? 'true' : 'false');
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize sidebar section toggles
|
||||
initSidebarSectionToggles();
|
||||
|
||||
// Close sidebar when clicking outside on mobile
|
||||
document.addEventListener('click', function(e) {
|
||||
if (window.innerWidth <= 768) {
|
||||
const isClickInsideSidebar = sidebar.contains(e.target);
|
||||
const isClickOnToggle = toggleBtn.contains(e.target);
|
||||
const isClickOnToggle = toggleBtn && toggleBtn.contains(e.target);
|
||||
|
||||
if (!isClickInsideSidebar && !isClickOnToggle && sidebar.classList.contains('active')) {
|
||||
sidebar.classList.remove('active');
|
||||
@@ -37,27 +69,47 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize sidebar section collapse/expand functionality
|
||||
*/
|
||||
function initSidebarSectionToggles() {
|
||||
const groupToggles = document.querySelectorAll('.sidebar-group-toggle');
|
||||
|
||||
groupToggles.forEach(toggle => {
|
||||
toggle.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const group = toggle.closest('.sidebar-group');
|
||||
const submenu = group ? group.querySelector('.sidebar-submenu') : null;
|
||||
if (!submenu) return;
|
||||
|
||||
const isOpen = group.classList.contains('is-open');
|
||||
group.classList.toggle('is-open', !isOpen);
|
||||
toggle.setAttribute('aria-expanded', (!isOpen).toString());
|
||||
submenu.style.display = isOpen ? 'none' : 'block';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize dropdown menus
|
||||
*/
|
||||
function initDropdowns() {
|
||||
const dropdowns = document.querySelectorAll('.dropdown');
|
||||
|
||||
|
||||
dropdowns.forEach(dropdown => {
|
||||
const button = dropdown.querySelector('.dropdown-menu');
|
||||
|
||||
if (!button) return;
|
||||
|
||||
const toggle = dropdown.querySelector('.dropdown-toggle, [data-toggle="dropdown"], .dt-button');
|
||||
const menu = dropdown.querySelector('.dropdown-menu');
|
||||
|
||||
// Toggle menu on button click
|
||||
dropdown.addEventListener('click', function(e) {
|
||||
if (e.target.closest('.user-btn') || e.target.closest('[aria-label="User menu"]')) {
|
||||
e.preventDefault();
|
||||
dropdown.classList.toggle('active');
|
||||
}
|
||||
|
||||
if (!toggle || !menu) return;
|
||||
|
||||
// Toggle menu on toggle click
|
||||
toggle.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dropdown.classList.toggle('active');
|
||||
});
|
||||
|
||||
|
||||
// Close menu when clicking outside
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!dropdown.contains(e.target)) {
|
||||
@@ -65,6 +117,99 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
// Support DataTables Buttons collections which are not wrapped by .dropdown
|
||||
document.addEventListener('click', function(e) {
|
||||
const btn = e.target.closest('.dt-button');
|
||||
|
||||
if (btn) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const wrapper = btn.closest('.dt-buttons') || btn.parentElement;
|
||||
|
||||
// close other open dt-buttons collections
|
||||
document.querySelectorAll('.dt-buttons.active').forEach(w => {
|
||||
if (w !== wrapper) w.classList.remove('active');
|
||||
});
|
||||
|
||||
wrapper.classList.toggle('active');
|
||||
|
||||
// If DataTables placed the collection on the body, find it and position it under the clicked button
|
||||
const allCollections = Array.from(document.querySelectorAll('.dt-button-collection'));
|
||||
let collection = wrapper.querySelector('.dt-button-collection') || allCollections.find(c => !wrapper.contains(c));
|
||||
|
||||
// If DataTables didn't create a collection element, create one as a fallback
|
||||
if (!collection) {
|
||||
collection = document.createElement('div');
|
||||
collection.className = 'dt-button-collection';
|
||||
// prefer to append near wrapper for positioning; fallback to body
|
||||
(wrapper || document.body).appendChild(collection);
|
||||
}
|
||||
|
||||
if (collection) {
|
||||
// hide other collections
|
||||
allCollections.forEach(c => { if (c !== collection) { c.classList.remove('show'); c.style.display = 'none'; } });
|
||||
|
||||
const rect = btn.getBoundingClientRect();
|
||||
const top = rect.bottom + window.scrollY;
|
||||
const left = rect.left + window.scrollX;
|
||||
|
||||
collection.style.position = 'absolute';
|
||||
collection.style.top = `${top}px`;
|
||||
collection.style.left = `${left}px`;
|
||||
collection.style.display = 'block';
|
||||
collection.classList.add('show');
|
||||
// DEBUG: log collection contents
|
||||
try {
|
||||
console.log('dt-button-collection opened, children:', collection.children.length, collection);
|
||||
} catch (err) {}
|
||||
|
||||
// If the collection is empty or visually empty, build a fallback column list from the nearest table
|
||||
const isEmpty = collection.children.length === 0 || collection.textContent.trim() === '' || collection.offsetHeight < 10;
|
||||
if (isEmpty) {
|
||||
try {
|
||||
let table = btn.closest('table') || wrapper.querySelector('table') || document.querySelector('table');
|
||||
if (table && window.jQuery && jQuery.fn && jQuery.fn.dataTable && jQuery.fn.dataTable.isDataTable(table)) {
|
||||
const dt = jQuery(table).DataTable();
|
||||
// clear existing
|
||||
collection.innerHTML = '';
|
||||
const thead = table.querySelectorAll('thead th');
|
||||
thead.forEach((th, idx) => {
|
||||
const text = (th.textContent || th.innerText || `Column ${idx+1}`).trim();
|
||||
const item = document.createElement('div');
|
||||
item.style.padding = '6px 12px';
|
||||
item.style.display = 'flex';
|
||||
item.style.alignItems = 'center';
|
||||
item.style.gap = '8px';
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.checked = dt.column(idx).visible();
|
||||
checkbox.addEventListener('change', function() {
|
||||
dt.column(idx).visible(this.checked);
|
||||
});
|
||||
const label = document.createElement('span');
|
||||
label.textContent = text;
|
||||
label.style.color = 'var(--color-text-primary)';
|
||||
item.appendChild(checkbox);
|
||||
item.appendChild(label);
|
||||
collection.appendChild(item);
|
||||
});
|
||||
console.log('Fallback: populated collection with', collection.children.length, 'items');
|
||||
} else {
|
||||
console.log('Fallback: no DataTable instance found to populate column visibility');
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Error building fallback column list', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// click outside dt-button -> close any open collections
|
||||
document.querySelectorAll('.dt-buttons.active').forEach(w => w.classList.remove('active'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user