fix: Termin-Uhrzeit ohne AM/PM (Stunde/Minute als Zahleneingabe)
Ersetzt type=time durch number 0–23 / 0–59, damit kein 12h-Picker mehr erscheint. Validierung, URL-Parameter und Vorschau angepasst; lang de-DE im Termin-Block. Made-with: Cursor
This commit is contained in:
+49
-6
@@ -318,6 +318,35 @@
|
||||
margin: -4px 0 12px 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.time-24h-block {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.time-24h-block .time-24h-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.time-24h-block input[type="number"] {
|
||||
width: 4.25rem;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.time-24h-sep {
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.time-24h-hint {
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -355,11 +384,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="section-event" class="content-section" style="display: none;" lang="en-GB">
|
||||
<div id="section-event" class="content-section" style="display: none;" lang="de-DE">
|
||||
<label for="event-title">Titel:</label>
|
||||
<input type="text" id="event-title" placeholder="" autocomplete="off">
|
||||
|
||||
<p class="event-datetime-hint">Datum im Format <strong>TT/MM/JJJJ</strong> (Kalenderfeld), Uhrzeit im <strong>24-Stunden-Format</strong> (keine AM/PM). Alle Zeiten: Ortszeit <strong>Europe/Berlin</strong>.</p>
|
||||
<p class="event-datetime-hint">Datum über das Kalenderfeld; Uhrzeit als <strong>Stunden 0–23</strong> und <strong>Minuten 0–59</strong> (reines 24h-Format, kein AM/PM). Ortszeit <strong>Europe/Berlin</strong>.</p>
|
||||
|
||||
<div class="options-row">
|
||||
<div class="options-col">
|
||||
@@ -367,8 +396,15 @@
|
||||
<input type="date" id="event-start-date" autocomplete="off">
|
||||
</div>
|
||||
<div class="options-col">
|
||||
<label for="event-start-time">Beginn – Uhrzeit (24h):</label>
|
||||
<input type="time" id="event-start-time" step="60" autocomplete="off">
|
||||
<div class="time-24h-block">
|
||||
<span class="label" style="display:block; margin-bottom:5px; font-weight:500; color:#374151;">Beginn – Uhrzeit (24h):</span>
|
||||
<div class="time-24h-row" role="group" aria-label="Beginn Uhrzeit 24 Stunden">
|
||||
<input type="number" id="event-start-hour" min="0" max="23" step="1" placeholder="HH" inputmode="numeric" autocomplete="off" aria-label="Stunde Beginn, 0 bis 23">
|
||||
<span class="time-24h-sep">:</span>
|
||||
<input type="number" id="event-start-minute" min="0" max="59" step="1" placeholder="MM" inputmode="numeric" autocomplete="off" aria-label="Minute Beginn, 0 bis 59">
|
||||
</div>
|
||||
<p class="time-24h-hint">Stunde 0–23, Minute 0–59</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-row">
|
||||
@@ -377,8 +413,15 @@
|
||||
<input type="date" id="event-end-date" autocomplete="off">
|
||||
</div>
|
||||
<div class="options-col">
|
||||
<label for="event-end-time">Ende (optional) – Uhrzeit (24h):</label>
|
||||
<input type="time" id="event-end-time" step="60" autocomplete="off">
|
||||
<div class="time-24h-block">
|
||||
<span class="label" style="display:block; margin-bottom:5px; font-weight:500; color:#374151;">Ende (optional) – Uhrzeit (24h):</span>
|
||||
<div class="time-24h-row" role="group" aria-label="Ende Uhrzeit 24 Stunden">
|
||||
<input type="number" id="event-end-hour" min="0" max="23" step="1" placeholder="HH" inputmode="numeric" autocomplete="off" aria-label="Stunde Ende, 0 bis 23">
|
||||
<span class="time-24h-sep">:</span>
|
||||
<input type="number" id="event-end-minute" min="0" max="59" step="1" placeholder="MM" inputmode="numeric" autocomplete="off" aria-label="Minute Ende, 0 bis 59">
|
||||
</div>
|
||||
<p class="time-24h-hint">Stunde 0–23, Minute 0–59</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="event-berlin-preview" id="event-berlin-preview" aria-live="polite"></p>
|
||||
|
||||
@@ -10,9 +10,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const wifiPasswordInput = document.getElementById('wifi-password');
|
||||
const eventTitleInput = document.getElementById('event-title');
|
||||
const eventStartDateInput = document.getElementById('event-start-date');
|
||||
const eventStartTimeInput = document.getElementById('event-start-time');
|
||||
const eventStartHourInput = document.getElementById('event-start-hour');
|
||||
const eventStartMinuteInput = document.getElementById('event-start-minute');
|
||||
const eventEndDateInput = document.getElementById('event-end-date');
|
||||
const eventEndTimeInput = document.getElementById('event-end-time');
|
||||
const eventEndHourInput = document.getElementById('event-end-hour');
|
||||
const eventEndMinuteInput = document.getElementById('event-end-minute');
|
||||
const eventLocationInput = document.getElementById('event-location');
|
||||
const eventDescriptionInput = document.getElementById('event-description');
|
||||
const sizeSelect = document.getElementById('size');
|
||||
@@ -108,9 +110,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const hasWifi = wifiSsidInput.value.trim().length > 0 || wifiPasswordInput.value.trim().length > 0;
|
||||
const hasEvent = eventTitleInput.value.trim().length > 0 ||
|
||||
eventStartDateInput.value.length > 0 ||
|
||||
eventStartTimeInput.value.length > 0 ||
|
||||
eventStartHourInput.value !== '' ||
|
||||
eventStartMinuteInput.value !== '' ||
|
||||
eventEndDateInput.value.length > 0 ||
|
||||
eventEndTimeInput.value.length > 0 ||
|
||||
eventEndHourInput.value !== '' ||
|
||||
eventEndMinuteInput.value !== '' ||
|
||||
eventLocationInput.value.trim().length > 0 ||
|
||||
eventDescriptionInput.value.trim().length > 0;
|
||||
if (hasText || hasWifi || hasEvent) {
|
||||
@@ -130,9 +134,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
wifiPasswordInput.value = '';
|
||||
eventTitleInput.value = '';
|
||||
eventStartDateInput.value = '';
|
||||
eventStartTimeInput.value = '';
|
||||
eventStartHourInput.value = '';
|
||||
eventStartMinuteInput.value = '';
|
||||
eventEndDateInput.value = '';
|
||||
eventEndTimeInput.value = '';
|
||||
eventEndHourInput.value = '';
|
||||
eventEndMinuteInput.value = '';
|
||||
eventLocationInput.value = '';
|
||||
eventDescriptionInput.value = '';
|
||||
contentModeSelect.value = 'text';
|
||||
@@ -187,12 +193,35 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
eventStartDateInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventStartDateInput.addEventListener('change', onEventDateTimeInput);
|
||||
eventStartTimeInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventStartTimeInput.addEventListener('change', onEventDateTimeInput);
|
||||
eventStartHourInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventStartHourInput.addEventListener('change', onEventDateTimeInput);
|
||||
eventStartMinuteInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventStartMinuteInput.addEventListener('change', onEventDateTimeInput);
|
||||
eventEndDateInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventEndDateInput.addEventListener('change', onEventDateTimeInput);
|
||||
eventEndTimeInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventEndTimeInput.addEventListener('change', onEventDateTimeInput);
|
||||
eventEndHourInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventEndHourInput.addEventListener('change', onEventDateTimeInput);
|
||||
eventEndMinuteInput.addEventListener('input', onEventDateTimeInput);
|
||||
eventEndMinuteInput.addEventListener('change', onEventDateTimeInput);
|
||||
|
||||
function clampTimeNumberInput(el, max) {
|
||||
if (el.value === '') {
|
||||
return;
|
||||
}
|
||||
var v = parseInt(el.value, 10);
|
||||
if (isNaN(v)) {
|
||||
return;
|
||||
}
|
||||
if (v < 0) {
|
||||
el.value = '0';
|
||||
} else if (v > max) {
|
||||
el.value = String(max);
|
||||
}
|
||||
}
|
||||
eventStartHourInput.addEventListener('blur', function() { clampTimeNumberInput(eventStartHourInput, 23); });
|
||||
eventStartMinuteInput.addEventListener('blur', function() { clampTimeNumberInput(eventStartMinuteInput, 59); });
|
||||
eventEndHourInput.addEventListener('blur', function() { clampTimeNumberInput(eventEndHourInput, 23); });
|
||||
eventEndMinuteInput.addEventListener('blur', function() { clampTimeNumberInput(eventEndMinuteInput, 59); });
|
||||
eventLocationInput.addEventListener('input', function() {
|
||||
generateQRCode();
|
||||
toggleClearButton();
|
||||
@@ -216,26 +245,39 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(s);
|
||||
}
|
||||
|
||||
function combineDateTime(dateStr, timeStr) {
|
||||
if (!dateStr || !timeStr) {
|
||||
function combineDateTimeFromParts(dateStr, hourStr, minuteStr) {
|
||||
if (!dateStr || hourStr === '' || minuteStr === '') {
|
||||
return '';
|
||||
}
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
|
||||
return '';
|
||||
}
|
||||
if (!/^\d{2}:\d{2}$/.test(timeStr)) {
|
||||
var h = parseInt(String(hourStr).trim(), 10);
|
||||
var mi = parseInt(String(minuteStr).trim(), 10);
|
||||
if (isNaN(h) || isNaN(mi)) {
|
||||
return '';
|
||||
}
|
||||
return dateStr + 'T' + timeStr;
|
||||
if (h < 0 || h > 23 || mi < 0 || mi > 59) {
|
||||
return '';
|
||||
}
|
||||
var pad = function(n) { return String(n).padStart(2, '0'); };
|
||||
return dateStr + 'T' + pad(h) + ':' + pad(mi);
|
||||
}
|
||||
|
||||
function applyCombinedToDateTimeInputs(combined, dateInput, timeInput) {
|
||||
function applyCombinedToDateTimeInputs(combined, dateInput, hourInput, minuteInput) {
|
||||
if (!isValidDatetimeLocal(combined)) {
|
||||
return;
|
||||
}
|
||||
const parts = combined.split('T');
|
||||
dateInput.value = parts[0];
|
||||
timeInput.value = parts[1];
|
||||
var splitT = combined.split('T');
|
||||
var d = splitT[0];
|
||||
var t = splitT[1];
|
||||
var tm = /^(\d{2}):(\d{2})$/.exec(t);
|
||||
if (!tm) {
|
||||
return;
|
||||
}
|
||||
dateInput.value = d;
|
||||
hourInput.value = String(parseInt(tm[1], 10));
|
||||
minuteInput.value = String(parseInt(tm[2], 10));
|
||||
}
|
||||
|
||||
// Or check for URL parameters if present
|
||||
@@ -279,13 +321,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
if (urlParams.has('eventStart')) {
|
||||
const es = urlParams.get('eventStart');
|
||||
if (isValidDatetimeLocal(es)) {
|
||||
applyCombinedToDateTimeInputs(es, eventStartDateInput, eventStartTimeInput);
|
||||
applyCombinedToDateTimeInputs(es, eventStartDateInput, eventStartHourInput, eventStartMinuteInput);
|
||||
}
|
||||
}
|
||||
if (urlParams.has('eventEnd')) {
|
||||
const ee = urlParams.get('eventEnd');
|
||||
if (isValidDatetimeLocal(ee)) {
|
||||
applyCombinedToDateTimeInputs(ee, eventEndDateInput, eventEndTimeInput);
|
||||
applyCombinedToDateTimeInputs(ee, eventEndDateInput, eventEndHourInput, eventEndMinuteInput);
|
||||
}
|
||||
}
|
||||
if (urlParams.has('eventLocation')) {
|
||||
@@ -387,15 +429,26 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
eventBerlinPreview.textContent = '';
|
||||
return;
|
||||
}
|
||||
const startRaw = combineDateTime(eventStartDateInput.value, eventStartTimeInput.value);
|
||||
const startRaw = combineDateTimeFromParts(
|
||||
eventStartDateInput.value,
|
||||
eventStartHourInput.value,
|
||||
eventStartMinuteInput.value
|
||||
);
|
||||
const endD = eventEndDateInput.value;
|
||||
const endT = eventEndTimeInput.value;
|
||||
const endH = eventEndHourInput.value;
|
||||
const endM = eventEndMinuteInput.value;
|
||||
const endTimeComplete = endH !== '' && endM !== '';
|
||||
const endTimeAny = endH !== '' || endM !== '';
|
||||
let endRaw = '';
|
||||
if (endD && endT) {
|
||||
endRaw = combineDateTime(endD, endT);
|
||||
} else if (endD || endT) {
|
||||
if (endD && endTimeComplete) {
|
||||
endRaw = combineDateTimeFromParts(endD, endH, endM);
|
||||
} else if (endD && !endTimeComplete) {
|
||||
eventBerlinPreview.textContent =
|
||||
'Bitte geben Sie für das Ende entweder beides (Datum und Uhrzeit, 24h) ein oder lassen Sie beides leer.';
|
||||
'Bitte geben Sie für das Ende Datum sowie Stunde (0–23) und Minute (0–59) an, oder lassen Sie das Ende vollständig leer.';
|
||||
return;
|
||||
} else if (!endD && endTimeAny) {
|
||||
eventBerlinPreview.textContent =
|
||||
'Bitte geben Sie für das Ende ein Datum ein, oder entfernen Sie Stunde/Minute.';
|
||||
return;
|
||||
}
|
||||
const sp = parseDatetimeLocalValue(startRaw);
|
||||
@@ -526,9 +579,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
if (mode === 'event') {
|
||||
const title = eventTitleInput.value.trim();
|
||||
const startRaw = combineDateTime(eventStartDateInput.value, eventStartTimeInput.value);
|
||||
const startRaw = combineDateTimeFromParts(
|
||||
eventStartDateInput.value,
|
||||
eventStartHourInput.value,
|
||||
eventStartMinuteInput.value
|
||||
);
|
||||
const endD = eventEndDateInput.value;
|
||||
const endT = eventEndTimeInput.value;
|
||||
const endH = eventEndHourInput.value;
|
||||
const endM = eventEndMinuteInput.value;
|
||||
const endTimeComplete = endH !== '' && endM !== '';
|
||||
const endTimeAny = endH !== '' || endM !== '';
|
||||
const loc = eventLocationInput.value;
|
||||
const desc = eventDescriptionInput.value;
|
||||
|
||||
@@ -539,20 +599,25 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
return;
|
||||
}
|
||||
if (!startRaw) {
|
||||
errorMessage.textContent = 'Bitte geben Sie Datum und Uhrzeit (24h) für den Beginn ein (TT/MM/JJJJ)';
|
||||
errorMessage.textContent =
|
||||
'Bitte geben Sie Datum sowie Stunde (0–23) und Minute (0–59) für den Beginn ein';
|
||||
qrcodeCanvas.style.display = 'none';
|
||||
qrcodeImg.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
if (endD || endT) {
|
||||
if (!endD || !endT) {
|
||||
if (endD && !endTimeComplete) {
|
||||
errorMessage.textContent =
|
||||
'Bitte geben Sie für das Ende sowohl Datum (TT/MM/JJJJ) als auch Uhrzeit (24h) an, oder lassen Sie beides leer';
|
||||
'Für das Ende: bitte Stunde und Minute ergänzen (0–23 / 0–59) oder Ende leer lassen';
|
||||
qrcodeCanvas.style.display = 'none';
|
||||
qrcodeImg.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
if (!endD && endTimeAny) {
|
||||
errorMessage.textContent = 'Für das Ende bitte zuerst ein Datum wählen oder Zeitfelder leeren';
|
||||
qrcodeCanvas.style.display = 'none';
|
||||
qrcodeImg.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const startParts = parseDatetimeLocalValue(startRaw);
|
||||
@@ -566,7 +631,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const dtStart = wallTimeToICal(startParts);
|
||||
|
||||
let endParts;
|
||||
const endRaw = endD && endT ? combineDateTime(endD, endT) : '';
|
||||
const endRaw = endD && endTimeComplete ? combineDateTimeFromParts(endD, endH, endM) : '';
|
||||
if (endRaw) {
|
||||
endParts = parseDatetimeLocalValue(endRaw);
|
||||
if (!endParts) {
|
||||
@@ -740,8 +805,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
if (eventTitleInput.value.trim()) {
|
||||
params.set('eventTitle', eventTitleInput.value.trim());
|
||||
}
|
||||
const shareStart = combineDateTime(eventStartDateInput.value, eventStartTimeInput.value);
|
||||
const shareEnd = combineDateTime(eventEndDateInput.value, eventEndTimeInput.value);
|
||||
const shareStart = combineDateTimeFromParts(
|
||||
eventStartDateInput.value,
|
||||
eventStartHourInput.value,
|
||||
eventStartMinuteInput.value
|
||||
);
|
||||
const shareEnd = combineDateTimeFromParts(
|
||||
eventEndDateInput.value,
|
||||
eventEndHourInput.value,
|
||||
eventEndMinuteInput.value
|
||||
);
|
||||
if (shareStart) {
|
||||
params.set('eventStart', shareStart);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user