213 lines
12 KiB
HTML
213 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="{{ language() }}">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>{{ concert.artist }} {{ _('bearbeiten · MetalCircle') }}</title>
|
||
<link rel="icon" type="image/png" href="/static/images/metalcircle-circle.png">
|
||
<link rel="stylesheet" href="/static/css/style.css">
|
||
<link rel="stylesheet" href="/static/css/language.css">
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<div class="header-inner">
|
||
<a href="/" class="logo"><img class="brand-logo" src="/static/images/metalcircle-full.png" alt="MetalCircle"></a>
|
||
{% include '_header_controls.html' %}
|
||
</div>
|
||
</header>
|
||
<main>
|
||
<div class="page-title">
|
||
<h1>{{ _('✏️ Veranstaltung bearbeiten') }}</h1>
|
||
<p>{{ _('Änderungen werden direkt bei der Veranstaltung gespeichert.') }}</p>
|
||
</div>
|
||
<section class="empty">
|
||
<form method="post" action="/concerts/{{ concert.id }}/edit" enctype="multipart/form-data">
|
||
{% if can_edit_details %}
|
||
<p>
|
||
<label>{{ _('Kategorie') }}<br>
|
||
<select name="event_type" id="event-type" required {% if not can_manage_access %}disabled{% endif %}>
|
||
<option value="concert" {% if concert.event_type == 'concert' %}selected{% endif %}>{{ _('Konzert') }}</option>
|
||
<option value="festival" {% if concert.event_type == 'festival' %}selected{% endif %}>Festival</option>
|
||
<option value="other" {% if concert.event_type == 'other' %}selected{% endif %}>{{ _('Sonstiges') }}</option>
|
||
</select>
|
||
</label>
|
||
</p>
|
||
<p id="parent-event-field" {% if concert.event_type != 'other' %}hidden{% endif %}>
|
||
<label>{{ _('Gehört zu') }}<br>
|
||
<select name="parent_event_id" id="parent-event-id">
|
||
<option value="">{{ _('Keine Verknüpfung – eigenständige Karte') }}</option>
|
||
{% for event in linkable_events %}
|
||
<option value="{{ event.id }}" {% if concert.parent_event and concert.parent_event.id == event.id %}selected{% endif %}>{{ event.event_type_label | t }} · {{ event.title }} · {{ event.date }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
</p>
|
||
{% if can_manage_access %}<fieldset id="event-visibility-field" {% if concert.event_type != 'other' %}hidden{% endif %}>
|
||
<legend>{{ _('Sichtbarkeit') }}</legend>
|
||
<label><input type="radio" name="visibility" value="public" {% if concert.visibility == 'public' %}checked{% endif %}> {{ _('Öffentlich') }}</label><br>
|
||
<label><input type="radio" name="visibility" value="friends" {% if concert.visibility == 'friends' %}checked{% endif %}> {{ _('Nur Freunde') }}</label><br>
|
||
<label><input type="radio" name="visibility" value="private" {% if concert.visibility == 'private' %}checked{% endif %}> {{ _('Privat – nur eingeladene Mitglieder') }}</label>
|
||
</fieldset>
|
||
<fieldset id="event-invitations-field" {% if concert.event_type != 'other' or concert.visibility != 'private' %}hidden{% endif %}>
|
||
<legend>{{ _('Mitglieder einladen') }}</legend>
|
||
{% for member in invitable_users %}
|
||
<label style="display:block;margin:7px 0"><input type="checkbox" name="invited_user_ids" value="{{ member.id }}" {% if member.id in invited_user_ids %}checked{% endif %}> {{ member.display_name }} <small>@{{ member.username }}</small></label>
|
||
{% else %}<p>{{ _('Noch keine weiteren Mitglieder vorhanden.') }}</p>{% endfor %}
|
||
</fieldset>
|
||
{% endif %}
|
||
{% endif %}
|
||
<p>
|
||
<label>{{ _('Titel / Künstler / Band') }}<br>
|
||
<input type="text" name="artist" value="{{ concert.artist }}" {% if not can_edit_title %}disabled{% endif %} required>
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Bands / Line-up') }} <small>{{ _('(eine Band pro Zeile)') }}</small><br>
|
||
<textarea name="band_names" rows="3" maxlength="4000" {% if not can_edit_title %}disabled{% endif %}>{{ band_names }}</textarea>
|
||
</label>
|
||
<small>{{ _('Diese Namen werden einzeln für die Folgen-Funktion verwendet.') }}</small>
|
||
</p>
|
||
{% if can_edit_details %}
|
||
<p>
|
||
<label>{{ _('Veranstaltungsort') }}<br>
|
||
<input type="text" name="venue_name" value="{{ concert.venue.name if concert.venue.id else '' }}" placeholder="{{ _('Name des Veranstaltungsorts') }}">
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Straße') }}<br>
|
||
<input type="text" name="street" value="{{ concert.venue.street or '' }}">
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('PLZ und Ort') }}<br>
|
||
<input type="text" name="postal_code" value="{{ concert.venue.postal_code or '' }}" placeholder="{{ _('PLZ') }}">
|
||
<input type="text" name="city" value="{{ concert.venue.city or '' }}" placeholder="{{ _('Ort') }}">
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Land') }}<br>
|
||
<input type="text" name="country" value="{{ concert.venue.country or '' }}" placeholder="{{ _('Land') }}">
|
||
</label>
|
||
</p>
|
||
<input type="hidden" name="latitude" value="{{ concert.venue.latitude or '' }}">
|
||
<input type="hidden" name="longitude" value="{{ concert.venue.longitude or '' }}">
|
||
<p>
|
||
<label>{{ _('Beginn') }}<br>
|
||
<input type="datetime-local" name="start_datetime" value="{{ concert.start_local }}" required>
|
||
</label>
|
||
</p>
|
||
<p id="festival-end-field" {% if concert.event_type != 'festival' %}hidden{% endif %}>
|
||
<label>{{ _('Ende') }}<br>
|
||
<input type="datetime-local" name="end_datetime" id="festival-end-datetime" value="{{ concert.end_local }}" {% if concert.event_type == 'festival' %}required{% endif %}>
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Beschreibung') }}<br>
|
||
<textarea name="description" rows="5">{{ concert.description or '' }}</textarea>
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Ticket-Link') }}<br>
|
||
<input type="url" name="ticket_url" value="{{ concert.ticket_url or '' }}" placeholder="https://...">
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Ticketpreis') }}<br>
|
||
<input type="number" name="ticket_price" value="{{ concert.ticket_price or '' }}" step="0.01" min="0">
|
||
</label>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Flyer extern verlinken') }} <small>{{ _('(bevorzugt)') }}</small><br>
|
||
<input type="url" name="flyer_url" value="{{ concert.flyer_url or '' }}" placeholder="https://veranstalter.example/flyer.jpg">
|
||
</label>
|
||
<small>{{ _('Bitte möglichst die offizielle Quelle verwenden. Ein externer Link wird gegenüber einem Upload bevorzugt und unter dem Bild genannt. Feld leeren, um wieder den Upload zu verwenden.') }}</small>
|
||
</p>
|
||
<p>
|
||
<label>{{ _('Neuen Flyer hochladen') }}<br>
|
||
<input type="file" name="flyer" accept="image/jpeg,image/png,image/webp">
|
||
</label>
|
||
<small>{{ _('Ohne neue Datei bleibt der bisherige Flyer erhalten.') }}</small>
|
||
</p>
|
||
{% if concert.flyer_url or concert.flyer_path %}
|
||
<p><img src="{{ concert.flyer_url or concert.flyer_path }}" alt="{{ _('Aktueller Flyer') }}" referrerpolicy="no-referrer" style="max-width: 300px; max-height: 400px; border-radius: 10px;"></p>
|
||
{% endif %}
|
||
{% endif %}
|
||
<div>
|
||
<button type="submit" class="button">{{ _('💾 Änderungen speichern') }}</button>
|
||
<a href="/concerts/{{ concert.id }}" class="button button-secondary">{{ _('Abbrechen') }}</a>
|
||
</div>
|
||
</form>
|
||
</section>
|
||
</main>
|
||
{% if can_edit_details %}
|
||
<script>
|
||
const editConcertForm = document.querySelector('form[enctype="multipart/form-data"]');
|
||
const editFlyerInput = editConcertForm?.querySelector('input[name="flyer"]');
|
||
async function optimizeEditFlyer(file) {
|
||
const bitmap = await createImageBitmap(file);
|
||
const maxSide = 1800;
|
||
const scale = Math.min(1, maxSide / Math.max(bitmap.width, bitmap.height));
|
||
const canvas = document.createElement("canvas");
|
||
canvas.width = Math.max(1, Math.round(bitmap.width * scale));
|
||
canvas.height = Math.max(1, Math.round(bitmap.height * scale));
|
||
canvas.getContext("2d").drawImage(bitmap, 0, 0, canvas.width, canvas.height);
|
||
bitmap.close();
|
||
let quality = 0.86;
|
||
let blob;
|
||
do {
|
||
blob = await new Promise(resolve => canvas.toBlob(resolve, "image/jpeg", quality));
|
||
quality -= 0.08;
|
||
} while (blob && blob.size > 900 * 1024 && quality >= 0.5);
|
||
if (!blob) throw new Error("Bild konnte nicht verarbeitet werden");
|
||
return new File([blob], "flyer.jpg", {type: "image/jpeg"});
|
||
}
|
||
|
||
editConcertForm?.addEventListener("submit", async event => {
|
||
if (editConcertForm.dataset.flyerOptimized === "true") return;
|
||
const file = editFlyerInput?.files[0];
|
||
if (!file) return;
|
||
event.preventDefault();
|
||
try {
|
||
const transfer = new DataTransfer();
|
||
transfer.items.add(await optimizeEditFlyer(file));
|
||
editFlyerInput.files = transfer.files;
|
||
editConcertForm.dataset.flyerOptimized = "true";
|
||
editConcertForm.requestSubmit();
|
||
} catch (error) {
|
||
console.error("Flyer optimization failed:", error);
|
||
editConcertForm.dataset.flyerOptimized = "true";
|
||
editConcertForm.requestSubmit();
|
||
}
|
||
});
|
||
|
||
const eventType = document.getElementById("event-type");
|
||
const parentEventField = document.getElementById("parent-event-field");
|
||
const parentEventId = document.getElementById("parent-event-id");
|
||
const festivalEndField = document.getElementById("festival-end-field");
|
||
const festivalEndDatetime = document.getElementById("festival-end-datetime");
|
||
const eventVisibilityField = document.getElementById("event-visibility-field");
|
||
const eventInvitationsField = document.getElementById("event-invitations-field");
|
||
const visibilityInputs = [...document.querySelectorAll('input[name="visibility"]')];
|
||
|
||
function updateEventFields() {
|
||
const isFestival = eventType.value === "festival";
|
||
const isOther = eventType.value === "other";
|
||
festivalEndField.hidden = !isFestival;
|
||
festivalEndDatetime.required = isFestival;
|
||
parentEventField.hidden = !isOther;
|
||
if (eventVisibilityField) {
|
||
eventVisibilityField.hidden = !isOther;
|
||
const isPrivate = isOther && document.querySelector('input[name="visibility"]:checked').value === "private";
|
||
eventInvitationsField.hidden = !isPrivate;
|
||
}
|
||
if (!isFestival) festivalEndDatetime.value = "";
|
||
if (!isOther) parentEventId.value = "";
|
||
}
|
||
|
||
eventType.addEventListener("change", updateEventFields);
|
||
visibilityInputs.forEach(input => input.addEventListener("change", updateEventFields));
|
||
</script>
|
||
{% endif %}
|
||
</body>
|
||
</html>
|