mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2026-02-04 10:35:30 +00:00
Basic site editor
This commit is contained in:
@@ -13,18 +13,11 @@
|
||||
|
||||
<div class="flex flex-col justify-end gap-y-4 pr-4">
|
||||
<div class="inputwrapper !mb-0">
|
||||
<div class="inputlabelrow">
|
||||
<label for="page-editor-select" class="inputlabel">Seite auswählen</label>
|
||||
</div>
|
||||
<select
|
||||
id="page-editor-select"
|
||||
name="key"
|
||||
class="inputinput"
|
||||
hx-get="/redaktion/seiten/form/"
|
||||
hx-trigger="change"
|
||||
hx-target="#page-editor-form"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="body">
|
||||
class="inputinput px-3 py-2 bg-white border border-slate-300 shadow-sm focus:border-slate-500 focus:ring-2 focus:ring-slate-400/30"
|
||||
onchange="window.location.href = '/redaktion/seiten/?key=' + encodeURIComponent(this.value);">
|
||||
{{- if $model.pages -}}
|
||||
{{- range $page := $model.pages -}}
|
||||
<option value="{{ $page.Key }}" {{ if eq $page.Key $model.selected_key }}selected{{ end }}>{{ $page.Title }}</option>
|
||||
@@ -41,3 +34,115 @@
|
||||
<div class="container-normal mx-auto mt-4 !px-0">
|
||||
{{ template "_page_form" $model }}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
if (window.pageEditorTinyMCEInit) {
|
||||
return;
|
||||
}
|
||||
window.pageEditorTinyMCEInit = true;
|
||||
|
||||
const selector = "textarea.page-html-editor";
|
||||
const formId = "page-editor-form";
|
||||
|
||||
function initEditors(root) {
|
||||
if (!window.tinymce) return;
|
||||
cleanupEditors(document);
|
||||
const container = root || document;
|
||||
const targets = Array.from(container.querySelectorAll(selector));
|
||||
if (targets.length === 0) return;
|
||||
|
||||
targets.forEach((textarea) => {
|
||||
if (!textarea.id) {
|
||||
textarea.id = "page-html-editor-" + Math.random().toString(36).slice(2);
|
||||
}
|
||||
const existing = tinymce.get(textarea.id);
|
||||
if (existing) {
|
||||
existing.remove();
|
||||
}
|
||||
});
|
||||
|
||||
targets.reduce((chain, textarea) => {
|
||||
return chain.then(() => {
|
||||
if (tinymce.get(textarea.id)) return Promise.resolve();
|
||||
textarea.style.visibility = "hidden";
|
||||
return tinymce.init({
|
||||
target: textarea,
|
||||
base_url: "/assets/vendor/tinymce",
|
||||
suffix: ".min",
|
||||
license_key: "gpl",
|
||||
menubar: false,
|
||||
branding: false,
|
||||
plugins: "advlist lists link code autoresize",
|
||||
toolbar: "undo redo | blocks | bold italic | bullist numlist | outdent indent | link | code removeformat",
|
||||
block_formats: "Absatz=p;Überschrift 2=h2;Überschrift 3=h3;Zitat=blockquote;Vorformatiert=pre",
|
||||
forced_root_block: "p",
|
||||
autoresize_bottom_margin: 16,
|
||||
content_style: "body { font-family: inherit; font-size: 1rem; } p { margin: 0 0 0.75rem; }",
|
||||
init_instance_callback: function (editor) {
|
||||
if (editor && editor.targetElm) {
|
||||
editor.targetElm.style.visibility = "";
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}, Promise.resolve());
|
||||
}
|
||||
|
||||
function cleanupEditors(root) {
|
||||
if (!window.tinymce) return;
|
||||
tinymce.remove();
|
||||
}
|
||||
|
||||
function waitForTinyMCE(callback) {
|
||||
if (window.tinymce) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
let retries = 0;
|
||||
const timer = setInterval(() => {
|
||||
if (window.tinymce || retries > 40) {
|
||||
clearInterval(timer);
|
||||
if (window.tinymce) callback();
|
||||
return;
|
||||
}
|
||||
retries += 1;
|
||||
}, 50);
|
||||
}
|
||||
|
||||
waitForTinyMCE(() => initEditors(document));
|
||||
|
||||
window.PageEditorCleanup = function () {
|
||||
cleanupEditors(document);
|
||||
};
|
||||
|
||||
window.PageEditorInit = function () {
|
||||
const form = document.getElementById(formId);
|
||||
waitForTinyMCE(() => {
|
||||
requestAnimationFrame(() => {
|
||||
setTimeout(() => initEditors(form || document), 0);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
let shouldInit = false;
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (!(node instanceof Element)) return;
|
||||
if (node.id === formId) {
|
||||
shouldInit = true;
|
||||
return;
|
||||
}
|
||||
if (node.querySelector && node.querySelector(selector)) {
|
||||
shouldInit = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
if (shouldInit) {
|
||||
window.PageEditorInit();
|
||||
}
|
||||
});
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -57,75 +57,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<trix-toolbar id="page-html-toolbar-{{ $index }}">
|
||||
<div class="trix-toolbar-container">
|
||||
<span class="trix-toolbar-group">
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="bold" data-trix-key="b" title="Fett">
|
||||
<i class="ri-bold"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="italic" data-trix-key="i" title="Kursiv">
|
||||
<i class="ri-italic"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="strike" title="Gestrichen">
|
||||
<i class="ri-strikethrough"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="Link">
|
||||
<i class="ri-links-line"></i>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<span class="trix-toolbar-group">
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="heading1" title="Überschrift">
|
||||
<i class="ri-h-1"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="quote" title="Zitat">
|
||||
<i class="ri-double-quotes-l"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="bullet" title="Liste">
|
||||
<i class="ri-list-unordered"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-attribute="number" title="Aufzählung">
|
||||
<i class="ri-list-ordered"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-action="decreaseNestingLevel" title="Einzug verkleinern">
|
||||
<i class="ri-indent-decrease"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-action="increaseNestingLevel" title="Einzug vergrößern">
|
||||
<i class="ri-indent-increase"></i>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<span class="trix-toolbar-group">
|
||||
<button type="button" class="trix-toolbar-button" data-trix-action="undo" data-trix-key="z" title="Rückgängig">
|
||||
<i class="ri-arrow-go-back-line"></i>
|
||||
</button>
|
||||
<button type="button" class="trix-toolbar-button" data-trix-action="redo" data-trix-key="shift+z" title="Wiederholen">
|
||||
<i class="ri-arrow-go-forward-line"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="trix-dialogs" data-trix-dialogs>
|
||||
<div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
|
||||
<div class="trix-dialog__link-fields flex flex-row">
|
||||
<input type="url" name="href" class="trix-input trix-input--dialog" placeholder="URL eingeben…" aria-label="URL" required data-trix-input>
|
||||
<div class="trix-button-group flex-row">
|
||||
<input type="button" class="trix-button trix-button--dialog" value="Link" data-trix-method="setAttribute">
|
||||
<input type="button" class="trix-button trix-button--dialog" value="Unlink" data-trix-method="removeAttribute">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</trix-toolbar>
|
||||
|
||||
<textarea hidden id="page-html-{{ $index }}" name="html[{{ $section.Key }}]" autocomplete="off">{{- $section.HTML -}}</textarea>
|
||||
<trix-editor input="page-html-{{ $index }}" toolbar="page-html-toolbar-{{ $index }}"></trix-editor>
|
||||
<textarea
|
||||
id="page-html-{{ $index }}"
|
||||
name="html[{{ $section.Key }}]"
|
||||
class="inputinput page-html-editor"
|
||||
rows="12"
|
||||
autocomplete="off">{{- $section.HTML -}}</textarea>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
<div class="flex justify-end mt-6">
|
||||
<button type="submit" class="btn bg-slate-800 text-white px-4 py-2 rounded-xs hover:bg-slate-900">
|
||||
<button type="submit" class="submitbutton w-40 flex items-center gap-2 justify-center">
|
||||
<i class="ri-save-line"></i> Speichern
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
<title>Seiteneditor</title>
|
||||
<script src="/assets/vendor/tinymce/tinymce.min.js" defer></script>
|
||||
|
||||
Reference in New Issue
Block a user