Weiter am Chastity Ingame gearbeitet
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
<title>Meine Vorlagen – xXx Sphere</title>
|
||||
<link rel="stylesheet" href="/css/variables.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="stylesheet" href="/css/time-picker.css">
|
||||
<style>
|
||||
|
||||
/* ── Liste ── */
|
||||
@@ -133,26 +134,6 @@
|
||||
}
|
||||
.stepper input[type="text"]:focus { outline:none; background:rgba(255,255,255,0.08); }
|
||||
|
||||
/* ── Zeitpicker ── */
|
||||
.time-picker { display:flex; align-items:center; gap:0.4rem; flex-wrap:wrap; }
|
||||
.tp-seg { display:flex; flex-direction:column; align-items:center; gap:0.15rem; }
|
||||
.tp-seg-row { display:flex; align-items:center; gap:0.2rem; }
|
||||
.tp-seg button {
|
||||
width:24px; height:24px; background:var(--color-card);
|
||||
border:1px solid var(--color-muted); border-radius:4px;
|
||||
cursor:pointer; font-size:0.9rem; font-weight:700; color:var(--color-text);
|
||||
display:flex; align-items:center; justify-content:center; padding:0; flex-shrink:0;
|
||||
}
|
||||
.tp-seg button:hover { background:var(--color-primary); color:#fff; border-color:var(--color-primary); }
|
||||
.tp-seg input {
|
||||
width:28px; text-align:center; background:var(--color-card);
|
||||
border:1px solid var(--color-muted); border-radius:4px;
|
||||
color:var(--color-text); font-size:0.9rem; font-weight:600;
|
||||
font-family:monospace; padding:0.15rem 0; box-sizing:border-box;
|
||||
}
|
||||
.tp-seg .tp-label { font-size:0.62rem; color:var(--color-muted); text-transform:uppercase; letter-spacing:0.04em; }
|
||||
.tp-colon { font-size:1rem; font-weight:700; color:var(--color-muted); margin-bottom:0.9rem; }
|
||||
|
||||
/* ── Aufgaben ── */
|
||||
.task-list { display:flex; flex-direction:column; gap:0.5rem; margin-bottom:0.6rem; }
|
||||
.task-item {
|
||||
@@ -260,6 +241,33 @@
|
||||
.radio-group label { display:flex; align-items:center; gap:0.5rem; cursor:pointer; font-size:0.9rem; margin:0; color:var(--color-text); }
|
||||
.radio-group input[type="radio"] { width:auto; padding:0; margin:0; }
|
||||
|
||||
/* ── Spiel-Set Suche ── */
|
||||
.gs-dropdown {
|
||||
display:none; position:absolute; top:100%; left:0; right:0; z-index:200;
|
||||
background:var(--color-card); border:1px solid var(--color-secondary);
|
||||
border-radius:6px; max-height:200px; overflow-y:auto;
|
||||
box-shadow:0 4px 14px rgba(0,0,0,0.35); margin-top:2px;
|
||||
}
|
||||
.gs-dropdown-item {
|
||||
padding:0.55rem 0.9rem; cursor:pointer; font-size:0.9rem;
|
||||
border-bottom:1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
.gs-dropdown-item:last-child { border-bottom:none; }
|
||||
.gs-dropdown-item:hover { background:rgba(255,255,255,0.07); }
|
||||
.gs-item-name { font-weight:600; color:var(--color-text); }
|
||||
.gs-item-desc { font-size:0.78rem; color:var(--color-muted); margin-top:0.1rem; }
|
||||
.gs-selected {
|
||||
display:flex; align-items:center; gap:0.6rem;
|
||||
background:rgba(255,255,255,0.05); border:1px solid var(--color-secondary);
|
||||
border-radius:6px; padding:0.45rem 0.75rem; margin-top:0.35rem;
|
||||
font-size:0.88rem; color:var(--color-text);
|
||||
}
|
||||
.gs-selected button {
|
||||
background:none; border:none; color:var(--color-muted);
|
||||
cursor:pointer; padding:0; margin:0; font-size:1rem; width:auto; line-height:1;
|
||||
}
|
||||
.gs-selected button:hover { color:#e74c3c; background:none; }
|
||||
|
||||
/* ── Simulation ── */
|
||||
.sim-bar-track { background:var(--color-secondary); border-radius:6px; height:8px; overflow:hidden; margin:0.5rem 0 0.25rem; }
|
||||
.sim-bar-fill { height:100%; background:var(--color-primary); border-radius:6px; transition:width 0.1s linear; width:0%; }
|
||||
@@ -353,32 +361,9 @@
|
||||
<div class="form-row" style="margin-top:0.75rem;">
|
||||
<label>Karte ziehen alle</label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg">
|
||||
<div class="tp-seg-row">
|
||||
<button type="button" onclick="tpChange('pe',-1,'d')">−</button>
|
||||
<input type="text" id="pe_d" value="0" readonly>
|
||||
<button type="button" onclick="tpChange('pe',1,'d')">+</button>
|
||||
</div>
|
||||
<span class="tp-label">Tage</span>
|
||||
</div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg">
|
||||
<div class="tp-seg-row">
|
||||
<button type="button" onclick="tpChange('pe',-1,'h')">−</button>
|
||||
<input type="text" id="pe_h" value="01" readonly>
|
||||
<button type="button" onclick="tpChange('pe',1,'h')">+</button>
|
||||
</div>
|
||||
<span class="tp-label">Std</span>
|
||||
</div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg">
|
||||
<div class="tp-seg-row">
|
||||
<button type="button" onclick="tpChange('pe',-1,'m')">−</button>
|
||||
<input type="text" id="pe_m" value="00" readonly>
|
||||
<button type="button" onclick="tpChange('pe',1,'m')">+</button>
|
||||
</div>
|
||||
<span class="tp-label">Min</span>
|
||||
</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pe',-1,'d')">−</button><input type="text" id="pe_d" value="0" readonly><button type="button" onclick="tpChange('pe',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pe',-1,'h')">−</button><input type="text" id="pe_h" value="01" readonly><button type="button" onclick="tpChange('pe',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pe',-1,'m')">−</button><input type="text" id="pe_m" value="00" readonly><button type="button" onclick="tpChange('pe',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -391,25 +376,55 @@
|
||||
<label for="fShowRemaining">Art der verbleibenden Karten anzeigen</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Aufgaben (CardLock) -->
|
||||
<div class="form-section">
|
||||
<div class="form-section-title">Aufgaben (optional)</div>
|
||||
<div style="margin-bottom:0.65rem;">
|
||||
<div style="font-size:0.75rem;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--color-muted);margin-bottom:0.45rem;">Wer entscheidet über die Aufgabe?</div>
|
||||
<div class="radio-group">
|
||||
<label><input type="radio" name="modalCardTaskMode" value="RANDOM" checked> Zufall</label>
|
||||
<label><input type="radio" name="modalCardTaskMode" value="KEYHOLDER" > Keyholder*In</label>
|
||||
<label><input type="radio" name="modalCardTaskMode" value="COMMUNITY" > Community</label>
|
||||
<!-- Aufgaben-Set – sichtbar wenn TASK > 0 oder GAME_CARD > 0 -->
|
||||
<div id="sectionAufgabenSet" style="display:none;">
|
||||
<div class="form-section">
|
||||
<div class="form-section-title">Aufgaben-Set</div>
|
||||
|
||||
<!-- Task-Karte: Entscheider + internes Set -->
|
||||
<div id="subCardTaskSet" style="display:none;">
|
||||
<div style="margin-bottom:0.65rem;">
|
||||
<div style="font-size:0.75rem;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--color-muted);margin-bottom:0.45rem;">Wer entscheidet über die Aufgabe?</div>
|
||||
<div class="radio-group">
|
||||
<label><input type="radio" name="modalCardTaskMode" value="RANDOM" checked> Zufall</label>
|
||||
<label><input type="radio" name="modalCardTaskMode" value="KEYHOLDER" > Keyholder*In</label>
|
||||
<label><input type="radio" name="modalCardTaskMode" value="COMMUNITY" > Community</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:0.5rem;">
|
||||
<label>Aufgaben-Set <span class="required-star">*</span></label>
|
||||
<select id="fCardTaskSetId" onchange="onTaskSetChange('card')">
|
||||
<option value="">Kein Aufgaben-Set</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn-add" type="button" onclick="openTaskSetModal(null,'card')">+ Neues Set anlegen</button>
|
||||
<div id="cardTaskSetPreview" class="task-set-preview"></div>
|
||||
</div>
|
||||
|
||||
<!-- Spiel-Karte: Chastity-Set + Spieldauer -->
|
||||
<div id="subGameSet" style="display:none;">
|
||||
<div class="form-row">
|
||||
<label>Aufgaben-Set (Chastity) <span class="required-star">*</span></label>
|
||||
<div style="position:relative;">
|
||||
<input type="text" id="gameSetSearch" placeholder="Name eingeben zum Suchen…"
|
||||
autocomplete="off" oninput="onGameSetSearch(this.value)" onfocus="onGameSetSearchFocus()">
|
||||
<div id="gameSetDropdown" class="gs-dropdown"></div>
|
||||
</div>
|
||||
<div id="gameSetSelected" class="gs-selected" style="display:none;"></div>
|
||||
<input type="hidden" id="fGameSetId">
|
||||
<div class="field-error-msg" id="errGameSet" style="display:none;">Bitte ein Aufgaben-Set für Spiel-Karten auswählen.</div>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:0;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.4rem;">
|
||||
<label for="sldGameSpieldauer" style="margin:0;">Spieldauer</label>
|
||||
<span id="valGameSpieldauer" style="font-size:0.85rem;color:var(--color-muted);">Mittel</span>
|
||||
</div>
|
||||
<input type="range" id="sldGameSpieldauer" min="0" max="4" value="2"
|
||||
oninput="updateGameSpieldauer(this.value)"
|
||||
style="width:100%;accent-color:var(--color-primary);">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:0.5rem;">
|
||||
<label>Aufgaben-Set</label>
|
||||
<select id="fCardTaskSetId" onchange="onTaskSetChange('card')">
|
||||
<option value="">Kein Aufgaben-Set</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn-add" type="button" onclick="openTaskSetModal(null,'card')">+ Neues Set anlegen</button>
|
||||
<div id="cardTaskSetPreview" class="task-set-preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -423,20 +438,16 @@
|
||||
<label>Mindestdauer (optional)</label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmin',-1,'d')">−</button><input type="text" id="tmin_d" value="0" readonly><button type="button" onclick="tpChange('tmin',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmin',-1,'h')">−</button><input type="text" id="tmin_h" value="00" readonly><button type="button" onclick="tpChange('tmin',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmin',-1,'m')">−</button><input type="text" id="tmin_m" value="00" readonly><button type="button" onclick="tpChange('tmin',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmin',-1,'h')">−</button><input type="text" id="tmin_h" value="00" readonly><button type="button" onclick="tpChange('tmin',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmin',-1,'m')">−</button><input type="text" id="tmin_m" value="00" readonly><button type="button" onclick="tpChange('tmin',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" id="rowMaxTime">
|
||||
<label>Maximaldauer<span class="required-star">*</span></label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmax',-1,'d')">−</button><input type="text" id="tmax_d" value="0" readonly><button type="button" onclick="tpChange('tmax',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmax',-1,'h')">−</button><input type="text" id="tmax_h" value="01" readonly><button type="button" onclick="tpChange('tmax',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmax',-1,'m')">−</button><input type="text" id="tmax_m" value="00" readonly><button type="button" onclick="tpChange('tmax',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmax',-1,'h')">−</button><input type="text" id="tmax_h" value="01" readonly><button type="button" onclick="tpChange('tmax',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('tmax',-1,'m')">−</button><input type="text" id="tmax_m" value="00" readonly><button type="button" onclick="tpChange('tmax',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkbox-row">
|
||||
@@ -457,10 +468,8 @@
|
||||
<label>Rad drehen alle</label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('se',-1,'d')">−</button><input type="text" id="se_d" value="0" readonly><button type="button" onclick="tpChange('se',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('se',-1,'h')">−</button><input type="text" id="se_h" value="01" readonly><button type="button" onclick="tpChange('se',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('se',-1,'m')">−</button><input type="text" id="se_m" value="00" readonly><button type="button" onclick="tpChange('se',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('se',-1,'h')">−</button><input type="text" id="se_h" value="01" readonly><button type="button" onclick="tpChange('se',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('se',-1,'m')">−</button><input type="text" id="se_m" value="00" readonly><button type="button" onclick="tpChange('se',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@@ -486,10 +495,8 @@
|
||||
<label>Aufgaben alle</label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('te',-1,'d')">−</button><input type="text" id="te_d" value="0" readonly><button type="button" onclick="tpChange('te',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('te',-1,'h')">−</button><input type="text" id="te_h" value="08" readonly><button type="button" onclick="tpChange('te',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('te',-1,'m')">−</button><input type="text" id="te_m" value="00" readonly><button type="button" onclick="tpChange('te',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('te',-1,'h')">−</button><input type="text" id="te_h" value="08" readonly><button type="button" onclick="tpChange('te',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('te',-1,'m')">−</button><input type="text" id="te_m" value="00" readonly><button type="button" onclick="tpChange('te',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:0;">
|
||||
@@ -533,10 +540,8 @@
|
||||
<label>Dauer</label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pv',-1,'d')">−</button><input type="text" id="pv_d" value="0" readonly><button type="button" onclick="tpChange('pv',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pv',-1,'h')">−</button><input type="text" id="pv_h" value="01" readonly><button type="button" onclick="tpChange('pv',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pv',-1,'m')">−</button><input type="text" id="pv_m" value="00" readonly><button type="button" onclick="tpChange('pv',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pv',-1,'h')">−</button><input type="text" id="pv_h" value="01" readonly><button type="button" onclick="tpChange('pv',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('pv',-1,'m')">−</button><input type="text" id="pv_m" value="00" readonly><button type="button" onclick="tpChange('pv',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -554,20 +559,16 @@
|
||||
<label>Hygiene-Öffnung alle</label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('he',-1,'d')">−</button><input type="text" id="he_d" value="1" readonly><button type="button" onclick="tpChange('he',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('he',-1,'h')">−</button><input type="text" id="he_h" value="00" readonly><button type="button" onclick="tpChange('he',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('he',-1,'m')">−</button><input type="text" id="he_m" value="00" readonly><button type="button" onclick="tpChange('he',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('he',-1,'h')">−</button><input type="text" id="he_h" value="00" readonly><button type="button" onclick="tpChange('he',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('he',-1,'m')">−</button><input type="text" id="he_m" value="00" readonly><button type="button" onclick="tpChange('he',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:0;">
|
||||
<label>Dauer der Öffnung</label>
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('hd',-1,'d')">−</button><input type="text" id="hd_d" value="0" readonly><button type="button" onclick="tpChange('hd',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('hd',-1,'h')">−</button><input type="text" id="hd_h" value="00" readonly><button type="button" onclick="tpChange('hd',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('hd',-1,'m')">−</button><input type="text" id="hd_m" value="30" readonly><button type="button" onclick="tpChange('hd',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('hd',-1,'h')">−</button><input type="text" id="hd_h" value="00" readonly><button type="button" onclick="tpChange('hd',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('hd',-1,'m')">−</button><input type="text" id="hd_m" value="30" readonly><button type="button" onclick="tpChange('hd',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -652,8 +653,9 @@
|
||||
<script src="/js/card-defs.js"></script>
|
||||
<script src="/js/card-display.js"></script>
|
||||
<script src="/js/icons.js"></script>
|
||||
<script src="/js/nav.js"></script>
|
||||
<script src="/js/nav.js"></script>
|
||||
<script src="/js/social-sidebar.js"></script>
|
||||
<script src="/js/time-picker.js"></script>
|
||||
<script>
|
||||
function esc(s) { const d = document.createElement('div'); d.textContent = s ?? ''; return d.innerHTML; }
|
||||
|
||||
@@ -673,36 +675,6 @@
|
||||
let isLastPage = false;
|
||||
let isLoading = false;
|
||||
|
||||
// ── Zeitpicker ──
|
||||
function tpChange(prefix, delta, seg) {
|
||||
let d = parseInt(document.getElementById(prefix + '_d').value) || 0;
|
||||
let h = parseInt(document.getElementById(prefix + '_h').value) || 0;
|
||||
let m = parseInt(document.getElementById(prefix + '_m').value) || 0;
|
||||
if (seg === 'm') m += delta;
|
||||
else if (seg === 'h') h += delta;
|
||||
else d += delta;
|
||||
if (m >= 60) { h += Math.floor(m/60); m %= 60; }
|
||||
if (m < 0) { const b = Math.ceil(-m/60); h -= b; m += b*60; }
|
||||
if (h >= 24) { d += Math.floor(h/24); h %= 24; }
|
||||
if (h < 0) { const b = Math.ceil(-h/24); d -= b; h += b*24; }
|
||||
if (d < 0) d = 0;
|
||||
document.getElementById(prefix + '_d').value = d;
|
||||
document.getElementById(prefix + '_h').value = String(h).padStart(2,'0');
|
||||
document.getElementById(prefix + '_m').value = String(m).padStart(2,'0');
|
||||
}
|
||||
function tpToMinutes(prefix) {
|
||||
const d = parseInt(document.getElementById(prefix + '_d').value) || 0;
|
||||
const h = parseInt(document.getElementById(prefix + '_h').value) || 0;
|
||||
const m = parseInt(document.getElementById(prefix + '_m').value) || 0;
|
||||
return d*1440 + h*60 + m;
|
||||
}
|
||||
function tpFromMinutes(prefix, total) {
|
||||
total = total || 0;
|
||||
const d = Math.floor(total/1440), h = Math.floor((total%1440)/60), m = total%60;
|
||||
document.getElementById(prefix + '_d').value = d;
|
||||
document.getElementById(prefix + '_h').value = String(h).padStart(2,'0');
|
||||
document.getElementById(prefix + '_m').value = String(m).padStart(2,'0');
|
||||
}
|
||||
function fmtMinutes(min) {
|
||||
if (!min) return '–';
|
||||
const d = Math.floor(min/1440), h = Math.floor((min%1440)/60), m = min%60;
|
||||
@@ -757,8 +729,134 @@
|
||||
function syncMinMax(id, val) {
|
||||
if (id.startsWith('min_')) { const mx = document.getElementById('max_'+id.slice(4)); if (mx && val > (parseInt(mx.value)||0)) mx.value = val; }
|
||||
else if (id.startsWith('max_')) { const mn = document.getElementById('min_'+id.slice(4)); if (mn && val < (parseInt(mn.value)||0)) mn.value = val; }
|
||||
if (id === 'min_GAME_CARD' || id === 'max_GAME_CARD') {
|
||||
if (val > 0) {
|
||||
// Gegenseitiger Ausschluss: Task-Karten nullen
|
||||
const minT = document.getElementById('min_TASK'); if (minT) minT.value = 0;
|
||||
const maxT = document.getElementById('max_TASK'); if (maxT) maxT.value = 0;
|
||||
checkTaskCardSection();
|
||||
}
|
||||
checkGameCardSection();
|
||||
}
|
||||
if (id === 'min_TASK' || id === 'max_TASK') {
|
||||
if (val > 0) {
|
||||
// Gegenseitiger Ausschluss: Game-Karten nullen
|
||||
const minG = document.getElementById('min_GAME_CARD'); if (minG) minG.value = 0;
|
||||
const maxG = document.getElementById('max_GAME_CARD'); if (maxG) maxG.value = 0;
|
||||
checkGameCardSection();
|
||||
}
|
||||
checkTaskCardSection();
|
||||
}
|
||||
}
|
||||
|
||||
// ── Spiel-Karte: Aufgaben-Set + Spieldauer ──
|
||||
const GAME_SPIELDAUER = [
|
||||
{ label: 'Sehr kurz' },
|
||||
{ label: 'Kurz' },
|
||||
{ label: 'Mittel' },
|
||||
{ label: 'Lang' },
|
||||
{ label: 'Sehr lang' },
|
||||
];
|
||||
let _gameSetSearchTimer = null;
|
||||
let _gameSetResults = [];
|
||||
|
||||
function checkGameCardSection() {
|
||||
const minV = parseInt(document.getElementById('min_GAME_CARD')?.value) || 0;
|
||||
const maxV = parseInt(document.getElementById('max_GAME_CARD')?.value) || 0;
|
||||
const hasGame = minV > 0 || maxV > 0;
|
||||
const sub = document.getElementById('subGameSet');
|
||||
if (sub) sub.style.display = hasGame ? '' : 'none';
|
||||
checkAufgabenSetSection();
|
||||
}
|
||||
|
||||
function checkTaskCardSection() {
|
||||
const minV = parseInt(document.getElementById('min_TASK')?.value) || 0;
|
||||
const maxV = parseInt(document.getElementById('max_TASK')?.value) || 0;
|
||||
const hasTask = minV > 0 || maxV > 0;
|
||||
const sub = document.getElementById('subCardTaskSet');
|
||||
if (sub) sub.style.display = hasTask ? '' : 'none';
|
||||
checkAufgabenSetSection();
|
||||
}
|
||||
|
||||
function checkAufgabenSetSection() {
|
||||
const hasTask = (parseInt(document.getElementById('min_TASK')?.value) || 0) > 0
|
||||
|| (parseInt(document.getElementById('max_TASK')?.value) || 0) > 0;
|
||||
const hasGame = (parseInt(document.getElementById('min_GAME_CARD')?.value) || 0) > 0
|
||||
|| (parseInt(document.getElementById('max_GAME_CARD')?.value) || 0) > 0;
|
||||
const sec = document.getElementById('sectionAufgabenSet');
|
||||
if (sec) sec.style.display = (hasTask || hasGame) ? '' : 'none';
|
||||
}
|
||||
|
||||
function updateGameSpieldauer(val) {
|
||||
document.getElementById('valGameSpieldauer').textContent = GAME_SPIELDAUER[+val].label;
|
||||
}
|
||||
|
||||
function onGameSetSearchFocus() {
|
||||
if (!document.getElementById('fGameSetId').value) onGameSetSearch(document.getElementById('gameSetSearch').value);
|
||||
}
|
||||
|
||||
function onGameSetSearch(value) {
|
||||
clearTimeout(_gameSetSearchTimer);
|
||||
if (value.length === 0) {
|
||||
_gameSetSearchTimer = setTimeout(() => doGameSetSearch(''), 0);
|
||||
} else if (value.length < 2) {
|
||||
document.getElementById('gameSetDropdown').style.display = 'none';
|
||||
} else {
|
||||
_gameSetSearchTimer = setTimeout(() => doGameSetSearch(value), 300);
|
||||
}
|
||||
}
|
||||
|
||||
async function doGameSetSearch(search) {
|
||||
try {
|
||||
const url = '/gruppe/chastity' + (search ? '?search=' + encodeURIComponent(search) : '');
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
_gameSetResults = data.gruppen || [];
|
||||
renderGameSetDropdown();
|
||||
} catch(e) { console.error(e); }
|
||||
}
|
||||
|
||||
function renderGameSetDropdown() {
|
||||
const dd = document.getElementById('gameSetDropdown');
|
||||
if (!dd) return;
|
||||
if (!_gameSetResults.length) { dd.style.display = 'none'; return; }
|
||||
dd.innerHTML = _gameSetResults.map(g => `
|
||||
<div class="gs-dropdown-item" onclick="selectGameSet('${esc(g.gruppenId)}','${esc(g.name).replace(/'/g, "\\'")}')">
|
||||
<div class="gs-item-name">${esc(g.name)}</div>
|
||||
${g.beschreibung ? `<div class="gs-item-desc">${esc(g.beschreibung)}</div>` : ''}
|
||||
</div>`).join('');
|
||||
dd.style.display = 'block';
|
||||
}
|
||||
|
||||
function selectGameSet(id, name, suppressDirty = false) {
|
||||
document.getElementById('fGameSetId').value = id;
|
||||
document.getElementById('gameSetSearch').value = '';
|
||||
document.getElementById('gameSetDropdown').style.display = 'none';
|
||||
document.getElementById('gameSetSelected').innerHTML =
|
||||
`<span style="flex:1;">${esc(name)}</span>
|
||||
<button type="button" onclick="clearGameSet()" title="Auswahl entfernen">✕</button>`;
|
||||
document.getElementById('gameSetSelected').style.display = 'flex';
|
||||
document.getElementById('errGameSet').style.display = 'none';
|
||||
if (!suppressDirty) markDirty();
|
||||
}
|
||||
|
||||
function clearGameSet() {
|
||||
document.getElementById('fGameSetId').value = '';
|
||||
document.getElementById('gameSetSearch').value = '';
|
||||
document.getElementById('gameSetSelected').style.display = 'none';
|
||||
document.getElementById('gameSetSelected').innerHTML = '';
|
||||
markDirty();
|
||||
}
|
||||
|
||||
document.addEventListener('click', e => {
|
||||
const search = document.getElementById('gameSetSearch');
|
||||
const dd = document.getElementById('gameSetDropdown');
|
||||
if (dd && search && !search.contains(e.target) && !dd.contains(e.target)) {
|
||||
dd.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// ── Karten-Info ──
|
||||
function openCardInfo(cardId) {
|
||||
const c = CARD_DEFS.find(x => x.id === cardId); if (!c) return;
|
||||
@@ -815,10 +913,8 @@
|
||||
<div id="we-tp-${id}" style="display:none;">
|
||||
<div class="time-picker">
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('wt${id}',-1,'d')">−</button><input type="text" id="wt${id}_d" value="0" readonly><button type="button" onclick="tpChange('wt${id}',1,'d')">+</button></div><span class="tp-label">Tage</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('wt${id}',-1,'h')">−</button><input type="text" id="wt${id}_h" value="01" readonly><button type="button" onclick="tpChange('wt${id}',1,'h')">+</button></div><span class="tp-label">Std</span></div>
|
||||
<div class="tp-colon">:</div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('wt${id}',-1,'m')">−</button><input type="text" id="wt${id}_m" value="00" readonly><button type="button" onclick="tpChange('wt${id}',1,'m')">+</button></div><span class="tp-label">Min</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('wt${id}',-1,'h')">−</button><input type="text" id="wt${id}_h" value="01" readonly><button type="button" onclick="tpChange('wt${id}',1,'h')">+</button></div><span class="tp-label">Stunden</span></div>
|
||||
<div class="tp-seg"><div class="tp-seg-row"><button type="button" onclick="tpChange('wt${id}',-1,'m')">−</button><input type="text" id="wt${id}_m" value="00" readonly><button type="button" onclick="tpChange('wt${id}',1,'m')">+</button></div><span class="tp-label">Minuten</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" id="we-str-${id}" placeholder="Text…" maxlength="200"
|
||||
@@ -1163,7 +1259,7 @@
|
||||
function alignModalToContent() {
|
||||
const rect = document.querySelector('.content')?.getBoundingClientRect();
|
||||
if (!rect) return;
|
||||
document.getElementById('modalBackdrop').querySelector('.modal-box').style.width = Math.min(rect.width, 720) + 'px';
|
||||
document.getElementById('modalBackdrop').querySelector('.modal-box').style.width = Math.min(rect.width, 800) + 'px';
|
||||
document.getElementById('taskSetModalBackdrop').querySelector('.modal-box').style.width = Math.min(rect.width, 900) + 'px';
|
||||
}
|
||||
|
||||
@@ -1201,6 +1297,20 @@
|
||||
tpFromMinutes('pe', template?.pickEveryMinute || 60);
|
||||
document.getElementById('fAccumulate').checked = template?.accumulatePicks || false;
|
||||
document.getElementById('fShowRemaining').checked = template?.showRemainingCards || false;
|
||||
|
||||
// Task-Karte und Spiel-Karte
|
||||
checkTaskCardSection();
|
||||
clearGameSet();
|
||||
checkGameCardSection();
|
||||
const gsi = template?.gameSpieldauerIdx ?? 2;
|
||||
document.getElementById('sldGameSpieldauer').value = gsi;
|
||||
updateGameSpieldauer(gsi);
|
||||
if (template?.gameSetId) {
|
||||
fetch(`/gruppe/${template.gameSetId}`)
|
||||
.then(r => r.ok ? r.json() : null)
|
||||
.then(g => { if (g?.name) selectGameSet(template.gameSetId, g.name, true); })
|
||||
.catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'TIMELOCK') {
|
||||
@@ -1350,7 +1460,15 @@
|
||||
const totalMax = CARD_DEFS.reduce((s,c)=>s+(parseInt(document.getElementById('max_'+c.id).value)||0),0);
|
||||
if (totalMax===0) { showModalError('Das Deck muss mindestens eine Karte enthalten.'); firstError=firstError||document.getElementById('modalError'); }
|
||||
const hasTaskCards = (parseInt(document.getElementById('min_TASK').value)||0)>0 || (parseInt(document.getElementById('max_TASK').value)||0)>0;
|
||||
if (hasTaskCards && !document.getElementById('fCardTaskSetId').value) { showModalError('Aufgaben-Karten konfiguriert, aber kein Aufgaben-Set ausgewählt.'); firstError=firstError||document.getElementById('modalError'); }
|
||||
if (hasTaskCards && !document.getElementById('fCardTaskSetId').value) { showModalError('Bitte ein Aufgaben-Set für die Aufgaben-Karten auswählen.'); firstError=firstError||document.getElementById('modalError'); }
|
||||
const hasGameCards = (parseInt(document.getElementById('min_GAME_CARD').value)||0)>0 || (parseInt(document.getElementById('max_GAME_CARD').value)||0)>0;
|
||||
if (hasGameCards && !document.getElementById('fGameSetId').value) {
|
||||
document.getElementById('errGameSet').style.display = '';
|
||||
showModalError('Spiel-Karten konfiguriert, aber kein Aufgaben-Set ausgewählt.');
|
||||
firstError = firstError || document.getElementById('errGameSet');
|
||||
} else {
|
||||
document.getElementById('errGameSet').style.display = 'none';
|
||||
}
|
||||
if (firstError) { firstError.scrollIntoView({behavior:'smooth',block:'center'}); return; }
|
||||
|
||||
const cardCountsMin={}, cardCountsMax={};
|
||||
@@ -1369,6 +1487,8 @@
|
||||
taskSetId: document.getElementById('fCardTaskSetId').value || null,
|
||||
requiresVerification: document.getElementById('fRequiresVerification').checked,
|
||||
taskMode: document.querySelector('input[name="modalCardTaskMode"]:checked')?.value||'RANDOM',
|
||||
gameSetId: hasGameCards ? (document.getElementById('fGameSetId').value || null) : null,
|
||||
gameSpieldauerIdx: hasGameCards ? (parseInt(document.getElementById('sldGameSpieldauer').value) || 2) : null,
|
||||
};
|
||||
} else {
|
||||
// TimeLock
|
||||
|
||||
Reference in New Issue
Block a user