Quelltext des aktuellen Standes
<?php
// Standardwerte setzen
$topic = $topic ?? null;
$topic_ancestors = $topic_ancestors ?? [];
$responsibilities = $responsibilities ?? [];
$files = $files ?? [];
$child_pages = $child_pages ?? [];
$linked_pages = $linked_pages ?? [];
$linked_objects = $linked_objects ?? [];
$current_version = $current_version ?? null;
$version_count = $version_count ?? 1;
$ansprechpartner = $ansprechpartner ?? null;
$this->layout('layouts/main', [
'page_title' => $page['title'],
'breadcrumbs' => [], // Eigener Breadcrumb im Hero
'full_width' => true
]);
$isDraft = !empty($page['is_draft']);
$contentHtml = $current_version['content_html'] ?? $page['content_html'] ?? '';
?>
<div class="page-show-fullwidth">
<div class="content-header">
<div>
<h1>
<?= $this->e($page['title']) ?>
<span class="status-pill status-pill--info title-pill">v<?= $this->e($page['version_number'] ?? 1) ?></span>
<?php if ($isDraft): ?>
<span class="status-pill status-pill--warning title-pill"><?= $this->te('Entwurf') ?></span>
<?php endif; ?>
<?php if (!empty($page['portal_published'])): ?>
<span class="status-pill status-pill--success title-pill"
title="<?= $this->te('Diese Seite ist als Anleitung im Self-Service-Portal veröffentlicht') ?>">
<i class="fas fa-book-open" aria-hidden="true"></i> <?= $this->te('Im Portal') ?>
</span>
<?php endif; ?>
</h1>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
<li class="breadcrumb-item"><a href="/topics"><?= $this->te('Themengebiete') ?></a></li>
<?php foreach ($topic_ancestors as $ancestor): ?>
<li class="breadcrumb-item"><a href="/topics/<?= $ancestor['id'] ?>"><?= $this->e($ancestor['name']) ?></a></li>
<?php endforeach; ?>
<?php if ($topic): ?>
<li class="breadcrumb-item"><a href="/topics/<?= $topic['id'] ?>"><?= $this->e($topic['name']) ?></a></li>
<?php endif; ?>
<li class="breadcrumb-item active"><?= $this->e($page['title']) ?></li>
</ol>
</div>
<div class="content-header-actions">
<?php if ($can_edit ?? false): ?>
<a href="/pages/<?= $page['id'] ?>/edit" class="btn btn-primary btn-sm"><?= $this->te('✎ Bearbeiten') ?></a>
<?php endif; ?>
<a href="/pages/<?= $page['id'] ?>/versions" class="btn btn-default btn-sm">📅 <?= $this->te($version_count === 1 ? '{anzahl} Version' : '{anzahl} Versionen', ['anzahl' => $version_count]) ?></a>
<?php if ($can_export_pdf ?? false): ?>
<a href="/pages/<?= $page['id'] ?>/export/pdf" class="btn btn-default btn-sm"><?= $this->te('📄 PDF') ?></a>
<?php endif; ?>
<?php if ($can_manage_responsibilities ?? false): ?>
<a href="/pages/<?= $page['id'] ?>/responsibilities" class="btn btn-default btn-sm"><?= $this->te('👥 Verantwortliche') ?></a>
<?php endif; ?>
</div>
</div>
<div class="page-body">
<div class="page-layout">
<!-- Hauptinhalt -->
<main class="page-main">
<!-- Verantwortlichkeiten-Bar -->
<?php $pageTags = $page_tags ?? []; ?>
<?php if (!empty($responsibilities) || !empty($pageTags)): ?>
<div class="responsibility-bar">
<?php if (!empty($responsibilities)): ?>
<div class="resp-item">
<span class="resp-icon" aria-hidden="true">🛠</span>
<span class="resp-label"><?= $this->te('Technisch:') ?></span>
<span class="resp-value"><?= $this->e($responsibilities['technical_owner_name'] ?? 'Nicht zugewiesen') ?></span>
</div>
<div class="resp-item">
<span class="resp-icon" aria-hidden="true">💼</span>
<span class="resp-label"><?= $this->te('Fachlich:') ?></span>
<span class="resp-value"><?= $this->e($responsibilities['business_owner_name'] ?? 'Nicht zugewiesen') ?></span>
</div>
<?php if (!empty($responsibilities['next_review_date'])): ?>
<?php $isOverdue = strtotime($responsibilities['next_review_date']) < time(); ?>
<div class="resp-item <?= $isOverdue ? 'overdue' : '' ?>">
<span class="resp-icon" aria-hidden="true"><?= $isOverdue ? '⚠' : '📅' ?></span>
<span class="resp-label"><?= $this->te('Review:') ?></span>
<span class="resp-value <?= $isOverdue ? 'text-danger' : '' ?>">
<?php if ($isOverdue): ?>
<?= $this->te('Überfällig seit {datum}', ['datum' => date('d.m.Y', strtotime($responsibilities['next_review_date']))]) ?>
<?php else: ?>
<?= date('d.m.Y', strtotime($responsibilities['next_review_date'])) ?>
<?php endif; ?>
</span>
</div>
<?php endif; ?>
<?php endif; ?>
<?php if (!empty($pageTags)): ?>
<div class="resp-item resp-tags">
<span class="resp-icon" aria-hidden="true">🔖</span>
<span class="resp-label"><?= $this->te('Tags:') ?></span>
<span class="resp-value resp-tags-list">
<?php foreach ($pageTags as $tag): ?>
<?php
// Nur echte Hex-Farben dürfen in das style-Attribut; alles andere fällt auf
// neutrale Tokens zurück. Der Alpha-Suffix (15/30) ergibt nur bei
// sechsstelliger Notation eine gültige Farbe.
$tagColor = $this->safeHexColor($tag['color'] ?? '', '');
$tagHasAlphaBase = strlen($tagColor) === 7;
$tagFg = $tagColor !== '' ? $tagColor : 'var(--gray-600)';
$tagBg = $tagHasAlphaBase ? $tagColor . '15' : 'var(--gray-100)';
$tagBorder = $tagHasAlphaBase ? $tagColor . '30' : 'var(--gray-300)';
?>
<a href="/search?q=tag%3A<?= urlencode($tag['name']) ?>" class="resp-tag" style="background:<?= $this->e($tagBg) ?>;color:<?= $this->e($tagFg) ?>;border:1px solid <?= $this->e($tagBorder) ?>;">
<?= $this->e($tag['name']) ?>
</a>
<?php endforeach; ?>
</span>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Seiteninhalt -->
<article class="page-content">
<div class="wysiwyg-content">
<?= $this->fixRelativeUrls($contentHtml) ?>
</div>
</article>
<!-- Unterseiten -->
<?php if (!empty($child_pages)): ?>
<section class="page-children">
<h2><?= $this->te('📄 Unterseiten') ?></h2>
<div class="children-grid">
<?php foreach ($child_pages as $child): ?>
<a href="/pages/<?= $child['id'] ?>" class="child-card">
<span class="child-icon" aria-hidden="true">📄</span>
<span class="child-title"><?= $this->e($child['title']) ?></span>
<span class="child-arrow" aria-hidden="true">→</span>
</a>
<?php endforeach; ?>
</div>
</section>
<?php endif; ?>
</main>
<!-- Sidebar -->
<aside class="page-sidebar">
<!-- Info-Card -->
<div class="sidebar-card">
<h3><?= $this->te('ℹ️ Informationen') ?></h3>
<dl class="info-list">
<dt><?= $this->te('Erstellt') ?></dt>
<dd>
<?= date('d.m.Y H:i', strtotime($page['created_at'])) ?><br>
<span class="text-muted"><?= $this->te('von {person}', ['person' => $page['created_by_name'] ?? $this->t('Unbekannt')], 'herkunft') ?></span>
</dd>
<?php if (!empty($current_version)): ?>
<dt><?= $this->te('Letzte Änderung') ?></dt>
<dd>
<?= date('d.m.Y H:i', strtotime($current_version['created_at'])) ?><br>
<span class="text-muted"><?= $this->te('von {person}', ['person' => $current_version['created_by_name'] ?? $this->t('Unbekannt')], 'herkunft') ?></span>
</dd>
<?php if (!empty($current_version['change_reason'])): ?>
<dt><?= $this->te('Änderungsgrund') ?></dt>
<dd><?= $this->e($current_version['change_reason']) ?></dd>
<?php endif; ?>
<?php endif; ?>
<dt><?= $this->te('Version') ?></dt>
<dd><?= $this->te('{nummer} von {gesamt}', ['nummer' => $page['version_number'] ?? 1, 'gesamt' => $version_count]) ?></dd>
</dl>
</div>
<!-- Ansprechpartner -->
<?php if ($ansprechpartner !== null): ?>
<?php
$apType = $ansprechpartner['_type'];
$apName = $apType === 'contact'
? ($ansprechpartner['first_name'] . ' ' . $ansprechpartner['last_name'])
: ($apType === 'user'
? ($ansprechpartner['display_name'] ?? $ansprechpartner['name'] ?? '')
: $ansprechpartner['name']);
$apImage = $ansprechpartner['image_path'] ?? null;
$apLink = $apType === 'contact'
? '/contacts/companies/' . ($ansprechpartner['company_id'] ?? 0)
: ($apType === 'company'
? '/contacts/companies/' . $ansprechpartner['id']
: '#');
$apJobTitle = ($apType === 'directory') ? ($ansprechpartner['job_title'] ?? null) : null;
$apDepartment = ($apType === 'directory') ? ($ansprechpartner['department'] ?? null) : null;
$apPhone = $ansprechpartner['phone'] ?? null;
$apMobile = $ansprechpartner['mobile'] ?? null;
$apEmail = $ansprechpartner['email'] ?? null;
?>
<div class="sidebar-card">
<h3><?= $this->te('👤 Ansprechpartner') ?></h3>
<a href="<?= $apLink ?>" class="ap-link">
<div class="ap-avatar">
<?php if ($apImage): ?>
<img src="<?= $this->e($apImage) ?>" alt="<?= $this->e($apName) ?>">
<?php else: ?>
<span class="ap-avatar-letter" aria-hidden="true"><?= $this->e(mb_strtoupper(mb_substr($apName, 0, 1))) ?></span>
<?php endif; ?>
</div>
<div class="ap-info">
<span class="ap-name"><?= $this->e($apName) ?></span>
<?php if ($apType === 'contact' && !empty($ansprechpartner['position'])): ?>
<span class="ap-detail"><?= $this->e($ansprechpartner['position']) ?></span>
<?php endif; ?>
<?php if ($apType === 'contact' && !empty($ansprechpartner['company_name'])): ?>
<span class="ap-detail ap-company"><?= $this->e($ansprechpartner['company_name']) ?></span>
<?php endif; ?>
<?php if ($apType === 'user'): ?>
<span class="ap-detail" style="color:var(--gray-500);"><?= $this->te('Intern') ?></span>
<?php endif; ?>
<?php if ($apType === 'directory' && ($apJobTitle || $apDepartment)): ?>
<span class="ap-detail"><?= $this->e(implode(' – ', array_filter([$apJobTitle, $apDepartment]))) ?></span>
<?php endif; ?>
</div>
</a>
<?php if ($apPhone || $apMobile || $apEmail): ?>
<div class="ap-chips">
<?php if ($apPhone): ?>
<a href="tel:<?= $this->e($apPhone) ?>" class="ap-chip">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z"/></svg>
<?= $this->e($apPhone) ?>
</a>
<?php endif; ?>
<?php if ($apMobile): ?>
<a href="tel:<?= $this->e($apMobile) ?>" class="ap-chip">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>
<?= $this->e($apMobile) ?>
</a>
<?php endif; ?>
<?php if ($apEmail): ?>
<a href="mailto:<?= $this->e($apEmail) ?>" class="ap-chip">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
<?= $this->e($apEmail) ?>
</a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Anhänge (Sidebar) -->
<?php if (!empty($files)): ?>
<div class="sidebar-card">
<h3><?= $this->te('📎 Anhänge') ?> <span class="links-count"><?= count($files) ?></span></h3>
<div class="sidebar-files-list">
<?php foreach ($files as $file):
$ext = strtolower(pathinfo($file['original_filename'] ?? '', PATHINFO_EXTENSION));
$size = $file['file_size'] ?? 0;
?>
<a href="/files/<?= $file['id'] ?>" class="sidebar-file-item" target="_blank">
<span class="sidebar-file-ext"><?= strtoupper($ext ?: '?') ?></span>
<div class="sidebar-file-info">
<span class="sidebar-file-name"><?= $this->e($file['original_filename'] ?? 'Datei') ?></span>
<span class="sidebar-file-size"><?= $this->fileSize($size) ?></span>
</div>
</a>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<!-- Verknüpfte Seiten -->
<?php if (!empty($linked_pages) || !empty($linked_objects) || ($can_edit ?? false)): ?>
<div class="sidebar-card">
<div class="sidebar-card-header-flex">
<h3>🔗 <?= $this->t('Verknüpft') ?>
<?php $linkTotal = count($linked_pages) + count($linked_objects); ?>
<?php if ($linkTotal > 0): ?>
<span class="links-count"><?= $linkTotal ?></span>
<?php endif; ?>
</h3>
<?php if ($can_edit ?? false): ?>
<button type="button" class="lp-add-btn" id="lpAddBtn" title="<?= $this->te('Verknüpfung hinzufügen') ?>"
aria-label="<?= $this->te('Verknüpfung hinzufügen') ?>" aria-expanded="false" aria-controls="addLinkForm">+</button>
<?php endif; ?>
</div>
<?php if (!empty($linked_pages)): ?>
<div class="linked-pages-list">
<?php foreach ($linked_pages as $lp): ?>
<div class="linked-page-item">
<a href="/pages/<?= $lp['id'] ?>" class="linked-page-link">
<span class="lp-icon" aria-hidden="true">📄</span>
<div class="lp-info">
<span class="lp-title"><?= $this->e($lp['title']) ?></span>
<span class="lp-topic"><?= $this->e($lp['topic_name']) ?></span>
</div>
</a>
<?php if ($can_edit ?? false): ?>
<form action="/pages/<?= $page['id'] ?>/links/<?= $lp['id'] ?>" method="POST" class="lp-remove-form"
data-lp-title="<?= $this->e($lp['title']) ?>">
<input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="lp-remove-btn" title="<?= $this->te('Verknüpfung entfernen') ?>"
aria-label="<?= $this->te('Verknüpfung zu „{titel}“ entfernen', ['titel' => $lp['title']]) ?>">
<span aria-hidden="true">×</span>
</button>
</form>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (!empty($linked_objects)): ?>
<div class="linked-pages-list">
<?php foreach ($linked_objects as $lo): ?>
<div class="linked-page-item">
<a href="<?= $this->e($lo['href']) ?>" class="linked-page-link"<?= $lo['external'] ? ' target="_blank" rel="noopener"' : '' ?>>
<span class="lp-icon" aria-hidden="true"><i class="fas <?= $this->e($lo['icon']) ?>"></i></span>
<div class="lp-info">
<span class="lp-title"><?= $this->e($lo['title']) ?></span>
<?php $loMeta = $lo['type_label'] . (!empty($lo['subtitle']) ? ' · ' . $lo['subtitle'] : ''); ?>
<span class="lp-topic"><?= $this->e($loMeta) ?></span>
</div>
</a>
<?php if ($can_edit ?? false): ?>
<form action="/pages/<?= $page['id'] ?>/object-links/<?= $this->e($lo['type']) ?>/<?= (int)$lo['id'] ?>" method="POST" class="lp-remove-form"
data-lp-title="<?= $this->e($lo['title']) ?>">
<input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="lp-remove-btn" title="<?= $this->te('Verknüpfung entfernen') ?>"
aria-label="<?= $this->te('Verknüpfung zu „{titel}“ entfernen', ['titel' => $lo['title']]) ?>">
<span aria-hidden="true">×</span>
</button>
</form>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if ($can_edit ?? false): ?>
<div class="add-link-form" id="addLinkForm" style="display:none;">
<div class="link-search-wrapper">
<input type="text" id="linkSearchInput" placeholder="<?= ($can_link_objects ?? false) ? 'Seite, Gerät, Vertrag, Dienst…' : 'Seite suchen…' ?>"
class="link-search-input" autocomplete="off"
role="combobox" aria-expanded="false" aria-controls="linkSearchResults"
aria-autocomplete="list" aria-label="<?= $this->te('Seite, Gerät, Vertrag oder Dienst suchen') ?>">
<div id="linkSearchResults" class="link-search-results" style="display:none;" role="listbox" aria-label="<?= $this->te('Suchergebnisse') ?>"></div>
</div>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Themengebiet -->
<?php if ($topic): ?>
<div class="sidebar-card">
<h3><?= $this->te('📁 Themengebiet') ?></h3>
<a href="/topics/<?= $topic['id'] ?>" class="topic-link">
<?php if (!empty($topic['image_path'])): ?>
<img src="/uploads/topics/<?= $this->e($topic['image_path']) ?>" alt="" class="topic-icon-img">
<?php else: ?>
<span class="topic-icon" aria-hidden="true">📁</span>
<?php endif; ?>
<span class="topic-name"><?= $this->e($topic['name']) ?></span>
</a>
</div>
<?php endif; ?>
</aside>
</div>
</div>
</div>
<?php if ($can_edit ?? false): ?>
<!-- Bestätigung vor dem Entfernen einer Seitenverknüpfung -->
<div class="modal-overlay" id="lpRemoveModal" style="display:none;" role="dialog" aria-modal="true" aria-labelledby="lpRemoveModalTitle">
<div class="modal-card">
<div class="modal-header">
<h2 id="lpRemoveModalTitle"><?= $this->te('Verknüpfung entfernen') ?></h2>
<button type="button" class="modal-close" id="lpRemoveModalClose" aria-label="<?= $this->te('Schließen') ?>">×</button>
</div>
<div class="modal-body">
<p><?= $this->t('Soll die Verknüpfung zu <strong id="lpRemoveModalTarget">dieser Seite</strong> wirklich entfernt werden?') ?></p>
<p class="text-muted"><?= $this->te('Die verknüpfte Seite selbst bleibt erhalten.') ?></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="lpRemoveModalCancel"><?= $this->te('Abbrechen') ?></button>
<button type="button" class="btn btn-danger" id="lpRemoveModalConfirm"><?= $this->te('Entfernen') ?></button>
</div>
</div>
</div>
<?php endif; ?>
<style>
.page-show-fullwidth {
}
/* Status-Pills in der Seitenüberschrift folgen der Textlinie */
.title-pill {
vertical-align: middle;
margin-left: 0.375rem;
}
/* Body */
.page-body {
padding: 2rem;
background: var(--slate-50);
min-height: calc(100vh - 300px);
}
.page-layout {
display: grid;
grid-template-columns: 1fr 320px;
gap: 2rem;
}
/* Main Content */
.page-main {
min-width: 0;
}
/* Responsibility Bar */
.responsibility-bar {
display: flex;
gap: 2rem;
padding: 1rem 1.25rem;
background: var(--color-bg);
border-radius:0.25rem;
margin-bottom: 1.5rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
flex-wrap: wrap;
}
.resp-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.resp-item.overdue {
color: var(--red-600);
}
.resp-icon {
font-size: 1.1rem;
}
.resp-label {
color: var(--gray-500);
font-size: 0.85rem;
}
.resp-value {
font-weight: 500;
color: var(--gray-900);
}
.text-danger {
color: var(--red-600) !important;
font-weight: 600;
}
/* Page Content */
.page-content {
background: var(--color-bg);
border-radius:0.25rem;
padding: 2rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
margin-bottom: 1.5rem;
overflow: hidden;
max-width: 100%;
}
.wysiwyg-content {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif !important;
font-size: 1rem;
line-height: 1.7;
color: var(--gray-800);
overflow-wrap: break-word;
word-break: break-word;
overflow: hidden;
}
/* Alle TinyMCE-Kindelemente: Textüberlauf erzwingen, max-width begrenzen */
.wysiwyg-content p,
.wysiwyg-content div,
.wysiwyg-content span,
.wysiwyg-content li,
.wysiwyg-content blockquote,
.wysiwyg-content h1,
.wysiwyg-content h2,
.wysiwyg-content h3,
.wysiwyg-content h4,
.wysiwyg-content h5,
.wysiwyg-content h6 {
overflow-wrap: break-word !important;
word-break: break-word !important;
max-width: 100% !important;
}
/* Inline-Styles von TinyMCE ueberschreiben: keine Serifenschrift */
.wysiwyg-content :not(code):not(pre):not(kbd):not(samp) {
font-family: inherit !important;
}
.wysiwyg-content h1 { font-size: 1.75rem; margin: 2rem 0 1rem; }
.wysiwyg-content h2 { font-size: 1.5rem; margin: 1.75rem 0 0.75rem; border-bottom: 2px solid var(--gray-200); padding-bottom: 0.5rem; }
.wysiwyg-content h3 { font-size: 1.25rem; margin: 1.5rem 0 0.5rem; }
.wysiwyg-content p { margin: 0 0 1rem; }
.wysiwyg-content ul, .wysiwyg-content ol { margin: 0 0 1rem; padding-left: 1.5rem; }
.wysiwyg-content li { margin-bottom: 0.25rem; }
.table-scroll-wrapper { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; margin: 1rem 0; border-radius: 0.375rem; }
.wysiwyg-content table { min-width: 100%; border-collapse: collapse; margin: 0; table-layout: auto; }
.wysiwyg-content .table-scroll-wrapper table { width: auto; max-width: none !important; }
.wysiwyg-content th, .wysiwyg-content td { border: 1px solid var(--gray-200); padding: 0.5rem 0.75rem; text-align: left; white-space: normal; overflow-wrap: break-word; word-break: break-word; }
.wysiwyg-content th { background: var(--gray-50); font-weight: 600; }
.wysiwyg-content pre { background: var(--gray-800); color: var(--gray-50); padding: 1rem; border-radius:0.25rem; overflow-x: auto; max-width: 100%; }
.wysiwyg-content code { background: var(--gray-100); padding: 0.125rem 0.375rem; border-radius: 0.25rem; font-size: 0.9em; }
.wysiwyg-content pre code { background: transparent; padding: 0; }
.wysiwyg-content blockquote { border-left: 4px solid var(--color-primary); margin: 1rem 0; padding: 0.5rem 1rem; background: var(--color-primary-pale); }
.wysiwyg-content img { max-width: 100% !important; height: auto !important; border-radius:0.25rem; cursor: pointer; transition: opacity 0.15s; display: block; }
.wysiwyg-content img:hover { opacity: 0.9; }
/* Lightbox */
.lightbox-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.85);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
cursor: zoom-out;
padding: 2rem;
opacity: 0;
transition: opacity 0.2s;
}
.lightbox-overlay.active { opacity: 1; }
.lightbox-overlay img {
max-width: 95vw;
max-height: 90vh;
object-fit: contain;
border-radius:0.25rem;
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.lightbox-close {
position: absolute;
top: 1rem;
right: 1.5rem;
color: var(--color-on-accent);
background: rgba(0,0,0,0.5);
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
font-size: 1.5rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.15s;
}
.lightbox-close:hover { background: rgba(255,255,255,0.2); }
/* Attachments */
.page-attachments {
background: var(--color-bg);
border-radius:0.25rem;
padding: 0;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
margin-bottom: 1.5rem;
overflow: hidden;
}
.page-children {
background: var(--color-bg);
border-radius:0.25rem;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
margin-bottom: 1.5rem;
}
.page-children h2 {
margin: 0 0 1rem 0;
font-size: 1rem;
font-weight: 600;
color: var(--gray-900);
}
.attachments-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;
border-bottom: 1px solid var(--gray-100);
}
.attachments-header h2 {
margin: 0;
font-size: 0.95rem;
font-weight: 600;
color: var(--gray-900);
}
.attachments-count {
font-size: 0.8rem;
color: var(--gray-500);
background: var(--gray-100);
padding: 0.2rem 0.6rem;
border-radius: 9999px;
font-weight: 500;
}
.attachments-list {
display: flex;
flex-direction: column;
}
.att-card {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.875rem 1.5rem;
text-decoration: none;
transition: background 0.15s;
border-bottom: 1px solid var(--gray-50);
}
.att-card:last-child {
border-bottom: none;
}
.att-card:hover {
background: var(--slate-50);
text-decoration: none;
}
.att-card:hover .att-action {
opacity: 1;
}
.att-icon {
width: 40px;
height: 40px;
border-radius:0.25rem;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.att-icon svg {
width: 22px;
height: 22px;
}
/* Dateityp-Farben */
.type-pdf .att-icon { background: var(--red-50); color: var(--red-600); }
.type-word .att-icon { background: var(--color-primary-pale); color: var(--color-primary); }
.type-excel .att-icon { background: var(--green-50); color: var(--green-600); }
.type-ppt .att-icon { background: var(--orange-50); color: var(--orange-600); }
.type-image .att-icon { background: var(--fuchsia-50); color: var(--fuchsia-600); }
.type-video .att-icon { background: var(--amber-100); color: var(--amber-600); }
.type-audio .att-icon { background: var(--pink-100); color: var(--pink-600); }
.type-archive .att-icon { background: var(--violet-50); color: var(--violet-600); }
.type-code .att-icon { background: var(--emerald-50); color: var(--emerald-600); }
.type-text .att-icon { background: var(--slate-50); color: var(--slate-500); }
.type-generic .att-icon { background: var(--gray-100); color: var(--gray-500); }
.att-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.att-name {
font-weight: 500;
color: var(--gray-900);
font-size: 0.9rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.att-meta {
display: flex;
align-items: center;
gap: 0.5rem;
}
.att-type-badge {
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.04em;
padding: 0.1rem 0.4rem;
border-radius: 0.25rem;
text-transform: uppercase;
}
.type-pdf .att-type-badge { background: var(--red-50); color: var(--red-600); }
.type-word .att-type-badge { background: var(--color-primary-pale); color: var(--color-primary); }
.type-excel .att-type-badge { background: var(--green-50); color: var(--green-600); }
.type-ppt .att-type-badge { background: var(--orange-50); color: var(--orange-600); }
.type-image .att-type-badge { background: var(--fuchsia-50); color: var(--fuchsia-600); }
.type-video .att-type-badge { background: var(--amber-100); color: var(--amber-600); }
.type-audio .att-type-badge { background: var(--pink-100); color: var(--pink-600); }
.type-archive .att-type-badge { background: var(--violet-50); color: var(--violet-600); }
.type-code .att-type-badge { background: var(--emerald-50); color: var(--emerald-600); }
.type-text .att-type-badge { background: var(--slate-50); color: var(--slate-500); }
.type-generic .att-type-badge { background: var(--gray-100); color: var(--gray-500); }
.att-size {
font-size: 0.75rem;
color: var(--gray-400);
}
.att-action {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0.375rem;
color: var(--gray-400);
opacity: 0;
transition: all 0.15s;
flex-shrink: 0;
}
.att-action svg {
width: 18px;
height: 18px;
}
.att-card:hover .att-action {
color: var(--color-primary);
background: var(--color-primary-pale);
}
@media (max-width: 768px) {
.att-card {
padding: 0.75rem 1rem;
}
.att-action {
opacity: 1;
}
}
/* Children */
.children-grid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.child-card {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--gray-50);
border-radius:0.25rem;
text-decoration: none;
transition: all 0.15s;
}
.child-card:hover {
background: var(--color-primary-pale);
text-decoration: none;
}
.child-icon {
font-size: 1.25rem;
}
.child-title {
flex: 1;
font-weight: 500;
color: var(--gray-900);
}
.child-arrow {
color: var(--gray-300);
transition: all 0.15s;
}
.child-card:hover .child-arrow {
color: var(--color-primary);
transform: translateX(3px);
}
/* Verknüpfte Seiten (Sidebar) */
.sidebar-card-header-flex {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.sidebar-card-header-flex h3 {
margin: 0;
display: flex;
align-items: center;
gap: 0.375rem;
}
.lp-add-btn {
width: 24px;
height: 24px;
border-radius: 50%;
border: 1px solid var(--gray-300);
background: var(--color-bg);
color: var(--gray-500);
font-size: 1rem;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s;
}
.lp-add-btn:hover {
background: var(--color-primary-pale);
border-color: var(--blue-300);
color: var(--color-primary);
}
.lp-add-btn.active {
background: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-on-accent);
transform: rotate(45deg);
}
.links-count {
background: var(--gray-200);
color: var(--gray-700);
font-size: 0.65rem;
font-weight: 600;
padding: 0.1rem 0.4rem;
border-radius: 9999px;
}
.linked-pages-list {
display: flex;
flex-direction: column;
gap: 0.375rem;
}
.linked-page-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.linked-page-link {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.4rem 0.5rem;
background: var(--gray-50);
border-radius: 0.375rem;
text-decoration: none;
transition: all 0.15s;
}
.linked-page-link:hover {
background: var(--color-primary-pale);
text-decoration: none;
}
/* Feste Breite, damit Seiten- und Objektzeilen denselben Textanfang haben. */
.lp-icon { font-size: 0.9rem; opacity: 0.6; flex: 0 0 1.1rem; display: inline-flex; justify-content: center; }
.lp-info {
display: flex;
flex-direction: column;
gap: 0.1rem;
min-width: 0;
}
.lp-title {
font-weight: 500;
color: var(--gray-900);
font-size: 0.8rem;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.lp-topic {
font-size: 0.75rem;
color: var(--gray-400);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.lp-remove-form { flex-shrink: 0; }
.lp-remove-btn {
background: none;
border: none;
color: var(--gray-300);
font-size: 1.25rem;
cursor: pointer;
padding: 0.25rem;
border-radius: 0.25rem;
line-height: 1;
transition: all 0.15s;
}
.lp-remove-btn:hover {
color: var(--red-500);
background: var(--red-50);
}
/* Link-Suche */
.add-link-form {
padding-top: 0.5rem;
margin-top: 0.375rem;
border-top: 1px solid var(--gray-100);
}
.link-search-wrapper {
position: relative;
}
.link-search-input {
width: 100%;
padding: 0.5rem 0.75rem;
border: 1px solid var(--gray-200);
border-radius: 0.375rem;
font-size: 0.85rem;
outline: none;
transition: border-color 0.15s;
box-sizing: border-box;
}
.link-search-input:focus {
border-color: var(--blue-300);
box-shadow: 0 0 0 3px rgba(59,130,246,0.1);
}
.link-search-results {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--color-bg);
border: 1px solid var(--gray-200);
border-radius: 0.375rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
z-index: 50;
max-height: 240px;
overflow-y: auto;
margin-top: 0.25rem;
}
.link-search-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
cursor: pointer;
transition: background 0.1s;
font-size: 0.85rem;
}
.link-search-item:hover,
.link-search-item.is-active {
background: var(--color-primary-pale);
}
.link-search-item .lsi-title {
font-weight: 500;
color: var(--gray-900);
}
.link-search-item .lsi-topic {
font-size: 0.75rem;
color: var(--gray-400);
margin-left: auto;
}
.link-search-empty {
padding: 0.75rem;
text-align: center;
color: var(--gray-400);
font-size: 0.85rem;
}
/* Sidebar */
.page-sidebar {
display: flex;
flex-direction: column;
gap: 1rem;
}
.sidebar-card {
background: var(--color-bg);
border-radius:0.25rem;
padding: 1.25rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.sidebar-card h3 {
margin: 0 0 1rem 0;
font-size: 0.9rem;
font-weight: 600;
color: var(--gray-700);
}
/* Info List */
.info-list {
margin: 0;
}
.info-list dt {
font-size: 0.75rem;
color: var(--gray-500);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-top: 0.75rem;
}
.info-list dt:first-child {
margin-top: 0;
}
.info-list dd {
margin: 0.25rem 0 0 0;
font-size: 0.9rem;
color: var(--gray-900);
}
.text-muted {
color: var(--gray-400);
font-size: 0.85rem;
}
/* Action List */
.action-list {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.action-link {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.625rem 0.75rem;
border-radius: 0.375rem;
text-decoration: none;
color: var(--gray-700);
font-size: 0.9rem;
transition: all 0.15s;
}
.action-link:hover {
background: var(--color-primary-pale);
color: var(--color-primary);
text-decoration: none;
}
.action-icon {
font-size: 1.1rem;
}
/* Topic Link */
.topic-link {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--gray-50);
border-radius:0.25rem;
text-decoration: none;
transition: all 0.15s;
}
.topic-link:hover {
background: var(--color-primary-pale);
text-decoration: none;
}
.topic-icon {
font-size: 1.5rem;
}
.topic-icon-img {
width: 32px;
height: 32px;
border-radius: 0.25rem;
object-fit: cover;
flex-shrink: 0;
}
.topic-name {
font-weight: 500;
color: var(--gray-900);
}
/* Responsive */
@media (max-width: 1024px) {
.page-layout {
grid-template-columns: 1fr;
}
.page-sidebar {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
}
@media (max-width: 768px) {
.page-show-fullwidth {
overflow-x: hidden;
}
.page-body {
padding: 1rem;
}
.page-content {
padding: 1rem;
overflow: visible;
}
.table-scroll-wrapper { border-radius: 0; }
.responsibility-bar {
flex-direction: column;
gap: 0.75rem;
}
.page-sidebar {
grid-template-columns: 1fr;
}
.att-card {
padding: 0.75rem 1rem;
}
.att-action {
opacity: 1;
}
.children-grid .child-card {
padding: 0.625rem;
}
}
@media (max-width: 480px) {
.page-body {
padding: 0.75rem;
}
.page-content {
padding: 0.75rem;
}
.sidebar-card {
padding: 1rem;
}
}
/* Ansprechpartner Card */
.ap-link {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.5rem;
text-decoration: none;
color: inherit;
border-radius:0.25rem;
transition: background 0.15s;
}
.ap-link:hover {
background: var(--gray-100);
text-decoration: none;
}
.ap-avatar {
width: 44px;
height: 44px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: linear-gradient(135deg, var(--blue-500), var(--blue-800));
display: flex;
align-items: center;
justify-content: center;
}
.ap-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.ap-avatar-letter {
font-size: 1.1rem;
font-weight: 600;
color: var(--color-on-accent);
}
.ap-info {
display: flex;
flex-direction: column;
gap: 0.125rem;
min-width: 0;
}
.ap-name {
font-weight: 600;
color: var(--gray-900);
font-size: 0.875rem;
}
.ap-detail {
font-size: 0.8rem;
color: var(--gray-500);
}
.ap-company {
color: var(--color-primary);
}
.ap-chips {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
padding: 0.5rem 0.5rem 0;
margin-top: 0.25rem;
}
.ap-chip {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.3rem 0.625rem;
background: var(--gray-100);
color: var(--gray-700);
border: 1px solid var(--gray-200);
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
text-decoration: none;
transition: all 0.15s;
white-space: nowrap;
}
.ap-chip:hover {
background: var(--gray-200);
border-color: var(--gray-300);
color: var(--gray-900);
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0,0,0,0.08);
text-decoration: none;
}
.ap-chip svg {
flex-shrink: 0;
color: var(--gray-500);
}
/* Tags Bar */
.resp-tags {
flex-wrap: wrap;
}
.resp-tags-list {
display: inline-flex;
flex-wrap: wrap;
gap: 0.375rem;
}
.resp-tag {
display: inline-block;
padding: 0.15rem 0.5rem;
border-radius: 9999px;
font-size: 0.7rem;
font-weight: 500;
text-decoration: none;
transition: all 0.15s;
}
.resp-tag:hover {
text-decoration: none;
filter: brightness(0.9);
}
/* Sidebar Attachments */
.sidebar-files-list {
display: flex;
flex-direction: column;
gap: 0.375rem;
}
.sidebar-file-item {
display: flex;
align-items: center;
gap: 0.625rem;
padding: 0.5rem 0.625rem;
border-radius: 0.375rem;
text-decoration: none;
color: inherit;
transition: background 0.12s;
border: 1px solid var(--gray-100);
}
.sidebar-file-item:hover {
background: var(--gray-50);
text-decoration: none;
}
.sidebar-file-ext {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 0.375rem;
background: var(--color-primary-pale);
color: var(--color-primary);
font-size: 0.55rem;
font-weight: 700;
flex-shrink: 0;
letter-spacing: 0.03em;
}
.sidebar-file-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.sidebar-file-name {
font-size: 0.8rem;
font-weight: 500;
color: var(--gray-900);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sidebar-file-size {
font-size: 0.7rem;
color: var(--gray-400);
}
</style>
<script>
// Lightbox fuer Bilder in WYSIWYG-Content
(function() {
var overlay = null;
function openLightbox(src) {
if (overlay) overlay.remove();
overlay = document.createElement('div');
overlay.className = 'lightbox-overlay';
overlay.innerHTML = '<button class="lightbox-close">×</button><img src="' + src + '" alt="">';
document.body.appendChild(overlay);
// Trigger reflow for animation
overlay.offsetHeight;
overlay.classList.add('active');
document.body.style.overflow = 'hidden';
overlay.addEventListener('click', closeLightbox);
document.addEventListener('keydown', onEsc);
}
function closeLightbox() {
if (!overlay) return;
overlay.classList.remove('active');
setTimeout(function() {
if (overlay) overlay.remove();
overlay = null;
}, 200);
document.body.style.overflow = '';
document.removeEventListener('keydown', onEsc);
}
function onEsc(e) {
if (e.key === 'Escape') closeLightbox();
}
document.querySelectorAll('.wysiwyg-content img').forEach(function(img) {
img.addEventListener('click', function(e) {
e.preventDefault();
openLightbox(this.src);
});
});
})();
// Seitenverknüpfung Suche + Toggle
(function() {
var addBtn = document.getElementById('lpAddBtn');
var addForm = document.getElementById('addLinkForm');
var input = document.getElementById('linkSearchInput');
var resultsDiv = document.getElementById('linkSearchResults');
// Toggle-Button fuer Suchfeld
if (addBtn && addForm) {
addBtn.addEventListener('click', function() {
var isOpen = addForm.style.display !== 'none';
if (isOpen) {
addForm.style.display = 'none';
addBtn.classList.remove('active');
addBtn.setAttribute('aria-expanded', 'false');
if (input) input.value = '';
if (resultsDiv) hideResults();
} else {
addForm.style.display = '';
addBtn.classList.add('active');
addBtn.setAttribute('aria-expanded', 'true');
if (input) input.focus();
}
});
}
if (!input || !resultsDiv) return;
var pageId = <?= (int)$page['id'] ?>;
var timer = null;
var activeIndex = -1;
function items() {
return Array.prototype.slice.call(resultsDiv.querySelectorAll('.link-search-item'));
}
/** Hebt genau einen Treffer hervor; der Index läuft zyklisch um die Liste. */
function setActive(index) {
var list = items();
if (!list.length) { activeIndex = -1; return; }
if (index < 0) { index = list.length - 1; }
if (index >= list.length) { index = 0; }
activeIndex = index;
list.forEach(function(el, i) {
var on = (i === activeIndex);
el.classList.toggle('is-active', on);
el.setAttribute('aria-selected', on ? 'true' : 'false');
if (on) {
input.setAttribute('aria-activedescendant', el.id);
if (el.scrollIntoView) { el.scrollIntoView({ block: 'nearest' }); }
}
});
}
function showResults() {
resultsDiv.style.display = 'block';
input.setAttribute('aria-expanded', 'true');
}
function hideResults() {
resultsDiv.style.display = 'none';
input.setAttribute('aria-expanded', 'false');
input.removeAttribute('aria-activedescendant');
activeIndex = -1;
}
/**
* Legt die Verknüpfung zum gewählten Treffer an (Maus- wie Tastaturauswahl).
* Seiten und Objekte gehen an verschiedene Adressen; die Art steht am Treffer.
*/
function selectItem(el) {
if (!el) return;
var id = el.getAttribute('data-id');
var kind = el.getAttribute('data-kind');
var type = el.getAttribute('data-type');
var form = document.createElement('form');
form.method = 'POST';
if (kind === 'object') {
form.action = '/pages/' + pageId + '/object-links';
form.innerHTML = '<input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">' +
'<input type="hidden" name="object_type" value="' + type + '">' +
'<input type="hidden" name="object_id" value="' + id + '">';
} else {
form.action = '/pages/' + pageId + '/links';
form.innerHTML = '<input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">' +
'<input type="hidden" name="linked_page_id" value="' + id + '">';
}
document.body.appendChild(form);
form.submit();
}
input.addEventListener('input', function() {
clearTimeout(timer);
var q = this.value.trim();
if (q.length < 2) {
hideResults();
return;
}
timer = setTimeout(function() {
fetch('/pages/' + pageId + '/links/search?q=' + encodeURIComponent(q))
.then(function(r) { return r.json(); })
.then(function(data) {
activeIndex = -1;
input.removeAttribute('aria-activedescendant');
if (!data.length) {
resultsDiv.innerHTML = '<div class="link-search-empty">Nichts gefunden</div>';
} else {
resultsDiv.innerHTML = data.map(function(p, i) {
return '<div class="link-search-item" role="option" aria-selected="false" ' +
'id="linkSearchItem' + i + '" data-id="' + p.id + '" ' +
'data-kind="' + escHtml(p.kind) + '" data-type="' + escHtml(p.type || '') + '">' +
'<span class="lsi-title"><i class="fas ' + escHtml(p.icon) + '"></i> ' + escHtml(p.title) + '</span>' +
'<span class="lsi-topic">' + escHtml(p.subtitle) + '</span>' +
'</div>';
}).join('');
items().forEach(function(el, i) {
el.addEventListener('click', function() { selectItem(el); });
el.addEventListener('mousemove', function() { setActive(i); });
});
}
showResults();
});
}, 300);
});
input.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
hideResults();
return;
}
if (resultsDiv.style.display === 'none') return;
if (e.key === 'ArrowDown') {
e.preventDefault();
setActive(activeIndex + 1);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
setActive(activeIndex - 1);
} else if (e.key === 'Enter' && activeIndex >= 0) {
e.preventDefault();
selectItem(items()[activeIndex]);
}
});
document.addEventListener('click', function(e) {
if (!input.contains(e.target) && !resultsDiv.contains(e.target)) {
hideResults();
}
});
function escHtml(s) {
var d = document.createElement('div');
d.textContent = s;
return d.innerHTML;
}
})();
// Verknüpfung entfernen: Bestätigung über den zentralen Modal-Dialog
(function() {
var modal = document.getElementById('lpRemoveModal');
if (!modal) return;
var confirmBtn = document.getElementById('lpRemoveModalConfirm');
var cancelBtn = document.getElementById('lpRemoveModalCancel');
var closeBtn = document.getElementById('lpRemoveModalClose');
var targetEl = document.getElementById('lpRemoveModalTarget');
var pendingForm = null;
var lastFocus = null;
function openModal(form) {
pendingForm = form;
lastFocus = document.activeElement;
var title = form.getAttribute('data-lp-title');
if (targetEl) {
targetEl.textContent = title ? '„' + title + '“' : 'dieser Seite';
}
modal.style.display = 'flex';
if (confirmBtn) confirmBtn.focus();
}
function closeModal() {
modal.style.display = 'none';
pendingForm = null;
if (lastFocus && lastFocus.focus) lastFocus.focus();
}
document.querySelectorAll('.lp-remove-form').forEach(function(form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
openModal(form);
});
});
if (confirmBtn) {
confirmBtn.addEventListener('click', function() {
var form = pendingForm;
if (!form) return;
modal.style.display = 'none';
pendingForm = null;
// submit() umgeht den submit-Listener und sendet direkt ab
form.submit();
});
}
if (cancelBtn) cancelBtn.addEventListener('click', closeModal);
if (closeBtn) closeBtn.addEventListener('click', closeModal);
modal.addEventListener('click', function(e) {
if (e.target === modal) closeModal();
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && modal.style.display !== 'none') closeModal();
});
})();
// Tabellen in Scroll-Container einbetten (verhindert horizontalen Overflow)
(function() {
document.querySelectorAll('.wysiwyg-content table').forEach(function(table) {
if (table.closest('.table-scroll-wrapper')) return;
var wrapper = document.createElement('div');
wrapper.className = 'table-scroll-wrapper';
table.parentNode.insertBefore(wrapper, table);
wrapper.appendChild(table);
});
})();
</script>