- Reorganize admin into admin/theme/default/ (views + assets) - Rename GuideNav to Navigation plugin (essential, protected) - Plugin assets support (SCSS/CSS) loaded after theme CSS - User roles: Admin, Content Manager, BI Manager, Site Admin - Role-based access control (RBAC) for admin routes and sidebar - Guide restructure: sub-topics in separate folders with sidebar nav - Dynamic breadcrumb for homepage and subdirectories - Fix theme path traversal (../../ -> ../) in admin.php - Fix CodeMirror mode load order (xml -> css -> js -> htmlmixed -> php) - Fix editor-toolbar.js null checks for plugin edit pages - Layout select from theme.json with live frontmatter update - Footer sticky at bottom of viewport (min-height: 100vh) - Breadcrumb color fix (var(--nav-font) -> var(--header-bg)) - Remove language switcher from guide pages - Update README.md and README.en.md - Bump version to 2.5.1
127 lines
4.2 KiB
JavaScript
127 lines
4.2 KiB
JavaScript
// Main application JavaScript
|
|
// This file contains general application functionality
|
|
|
|
/**
|
|
* Toggle sidebar visibility (open/close)
|
|
*/
|
|
function toggleSidebar() {
|
|
const sidebar = document.getElementById('site-sidebar');
|
|
const contentCol = sidebar ? sidebar.nextElementSibling || sidebar.parentElement.querySelector('.content-column') : null;
|
|
const btn = document.querySelector('.sidebar-toggle-btn');
|
|
const icon = btn ? btn.querySelector('i') : null;
|
|
|
|
if (!sidebar) return;
|
|
|
|
sidebar.classList.toggle('sidebar-hidden');
|
|
|
|
// Adjust content column width, toggle icon, and update aria-expanded
|
|
if (sidebar.classList.contains('sidebar-hidden')) {
|
|
if (contentCol) {
|
|
contentCol.classList.remove('col-lg-9', 'col-md-8');
|
|
contentCol.classList.add('col-12');
|
|
}
|
|
if (icon) {
|
|
icon.classList.remove('bi-layout-sidebar-inset');
|
|
icon.classList.add('bi-layout-sidebar');
|
|
}
|
|
if (btn) {
|
|
btn.setAttribute('aria-expanded', 'false');
|
|
}
|
|
sessionStorage.setItem('sidebarHidden', 'true');
|
|
} else {
|
|
if (contentCol) {
|
|
contentCol.classList.remove('col-12');
|
|
contentCol.classList.add('col-lg-9', 'col-md-8');
|
|
}
|
|
if (icon) {
|
|
icon.classList.remove('bi-layout-sidebar');
|
|
icon.classList.add('bi-layout-sidebar-inset');
|
|
}
|
|
if (btn) {
|
|
btn.setAttribute('aria-expanded', 'true');
|
|
}
|
|
sessionStorage.setItem('sidebarHidden', 'false');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Restore sidebar state from sessionStorage on page load
|
|
*/
|
|
function restoreSidebarState() {
|
|
if (sessionStorage.getItem('sidebarHidden') === 'true') {
|
|
const sidebar = document.getElementById('site-sidebar');
|
|
if (sidebar) {
|
|
toggleSidebar();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize application when DOM is ready
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Restore sidebar state
|
|
restoreSidebarState();
|
|
|
|
// Initialize search functionality
|
|
const searchInputs = document.querySelectorAll('.search-input');
|
|
const searchButtons = document.querySelectorAll('button[type="submit"]');
|
|
|
|
searchInputs.forEach(function(input) {
|
|
input.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Enter') {
|
|
const query = this.value.trim();
|
|
if (query) {
|
|
// Submit the form
|
|
this.closest('form').submit();
|
|
} else {
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Ensure search buttons submit the form
|
|
searchButtons.forEach(function(btn) {
|
|
btn.addEventListener('click', function(e) {
|
|
const form = this.closest('form');
|
|
if (form && form.getAttribute('role') === 'search') {
|
|
const input = form.querySelector('.search-input');
|
|
if (input && !input.value.trim()) {
|
|
e.preventDefault();
|
|
input.focus();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Handle nested dropdowns for touch devices using event delegation
|
|
document.addEventListener('click', function(e) {
|
|
const toggle = e.target.closest('.dropdown-submenu .dropdown-toggle');
|
|
|
|
if (toggle) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
const submenu = toggle.closest('.dropdown-submenu');
|
|
const dropdown = submenu.querySelector('.dropdown-menu');
|
|
|
|
// Close other submenus at the same level
|
|
const parent = submenu.parentElement;
|
|
parent.querySelectorAll('.dropdown-submenu').forEach(function(sibling) {
|
|
if (sibling !== submenu) {
|
|
var siblingMenu = sibling.querySelector('.dropdown-menu');
|
|
if (siblingMenu) siblingMenu.classList.remove('show');
|
|
}
|
|
});
|
|
|
|
// Toggle current submenu
|
|
if (dropdown) dropdown.classList.toggle('show');
|
|
return;
|
|
}
|
|
|
|
// Close all open submenus when clicking outside
|
|
document.querySelectorAll('.dropdown-submenu .dropdown-menu.show').forEach(function(menu) {
|
|
menu.classList.remove('show');
|
|
});
|
|
});
|
|
});
|