383 lines
31 KiB
PHP
383 lines
31 KiB
PHP
<?php require __DIR__ . '/settings_nav.php'; ?>
|
||
<div class="d-flex flex-wrap justify-content-between align-items-start gap-2 mb-3">
|
||
<div>
|
||
<h2 class="mb-1"><?= h(t('public_site.settings_heading')) ?></h2>
|
||
<div class="text-muted"><?= h(t('public_site.settings_intro')) ?></div>
|
||
</div><a class="btn btn-outline-primary" href="<?= h(PublicSiteController::url()) ?>" target="_blank">↗
|
||
<?= h(t('public_site.preview')) ?></a>
|
||
</div>
|
||
<?php if ($saved): ?><div class="alert alert-success">✅ <?= h(t('public_site.saved')) ?></div>
|
||
<?php endif; ?><?php if ($error): ?><div class="alert alert-danger">⚠️ <?= h($error) ?></div><?php endif; ?>
|
||
<div class="card mb-3">
|
||
<div class="card-header"><h3 class="card-title">🖼️ <?= h(t('public_site.image_library')) ?></h3></div>
|
||
<div class="card-body">
|
||
<form id="public-image-upload" method="post" action="/settings/public-site/image" enctype="multipart/form-data" class="row g-2 align-items-end mb-3">
|
||
<input type="hidden" name="csrf" value="<?= h(Auth::csrf()) ?>">
|
||
<div class="col-md"><label class="form-label"><?= h(t('public_site.image_file')) ?></label><input class="form-control" type="file" name="public_site_image" accept="image/jpeg,image/png,image/webp" required></div>
|
||
<div class="col-md-auto"><button class="btn btn-outline-primary"><?= h(t('public_site.image_upload')) ?></button></div>
|
||
</form>
|
||
<div class="form-hint mb-3" id="public-image-help"><?= h(t('public_site.image_help')) ?></div>
|
||
<div class="text-muted<?= $images ? ' d-none' : '' ?>" id="public-image-empty"><?= h(t('public_site.image_none')) ?></div>
|
||
<div class="row g-3" id="public-image-library">
|
||
<?php foreach ($images as $image): ?><div class="col-6 col-md-3 col-xl-2">
|
||
<div class="card h-100"><img src="<?= h($image['url']) ?>" alt="" class="card-img-top" style="height:110px;object-fit:cover">
|
||
<div class="card-body p-2"><button type="button" class="btn btn-sm btn-outline-secondary w-100 public-image-insert" data-url="<?= h($image['url']) ?>"><?= h(t('public_site.image_insert')) ?></button></div>
|
||
</div>
|
||
</div><?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<form method="post" action="/settings/public-site/save"><input type="hidden" name="csrf" value="<?= h(Auth::csrf()) ?>">
|
||
<input type="hidden" id="public-site-navigation-order" name="public_site_navigation_order" value="<?= h($settings['public_site_navigation_order'] ?? '') ?>">
|
||
<div class="card mb-3">
|
||
<div class="card-status-top bg-green"></div>
|
||
<div class="card-header">
|
||
<h3 class="card-title"><?= h(t('public_site.activation_style')) ?></h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row g-3">
|
||
<div class="col-12"><label class="form-check form-switch"><input class="form-check-input"
|
||
type="checkbox" name="public_site_enabled" value="1"
|
||
<?= ($settings['public_site_enabled'] ?? '0') === '1' ? 'checked' : '' ?>><span
|
||
class="form-check-label fw-bold"><?= h(t('public_site.enable')) ?></span></label>
|
||
<div class="form-hint"><?= h(t('public_site.enable_help')) ?></div>
|
||
</div>
|
||
<div class="col-12"><label class="form-label"><?= h(t('public_site.main_address')) ?></label>
|
||
<div class="row g-2">
|
||
<div class="col-md-6"><label class="form-selectgroup-item w-100"><input
|
||
class="form-selectgroup-input" type="radio" name="public_site_routing"
|
||
value="integrated"
|
||
<?= ($settings['public_site_routing'] ?? 'integrated') === 'integrated' ? 'checked' : '' ?>><span
|
||
class="form-selectgroup-label d-block"><strong><?= h(t('public_site.routing_management')) ?></strong><span
|
||
class="d-block text-muted small"><?= h(t('public_site.routing_management_help')) ?></span></span></label>
|
||
</div>
|
||
<div class="col-md-6"><label class="form-selectgroup-item w-100"><input
|
||
class="form-selectgroup-input" type="radio" name="public_site_routing" value="root"
|
||
<?= ($settings['public_site_routing'] ?? 'integrated') === 'root' ? 'checked' : '' ?>><span
|
||
class="form-selectgroup-label d-block"><strong><?= h(t('public_site.routing_public')) ?></strong><span
|
||
class="d-block text-muted small"><?= h(t('public_site.routing_public_help')) ?></span></span></label>
|
||
</div>
|
||
</div>
|
||
<div class="form-hint mt-2"><?= h(t('public_site.routing_no_server')) ?></div>
|
||
</div>
|
||
<div class="col-12"><label class="form-label"><?= h(t('public_site.theme')) ?></label>
|
||
<div class="row g-2">
|
||
<?php foreach (['warm' => ['🧡',t('public_site.theme_warm')],'nature' => ['🌿',t('public_site.theme_nature')],'minimal' => ['◻️',t('public_site.theme_minimal')],'custom' => ['🎨',t('public_site.theme_custom')]] as $key => $theme): ?>
|
||
<div class="col-md-3"><label class="form-selectgroup-item w-100"><input type="radio"
|
||
name="public_site_theme" value="<?= h($key) ?>" class="form-selectgroup-input"
|
||
<?= ($settings['public_site_theme'] ?? 'warm') === $key ? 'checked' : '' ?>><span
|
||
class="form-selectgroup-label d-flex align-items-center gap-2"><?= $theme[0] ?>
|
||
<strong><?= h($theme[1]) ?></strong></span></label></div><?php endforeach; ?></div>
|
||
</div>
|
||
<div class="col-md-6"><label class="form-label"><?= h(t('public_site.site_name')) ?></label><input
|
||
class="form-control" name="public_site_name" value="<?= h($settings['public_site_name']) ?>"
|
||
placeholder="<?= h($settings['association_name']) ?>"></div>
|
||
<div class="col-12"><label class="form-label"><?= h(t('public_site.custom_css')) ?></label><textarea
|
||
class="form-control font-monospace" name="public_site_custom_css" rows="8"
|
||
placeholder=":root { --accent: #d87945; }"><?= h($settings['public_site_custom_css']) ?></textarea>
|
||
<div class="form-hint"><?= h(t('public_site.custom_css_help')) ?></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-2">
|
||
<div><h3 class="mb-0"><?= h(t('public_site.site_pages')) ?></h3><div class="text-muted small"><?= h(t('public_site.site_pages_help')) ?></div></div>
|
||
<button class="btn btn-outline-primary" type="button" id="public-page-add">+ <?= h(t('public_site.add_page')) ?></button>
|
||
</div>
|
||
<div id="public-pages-sortable" class="mb-3">
|
||
<details class="card mb-2 public-page-panel public-sortable-page" data-page-key="home" draggable="true" open>
|
||
<summary class="card-header gap-2">
|
||
<span class="public-page-drag" title="<?= h(t('public_site.drag_page')) ?>" aria-hidden="true">⠿</span>
|
||
<h3 class="card-title">🏠 <?= h(t('public_site.home')) ?></h3>
|
||
<span class="ms-auto d-flex gap-1 public-page-actions"><button class="btn btn-sm btn-icon btn-outline-secondary public-page-up" type="button" aria-label="<?= h(t('public_site.move_up')) ?>">↑</button><button class="btn btn-sm btn-icon btn-outline-secondary public-page-down" type="button" aria-label="<?= h(t('public_site.move_down')) ?>">↓</button><span class="public-page-chevron" aria-hidden="true">⌄</span></span>
|
||
</summary>
|
||
<div class="card-body row g-3">
|
||
<div class="col-12"><label class="form-label"><?= h(t('common.title')) ?></label><input class="form-control"
|
||
name="public_site_home_title" value="<?= h($settings['public_site_home_title']) ?>" required></div>
|
||
<div class="col-12"><label class="form-label"><?= h(t('common.text')) ?></label><textarea
|
||
class="form-control public-rich-text" name="public_site_home_text"
|
||
rows="4"><?= h($settings['public_site_home_text']) ?></textarea></div>
|
||
</div>
|
||
</details>
|
||
<div class="card mb-2 public-sortable-page" data-page-key="animals" draggable="true"><div class="card-header gap-2"><span class="public-page-drag" title="<?= h(t('public_site.drag_page')) ?>" aria-hidden="true">⠿</span><h3 class="card-title">🐾 <?= h(t('public_site.animals')) ?></h3><span class="ms-auto d-flex gap-1 public-page-actions"><button class="btn btn-sm btn-icon btn-outline-secondary public-page-up" type="button" aria-label="<?= h(t('public_site.move_up')) ?>">↑</button><button class="btn btn-sm btn-icon btn-outline-secondary public-page-down" type="button" aria-label="<?= h(t('public_site.move_down')) ?>">↓</button></span></div></div>
|
||
<details class="card mb-2 public-page-panel public-sortable-page" data-page-key="about" draggable="true">
|
||
<summary class="card-header gap-2">
|
||
<span class="public-page-drag" title="<?= h(t('public_site.drag_page')) ?>" aria-hidden="true">⠿</span>
|
||
<h3 class="card-title">📖 <?= h(t('public_site.free_page')) ?></h3>
|
||
<span class="ms-auto d-flex gap-1 public-page-actions"><button class="btn btn-sm btn-icon btn-outline-secondary public-page-up" type="button" aria-label="<?= h(t('public_site.move_up')) ?>">↑</button><button class="btn btn-sm btn-icon btn-outline-secondary public-page-down" type="button" aria-label="<?= h(t('public_site.move_down')) ?>">↓</button><span class="public-page-chevron" aria-hidden="true">⌄</span></span>
|
||
</summary>
|
||
<div class="card-body row g-3">
|
||
<div class="col-12"><label class="form-check form-switch"><input class="form-check-input" type="checkbox"
|
||
name="public_site_about_enabled" value="1"
|
||
<?= ($settings['public_site_about_enabled'] ?? '0') === '1' ? 'checked' : '' ?>><span
|
||
class="form-check-label"><?= h(t('public_site.show_free_page')) ?></span></label></div>
|
||
<div class="col-md-4"><label class="form-label"><?= h(t('common.title')) ?></label><input
|
||
class="form-control" name="public_site_about_title"
|
||
value="<?= h($settings['public_site_about_title']) ?>"></div>
|
||
<div class="col-md-8"><label class="form-label"><?= h(t('common.text')) ?></label><textarea
|
||
class="form-control public-rich-text" name="public_site_about_text"
|
||
rows="5"><?= h($settings['public_site_about_text']) ?></textarea></div>
|
||
</div>
|
||
</details>
|
||
<details class="card mb-2 public-page-panel public-sortable-page" data-page-key="donation" draggable="true">
|
||
<summary class="card-header gap-2">
|
||
<span class="public-page-drag" title="<?= h(t('public_site.drag_page')) ?>" aria-hidden="true">⠿</span>
|
||
<h3 class="card-title">💝 <?= h(t('public_site.donation')) ?></h3>
|
||
<span class="ms-auto d-flex gap-1 public-page-actions"><button class="btn btn-sm btn-icon btn-outline-secondary public-page-up" type="button" aria-label="<?= h(t('public_site.move_up')) ?>">↑</button><button class="btn btn-sm btn-icon btn-outline-secondary public-page-down" type="button" aria-label="<?= h(t('public_site.move_down')) ?>">↓</button><span class="public-page-chevron" aria-hidden="true">⌄</span></span>
|
||
</summary>
|
||
<div class="card-body row g-3">
|
||
<div class="col-md-4"><label class="form-label"><?= h(t('common.title')) ?></label><input
|
||
class="form-control" name="public_site_donation_title"
|
||
value="<?= h($settings['public_site_donation_title']) ?>"></div>
|
||
<div class="col-md-8"><label class="form-label"><?= h(t('public_site.donation_url')) ?></label><input
|
||
class="form-control" type="url" name="public_site_donation_url"
|
||
value="<?= h($settings['public_site_donation_url']) ?>" placeholder="https://..."></div>
|
||
<div class="col-12"><label class="form-label"><?= h(t('common.text')) ?></label><textarea
|
||
class="form-control public-rich-text" name="public_site_donation_text"
|
||
rows="4"><?= h($settings['public_site_donation_text']) ?></textarea></div>
|
||
</div>
|
||
</details>
|
||
<details class="card mb-2 public-page-panel public-sortable-page" data-page-key="contact" draggable="true">
|
||
<summary class="card-header gap-2">
|
||
<span class="public-page-drag" title="<?= h(t('public_site.drag_page')) ?>" aria-hidden="true">⠿</span>
|
||
<h3 class="card-title">✉️ <?= h(t('public_site.contact')) ?></h3>
|
||
<span class="ms-auto d-flex gap-1 public-page-actions"><button class="btn btn-sm btn-icon btn-outline-secondary public-page-up" type="button" aria-label="<?= h(t('public_site.move_up')) ?>">↑</button><button class="btn btn-sm btn-icon btn-outline-secondary public-page-down" type="button" aria-label="<?= h(t('public_site.move_down')) ?>">↓</button><span class="public-page-chevron" aria-hidden="true">⌄</span></span>
|
||
</summary>
|
||
<div class="card-body row g-3">
|
||
<div class="col-12">
|
||
<div class="alert alert-info py-2"><?= h(t('public_site.contact_reuse')) ?></div><label
|
||
class="form-label"><?= h(t('common.text')) ?></label><textarea class="form-control public-rich-text"
|
||
name="public_site_contact_text" rows="3"><?= h($settings['public_site_contact_text']) ?></textarea>
|
||
</div>
|
||
<div class="col-md-6"><label class="form-label">Facebook</label><input class="form-control" type="url"
|
||
name="public_site_facebook_url" value="<?= h($settings['public_site_facebook_url']) ?>"></div>
|
||
<div class="col-md-6"><label class="form-label">Instagram</label><input class="form-control" type="url"
|
||
name="public_site_instagram_url" value="<?= h($settings['public_site_instagram_url']) ?>"></div>
|
||
<?php foreach (['youtube' => 'YouTube','tiktok' => 'TikTok','whatsapp' => 'WhatsApp','linkedin' => 'LinkedIn','x' => 'X','snapchat' => 'Snapchat'] as $network => $label): ?>
|
||
<div class="col-md-6"><label class="form-label"><?= h($label) ?></label><input class="form-control"
|
||
type="url" name="public_site_<?= h($network) ?>_url"
|
||
value="<?= h($settings['public_site_' . $network . '_url']) ?>" placeholder="https://..."></div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</details>
|
||
<?php foreach (($customPages ?? []) as $index => $page): ?>
|
||
<details class="card mb-2 public-page-panel public-custom-page public-sortable-page" data-page-key="custom:<?= h($page['slug']) ?>" draggable="true">
|
||
<summary class="card-header gap-2">
|
||
<span class="public-page-drag" title="<?= h(t('public_site.drag_page')) ?>" aria-hidden="true">⠿</span>
|
||
<h3 class="card-title public-page-summary-title"><?= h($page['title']) ?></h3>
|
||
<span class="ms-auto d-flex gap-1 public-page-actions">
|
||
<button class="btn btn-sm btn-icon btn-outline-secondary public-page-up" type="button" title="<?= h(t('public_site.move_up')) ?>" aria-label="<?= h(t('public_site.move_up')) ?>">↑</button>
|
||
<button class="btn btn-sm btn-icon btn-outline-secondary public-page-down" type="button" title="<?= h(t('public_site.move_down')) ?>" aria-label="<?= h(t('public_site.move_down')) ?>">↓</button>
|
||
<span class="public-page-chevron" aria-hidden="true">⌄</span>
|
||
</span>
|
||
</summary>
|
||
<div class="card-body row g-3">
|
||
<input type="hidden" name="pages[<?= $index ?>][id]" value="<?= (int) $page['id'] ?>">
|
||
<input class="public-page-position" type="hidden" name="pages[<?= $index ?>][position]" value="<?= $index ?>">
|
||
<div class="col-12"><label class="form-check form-switch"><input class="form-check-input" type="checkbox" name="pages[<?= $index ?>][enabled]" value="1" <?= (int) $page['enabled'] === 1 ? 'checked' : '' ?>><span class="form-check-label"><?= h(t('public_site.page_published')) ?></span></label></div>
|
||
<div class="col-md-7"><label class="form-label"><?= h(t('public_site.page_title')) ?></label><input class="form-control public-page-title" name="pages[<?= $index ?>][title]" value="<?= h($page['title']) ?>" required></div>
|
||
<div class="col-md-5"><label class="form-label"><?= h(t('public_site.page_slug')) ?></label><input class="form-control public-page-slug" name="pages[<?= $index ?>][slug]" value="<?= h($page['slug']) ?>" required><div class="form-hint"><?= h(t('public_site.page_slug_help')) ?></div></div>
|
||
<div class="col-12"><label class="form-label"><?= h(t('common.text')) ?></label><textarea class="form-control public-rich-text" name="pages[<?= $index ?>][content]" rows="8"><?= h($page['content']) ?></textarea></div>
|
||
<div class="col-12"><label class="form-check text-danger"><input class="form-check-input" type="checkbox" name="pages[<?= $index ?>][delete]" value="1"><span class="form-check-label"><?= h(t('public_site.delete_page')) ?></span></label></div>
|
||
</div>
|
||
</details>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<template id="public-page-template">
|
||
<details class="card mb-2 public-page-panel public-custom-page public-sortable-page" data-page-key="custom:" draggable="true" open>
|
||
<summary class="card-header gap-2"><span class="public-page-drag" title="<?= h(t('public_site.drag_page')) ?>" aria-hidden="true">⠿</span><h3 class="card-title public-page-summary-title"><?= h(t('public_site.new_page')) ?></h3><span class="ms-auto d-flex gap-1 public-page-actions"><button class="btn btn-sm btn-icon btn-outline-secondary public-page-up" type="button" aria-label="<?= h(t('public_site.move_up')) ?>">↑</button><button class="btn btn-sm btn-icon btn-outline-secondary public-page-down" type="button" aria-label="<?= h(t('public_site.move_down')) ?>">↓</button><span class="public-page-chevron" aria-hidden="true">⌄</span></span></summary>
|
||
<div class="card-body row g-3"><input class="public-page-position" type="hidden" name="pages[__INDEX__][position]" value="0"><div class="col-12"><label class="form-check form-switch"><input class="form-check-input" type="checkbox" name="pages[__INDEX__][enabled]" value="1" checked><span class="form-check-label"><?= h(t('public_site.page_published')) ?></span></label></div><div class="col-md-7"><label class="form-label"><?= h(t('public_site.page_title')) ?></label><input class="form-control public-page-title" name="pages[__INDEX__][title]" required></div><div class="col-md-5"><label class="form-label"><?= h(t('public_site.page_slug')) ?></label><input class="form-control public-page-slug" name="pages[__INDEX__][slug]" required><div class="form-hint"><?= h(t('public_site.page_slug_help')) ?></div></div><div class="col-12"><label class="form-label"><?= h(t('common.text')) ?></label><textarea class="form-control public-rich-text" name="pages[__INDEX__][content]" rows="8"></textarea></div><div class="col-12"><button class="btn btn-outline-danger public-page-remove" type="button"><?= h(t('public_site.delete_page')) ?></button></div></div>
|
||
</details>
|
||
</template>
|
||
<details class="card mb-3 public-page-panel">
|
||
<summary class="card-header">
|
||
<h3 class="card-title">⚖️ <?= h(t('public_site.legal_privacy')) ?></h3>
|
||
<span class="public-page-chevron" aria-hidden="true">⌄</span>
|
||
</summary>
|
||
<div class="card-body row g-3">
|
||
<div class="col-md-6"><label class="form-label"><?= h(t('public_site.legal')) ?></label><textarea
|
||
class="form-control" name="public_site_legal_text"
|
||
rows="16"><?= h(PublicSiteController::legalText($settings)) ?></textarea></div>
|
||
<div class="col-md-6"><label class="form-label"><?= h(t('public_site.privacy')) ?></label><textarea
|
||
class="form-control" name="public_site_privacy_text"
|
||
rows="16"><?= h(PublicSiteController::privacyText($settings)) ?></textarea></div>
|
||
<div class="col-12 form-hint"><?= h(t('public_site.legal_hint')) ?></div>
|
||
</div>
|
||
</details>
|
||
<div class="text-end mb-4"><button class="btn btn-primary"><?= h(t('common.save')) ?></button></div>
|
||
</form>
|
||
<style>
|
||
.public-page-panel>summary{cursor:pointer;display:flex;align-items:center;list-style:none}.public-page-panel>summary::-webkit-details-marker{display:none}.public-page-chevron{display:inline-flex;transition:transform .2s;font-size:1.25rem}.public-page-panel[open]>summary .public-page-chevron{transform:rotate(180deg)}.public-page-drag{cursor:grab;font-size:1.35rem;color:var(--tblr-secondary);padding:.25rem}.public-custom-page.is-dragging{opacity:.45}.public-custom-page.drag-over{outline:2px dashed var(--tblr-primary);outline-offset:2px}.public-page-actions button{position:relative;z-index:2}
|
||
</style>
|
||
<script>
|
||
let activePublicEditor = null;
|
||
const imageLibrary = document.getElementById('public-image-library');
|
||
const imageHelp = document.getElementById('public-image-help');
|
||
const insertImage = (button) => {
|
||
const textarea = activePublicEditor || document.querySelector('.public-rich-text');
|
||
if (!textarea) return;
|
||
const alt = window.prompt(<?= json_encode(t('public_site.image_alt_prompt'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>, '');
|
||
if (alt === null) return;
|
||
const safeAlt = alt.replace(/[\[\]]/g, '').trim() || <?= json_encode(t('public_site.image_default_alt'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||
textarea.setRangeText(`\n`, textarea.selectionStart, textarea.selectionEnd, 'end');
|
||
textarea.focus();
|
||
};
|
||
const enhanceTextarea = (textarea) => {
|
||
if (textarea.dataset.autoResize === '1') return;
|
||
textarea.dataset.autoResize = '1';
|
||
const resize = () => {
|
||
textarea.style.height = 'auto';
|
||
textarea.style.height = Math.max(140, textarea.scrollHeight + 8) + 'px';
|
||
};
|
||
textarea.addEventListener('input', resize);
|
||
resize();
|
||
};
|
||
const enhancePublicEditor = (textarea) => {
|
||
enhanceTextarea(textarea);
|
||
if (textarea.dataset.richEditor === '1') return;
|
||
textarea.dataset.richEditor = '1';
|
||
textarea.addEventListener('focus', () => { activePublicEditor = textarea; });
|
||
const toolbar = document.createElement('div');
|
||
toolbar.className = 'btn-list mb-2';
|
||
const actions = [['B', '**', '**'], ['I', '*', '*'], ['Titre', '## ', ''], ['Liste', '- ', ''], ['Lien', '[', '](https://)'], [<?= json_encode(t('public_site.markdown_table'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>, '| Colonne 1 | Colonne 2 |\n| --- | --- |\n| Valeur 1 | Valeur 2 |\n', '']];
|
||
actions.forEach(([label, before, after]) => {
|
||
const button = document.createElement('button');
|
||
button.type = 'button';
|
||
button.className = 'btn btn-sm btn-outline-secondary';
|
||
button.textContent = label;
|
||
button.addEventListener('click', () => {
|
||
const start = textarea.selectionStart;
|
||
const end = textarea.selectionEnd;
|
||
const selected = textarea.value.slice(start, end);
|
||
textarea.setRangeText(before + selected + after, start, end, 'select');
|
||
textarea.focus();
|
||
});
|
||
toolbar.append(button);
|
||
});
|
||
const imageButton = document.createElement('button');
|
||
imageButton.type = 'button';
|
||
imageButton.className = 'btn btn-sm btn-outline-primary';
|
||
imageButton.textContent = <?= json_encode('🖼️ ' . t('public_site.image_insert'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||
imageButton.addEventListener('click', () => {
|
||
activePublicEditor = textarea;
|
||
imageHelp.textContent = <?= json_encode(t('public_site.image_target_selected'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||
imageLibrary.scrollIntoView({behavior: 'smooth', block: 'center'});
|
||
});
|
||
toolbar.append(imageButton);
|
||
textarea.before(toolbar);
|
||
};
|
||
document.querySelectorAll('textarea').forEach(enhanceTextarea);
|
||
document.querySelectorAll('.public-rich-text').forEach(enhancePublicEditor);
|
||
document.querySelectorAll('.public-image-insert').forEach((button) => {
|
||
button.addEventListener('click', () => insertImage(button));
|
||
});
|
||
document.getElementById('public-image-upload').addEventListener('submit', async (event) => {
|
||
event.preventDefault();
|
||
const form = event.currentTarget;
|
||
const submit = form.querySelector('button');
|
||
submit.disabled = true;
|
||
try {
|
||
const response = await fetch(form.action, {method: 'POST', headers: {'Accept': 'application/json'}, body: new FormData(form)});
|
||
const data = await response.json();
|
||
if (!response.ok) throw new Error(data.error || <?= json_encode(t('public_site.image_invalid'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>);
|
||
const column = document.createElement('div');
|
||
column.className = 'col-6 col-md-3 col-xl-2';
|
||
column.innerHTML = '<div class="card h-100"><img alt="" class="card-img-top" style="height:110px;object-fit:cover"><div class="card-body p-2"><button type="button" class="btn btn-sm btn-outline-secondary w-100 public-image-insert"></button></div></div>';
|
||
const image = column.querySelector('img');
|
||
const insert = column.querySelector('button');
|
||
image.src = data.url;
|
||
insert.dataset.url = data.url;
|
||
insert.textContent = <?= json_encode(t('public_site.image_insert'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||
insert.addEventListener('click', () => insertImage(insert));
|
||
imageLibrary.prepend(column);
|
||
document.getElementById('public-image-empty').classList.add('d-none');
|
||
form.reset();
|
||
insert.click();
|
||
} catch (error) {
|
||
window.alert(error.message);
|
||
} finally {
|
||
submit.disabled = false;
|
||
}
|
||
});
|
||
|
||
const pagesContainer = document.getElementById('public-pages-sortable');
|
||
const navigationOrderInput = document.getElementById('public-site-navigation-order');
|
||
let publicPageIndex = <?= (int) count($customPages ?? []) ?>;
|
||
const refreshPagePositions = () => {
|
||
const pages = [...pagesContainer.querySelectorAll('.public-sortable-page')];
|
||
pages.forEach((page, position) => {
|
||
const input = page.querySelector('.public-page-position');
|
||
if (input) input.value = String(position);
|
||
page.querySelector('.public-page-up')?.toggleAttribute('disabled', position === 0);
|
||
page.querySelector('.public-page-down')?.toggleAttribute('disabled', position === pages.length - 1);
|
||
});
|
||
navigationOrderInput.value = JSON.stringify(pages.map((page) => page.dataset.pageKey).filter((key) => key && key !== 'custom:'));
|
||
};
|
||
const slugify = (value) => value.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 80);
|
||
const wirePage = (page) => {
|
||
const title = page.querySelector('.public-page-title');
|
||
const slug = page.querySelector('.public-page-slug');
|
||
let slugEdited = Boolean(slug?.value);
|
||
slug?.addEventListener('input', () => { slugEdited = Boolean(slug.value); });
|
||
slug?.addEventListener('input', () => { page.dataset.pageKey = 'custom:' + slugify(slug.value); refreshPagePositions(); });
|
||
title?.addEventListener('input', () => {
|
||
page.querySelector('.public-page-summary-title').textContent = title.value.trim() || <?= json_encode(t('public_site.new_page'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||
if (!slugEdited && slug) {
|
||
slug.value = slugify(title.value);
|
||
page.dataset.pageKey = 'custom:' + slug.value;
|
||
refreshPagePositions();
|
||
}
|
||
});
|
||
page.querySelectorAll('.public-page-actions button').forEach((button) => button.addEventListener('click', (event) => event.stopPropagation()));
|
||
page.querySelectorAll('input,textarea,button').forEach((control) => control.addEventListener('mousedown', () => { page.draggable = false; }));
|
||
page.querySelector('.public-page-drag')?.addEventListener('mousedown', () => { page.draggable = true; });
|
||
page.querySelector('.public-page-up')?.addEventListener('click', () => {
|
||
if (page.previousElementSibling) pagesContainer.insertBefore(page, page.previousElementSibling);
|
||
refreshPagePositions();
|
||
});
|
||
page.querySelector('.public-page-down')?.addEventListener('click', () => {
|
||
if (page.nextElementSibling) pagesContainer.insertBefore(page.nextElementSibling, page);
|
||
refreshPagePositions();
|
||
});
|
||
page.querySelector('.public-page-remove')?.addEventListener('click', () => { page.remove(); refreshPagePositions(); });
|
||
page.querySelectorAll('textarea').forEach(enhanceTextarea);
|
||
page.querySelectorAll('.public-rich-text').forEach(enhancePublicEditor);
|
||
page.addEventListener('dragstart', (event) => {
|
||
if (!event.target.closest('.public-page-drag') && document.activeElement !== page.querySelector('.public-page-drag')) {
|
||
// The whole card remains draggable for browser compatibility.
|
||
}
|
||
page.classList.add('is-dragging');
|
||
event.dataTransfer.effectAllowed = 'move';
|
||
});
|
||
page.addEventListener('dragend', () => {
|
||
page.draggable = true;
|
||
page.classList.remove('is-dragging');
|
||
pagesContainer.querySelectorAll('.drag-over').forEach((item) => item.classList.remove('drag-over'));
|
||
refreshPagePositions();
|
||
});
|
||
};
|
||
let savedNavigationOrder = [];
|
||
try { savedNavigationOrder = JSON.parse(navigationOrderInput.value || '[]'); } catch (_) {}
|
||
const initialPages = [...pagesContainer.querySelectorAll('.public-sortable-page')];
|
||
const orderedPages = savedNavigationOrder.map((key) => initialPages.find((item) => item.dataset.pageKey === key)).filter(Boolean);
|
||
[...orderedPages, ...initialPages.filter((item) => !orderedPages.includes(item))].forEach((page) => pagesContainer.append(page));
|
||
pagesContainer.querySelectorAll('.public-sortable-page').forEach(wirePage);
|
||
pagesContainer.addEventListener('dragover', (event) => {
|
||
event.preventDefault();
|
||
const dragging = pagesContainer.querySelector('.is-dragging');
|
||
const target = event.target.closest('.public-sortable-page');
|
||
if (!dragging || !target || dragging === target) return;
|
||
pagesContainer.querySelectorAll('.drag-over').forEach((item) => item.classList.remove('drag-over'));
|
||
target.classList.add('drag-over');
|
||
const box = target.getBoundingClientRect();
|
||
pagesContainer.insertBefore(dragging, event.clientY < box.top + box.height / 2 ? target : target.nextElementSibling);
|
||
});
|
||
document.getElementById('public-page-add').addEventListener('click', () => {
|
||
const html = document.getElementById('public-page-template').innerHTML.replaceAll('__INDEX__', String(publicPageIndex++));
|
||
pagesContainer.insertAdjacentHTML('beforeend', html);
|
||
const page = pagesContainer.lastElementChild;
|
||
wirePage(page);
|
||
refreshPagePositions();
|
||
page.querySelector('.public-page-title').focus();
|
||
});
|
||
refreshPagePositions();
|
||
</script>
|