Plugin sidebar order + directory layout from index.md
- PluginManager: iterate allowedPlugins in user-defined order (frontmatter order) - content-edit.twig: plugin list with up/down arrows to set order - Directory listing: read layout/plugins from index.md if present - Directory default layout: full_content (no sidebar) unless index.md says otherwise
This commit is contained in:
@@ -29,13 +29,33 @@
|
||||
</div>
|
||||
{% if availablePlugins is not empty %}
|
||||
<div class="col-md-4">
|
||||
<label class="form-label d-block">Zichtbare plugins</label>
|
||||
<div class="d-flex flex-wrap gap-1">
|
||||
{% for plugin in availablePlugins %}
|
||||
<input type="checkbox" class="btn-check" id="plugin-{{ plugin }}" name="plugins[]" value="{{ plugin }}" autocomplete="off" {{ plugin in selectedPlugins ? 'checked' : '' }}>
|
||||
<label class="btn btn-outline-primary btn-sm" for="plugin-{{ plugin }}">{{ plugin }}</label>
|
||||
<label class="form-label d-block">Zichtbare plugins (volgorde = sidebar volgorde)</label>
|
||||
<ul class="list-group list-group-flush" id="plugin-order-list">
|
||||
{% for plugin in selectedPlugins %}
|
||||
<li class="list-group-item d-flex align-items-center justify-content-between px-2 py-1" data-plugin="{{ plugin }}">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="plugin-{{ plugin }}" name="plugins[]" value="{{ plugin }}" autocomplete="off" checked>
|
||||
<label class="form-check-label" for="plugin-{{ plugin }}">{{ plugin }}</label>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button type="button" class="btn btn-outline-secondary py-0 px-1 plugin-up" title="Omhoog"><i class="bi bi-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-outline-secondary py-0 px-1 plugin-down" title="Omlaag"><i class="bi bi-arrow-down"></i></button>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% for plugin in availablePlugins if plugin not in selectedPlugins %}
|
||||
<li class="list-group-item d-flex align-items-center justify-content-between px-2 py-1" data-plugin="{{ plugin }}">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="plugin-{{ plugin }}" name="plugins[]" value="{{ plugin }}" autocomplete="off">
|
||||
<label class="form-check-label" for="plugin-{{ plugin }}">{{ plugin }}</label>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button type="button" class="btn btn-outline-secondary py-0 px-1 plugin-up" title="Omhoog"><i class="bi bi-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-outline-secondary py-0 px-1 plugin-down" title="Omlaag"><i class="bi bi-arrow-down"></i></button>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -119,6 +139,36 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
}
|
||||
|
||||
window.__onContentChange = markChanged;
|
||||
|
||||
// Plugin order: move list items up/down
|
||||
var pluginList = document.getElementById('plugin-order-list');
|
||||
if (pluginList) {
|
||||
pluginList.addEventListener('click', function (e) {
|
||||
var upBtn = e.target.closest('.plugin-up');
|
||||
var downBtn = e.target.closest('.plugin-down');
|
||||
if (!upBtn && !downBtn) return;
|
||||
|
||||
var item = e.target.closest('li[data-plugin]');
|
||||
if (!item) return;
|
||||
|
||||
if (upBtn && item.previousElementSibling) {
|
||||
pluginList.insertBefore(item, item.previousElementSibling);
|
||||
markChanged();
|
||||
} else if (downBtn && item.nextElementSibling) {
|
||||
pluginList.insertBefore(item, item.nextElementSibling.nextElementSibling);
|
||||
markChanged();
|
||||
}
|
||||
});
|
||||
|
||||
// On form submit, reorder the checkboxes to match the visual order
|
||||
var form = document.getElementById('editor-form');
|
||||
if (form) {
|
||||
form.addEventListener('submit', function () {
|
||||
// The DOM order of the <li> elements already determines the form submission order
|
||||
// because the checkboxes are inside the <li> elements
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1141,9 +1141,22 @@ class CodePressCMS {
|
||||
$content .= '<p>' . $this->t('directory_empty') . '.</p>';
|
||||
}
|
||||
|
||||
// Check for index.md in this directory for layout/plugins metadata
|
||||
$indexFile = $dirPath . '/index.md';
|
||||
$layout = 'full_content';
|
||||
$metadata = [];
|
||||
if (file_exists($indexFile)) {
|
||||
$indexContent = file_get_contents($indexFile);
|
||||
$parsed = $this->parseMetadata($indexContent);
|
||||
$metadata = $parsed['metadata'];
|
||||
$layout = $metadata['layout'] ?? 'full_content';
|
||||
}
|
||||
|
||||
return [
|
||||
'title' => $title,
|
||||
'content' => $content
|
||||
'content' => $content,
|
||||
'layout' => $layout,
|
||||
'metadata' => $metadata,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -140,28 +140,27 @@ class PluginManager
|
||||
public function getSidebarContent(?array $allowedPlugins = null): string
|
||||
{
|
||||
$sidebarContent = '';
|
||||
|
||||
foreach ($this->plugins as $pluginName => $plugin) {
|
||||
if (!$this->isPluginViewable($plugin) || !method_exists($plugin, 'getSidebarContent')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($allowedPlugins !== null && !in_array($pluginName, $allowedPlugins, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = $plugin->getSidebarContent();
|
||||
if (trim($content) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$title = 'Plugin';
|
||||
if (method_exists($plugin, 'getConfig')) {
|
||||
$config = $plugin->getConfig();
|
||||
$title = $config['title'] ?? 'Plugin';
|
||||
}
|
||||
|
||||
$sidebarContent .= '
|
||||
|
||||
// If allowedPlugins is specified, iterate in that order (user-defined order)
|
||||
if ($allowedPlugins !== null) {
|
||||
foreach ($allowedPlugins as $pluginName) {
|
||||
$plugin = $this->plugins[$pluginName] ?? null;
|
||||
if (!$plugin || !$this->isPluginViewable($plugin) || !method_exists($plugin, 'getSidebarContent')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = $plugin->getSidebarContent();
|
||||
if (trim($content) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$title = 'Plugin';
|
||||
if (method_exists($plugin, 'getConfig')) {
|
||||
$config = $plugin->getConfig();
|
||||
$title = $config['title'] ?? 'Plugin';
|
||||
}
|
||||
|
||||
$sidebarContent .= '
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">' . htmlspecialchars($title) . '</h5>
|
||||
@@ -170,8 +169,37 @@ class PluginManager
|
||||
' . $content . '
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
} else {
|
||||
// No filter — show all viewable plugins in load order
|
||||
foreach ($this->plugins as $pluginName => $plugin) {
|
||||
if (!$this->isPluginViewable($plugin) || !method_exists($plugin, 'getSidebarContent')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = $plugin->getSidebarContent();
|
||||
if (trim($content) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$title = 'Plugin';
|
||||
if (method_exists($plugin, 'getConfig')) {
|
||||
$config = $plugin->getConfig();
|
||||
$title = $config['title'] ?? 'Plugin';
|
||||
}
|
||||
|
||||
$sidebarContent .= '
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">' . htmlspecialchars($title) . '</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
' . $content . '
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $sidebarContent;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ class HTMLBlock
|
||||
$currentPage = $this->api ? $this->api->getCurrentPageTitle() : 'Onbekend';
|
||||
$isHomepage = $this->api ? $this->api->isHomepage() : false;
|
||||
$currentLang = $this->api ? $this->api->getCurrentLanguage() : 'nl';
|
||||
$currentPath = $_GET['page'] ?? '';
|
||||
$currentPath = preg_replace('/\.(md|php|html)$/', '', $currentPath);
|
||||
|
||||
$content = '
|
||||
<p class="mb-2"><strong>Huidige pagina:</strong> ' . htmlspecialchars($currentPage) . '</p>
|
||||
@@ -42,7 +44,7 @@ class HTMLBlock
|
||||
</div>';
|
||||
}
|
||||
|
||||
// Add quick navigation
|
||||
// Add dynamic quick navigation
|
||||
$menu = $this->api->getMenu();
|
||||
if (!empty($menu)) {
|
||||
$content .= '
|
||||
@@ -51,8 +53,25 @@ class HTMLBlock
|
||||
|
||||
foreach ($menu as $item) {
|
||||
if ($item['type'] === 'file') {
|
||||
$url = $this->api->createUrl($item['path']);
|
||||
$content .= '<li><a href="' . htmlspecialchars($url) . '" class="text-decoration-none">📄 ' . htmlspecialchars($item['title']) . '</a></li>';
|
||||
$url = '/' . $currentLang . '/' . $item['path'];
|
||||
$isActive = ($item['path'] === $currentPath) ? ' fw-bold' : '';
|
||||
$content .= '<li><a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" class="text-decoration-none' . $isActive . '"><i class="bi bi-file-earmark"></i> ' . htmlspecialchars($item['title'], ENT_QUOTES, 'UTF-8') . '</a></li>';
|
||||
} elseif ($item['type'] === 'folder' && !empty($item['children'])) {
|
||||
$url = '/' . $currentLang . '/' . $item['path'];
|
||||
$isActive = strpos($currentPath, $item['path']) === 0 ? ' fw-bold' : '';
|
||||
$content .= '<li><a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" class="text-decoration-none' . $isActive . '"><i class="bi bi-folder"></i> ' . htmlspecialchars($item['title'], ENT_QUOTES, 'UTF-8') . '</a></li>';
|
||||
// Show children if current page is in this folder
|
||||
if (strpos($currentPath, $item['path']) === 0) {
|
||||
$content .= '<ul class="list-unstyled ms-3 mb-1">';
|
||||
foreach ($item['children'] as $child) {
|
||||
if ($child['type'] === 'file') {
|
||||
$childUrl = '/' . $currentLang . '/' . $child['path'];
|
||||
$childActive = ($child['path'] === $currentPath) ? ' fw-bold' : '';
|
||||
$content .= '<li><a href="' . htmlspecialchars($childUrl, ENT_QUOTES, 'UTF-8') . '" class="text-decoration-none' . $childActive . '"><i class="bi bi-file-earmark"></i> ' . htmlspecialchars($child['title'], ENT_QUOTES, 'UTF-8') . '</a></li>';
|
||||
}
|
||||
}
|
||||
$content .= '</ul>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user