Weiter am Taskgame gebastelt
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:
@@ -263,6 +263,12 @@
|
||||
cursor: pointer; transition: border-color 0.15s, color 0.15s;
|
||||
}
|
||||
.btn-item-edit:hover { border-color: var(--color-text); color: var(--color-text); }
|
||||
.btn-item-copy {
|
||||
background: none; border: 1px solid rgba(100,160,255,0.4); border-radius: 5px;
|
||||
color: var(--color-muted); font-size: 0.75rem; padding: 0.2rem 0.6rem;
|
||||
cursor: pointer; transition: border-color 0.15s, color 0.15s;
|
||||
}
|
||||
.btn-item-copy:hover { border-color: rgba(100,160,255,0.9); color: var(--color-text); }
|
||||
.btn-item-delete {
|
||||
background: none; border: 1px solid rgba(233,69,96,0.4); border-radius: 5px;
|
||||
color: var(--color-primary); font-size: 0.75rem; padding: 0.2rem 0.6rem;
|
||||
@@ -533,17 +539,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="iTempUnlockRow">
|
||||
<label>Temporäre Öffnungen</label>
|
||||
<div style="display:flex; flex-direction:column; gap:0.5rem; margin-top:0.5rem;">
|
||||
<label style="display:flex; align-items:center; gap:0.6rem; font-size:0.85rem; cursor:pointer;">
|
||||
<input type="checkbox" id="iTempUnlockBefore" style="accent-color:var(--color-primary); width:1rem; height:1rem;">
|
||||
Temporäre Öffnung <em>vor</em> der Zeitstrafe erforderlich
|
||||
</label>
|
||||
<label style="display:flex; align-items:center; gap:0.6rem; font-size:0.85rem; cursor:pointer;">
|
||||
<input type="checkbox" id="iTempUnlockAfter" style="accent-color:var(--color-primary); width:1rem; height:1rem;">
|
||||
Temporäre Öffnung <em>nach</em> der Zeitstrafe erforderlich
|
||||
</label>
|
||||
</div>
|
||||
<label class="toggle-switch" style="display:flex; align-items:center; gap:0.75rem; cursor:pointer; margin-top:0.25rem;">
|
||||
<input type="checkbox" id="iTempUnlockRequired">
|
||||
<span class="toggle-track"></span>
|
||||
<span style="font-size:0.9rem;">Temporäre Öffnung erforderlich</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="iReleaseTextRow">
|
||||
<label for="iReleaseText">Text bei Aufhebung</label>
|
||||
@@ -765,7 +765,7 @@
|
||||
${g.beschreibung ? `<div class="gruppe-desc">${esc(g.beschreibung)}</div>` : ''}
|
||||
${renderSubSection('Aufgaben', sortByLevelThenName(g.aufgaben || []), 'aufgabe', renderAufgabe, g.gruppenId, type)}
|
||||
${g.availableIn !== 'CHASTITY_ONLY' ? renderSubSection('Strafen', sortByLevelThenName(g.strafen || []), 'strafe', renderStrafe, g.gruppenId, type) : ''}
|
||||
${renderSubSection('Zeitstrafen',sortByName(g.sperren || []), 'zeitstrafe',renderZeitstrafe, g.gruppenId, type)}
|
||||
${renderSubSection('Zeitstrafen',sortByLevelThenName(g.sperren || []), 'zeitstrafe',renderZeitstrafe, g.gruppenId, type)}
|
||||
${renderSubSection('Finisher', sortByGeschlecht(g.finisher || []), 'finisher', renderFinisher, g.gruppenId, type)}
|
||||
</div>
|
||||
</div>`;
|
||||
@@ -814,6 +814,7 @@
|
||||
function renderAufgabe(a, type, gruppenId) {
|
||||
_itemData[a.aufgabeId] = { ...a, _kind: 'aufgabe', _gruppenId: gruppenId };
|
||||
const badges = [];
|
||||
(a.benoetigteToys || []).forEach(t => badges.push(`<span class="item-detail-chip item-detail-chip-toy">${esc(t.name || t)}</span>`));
|
||||
const zeit = formatSek(a.sekundenVon, a.sekundenBis);
|
||||
if (zeit) badges.push(`<span class="badge badge-neutral">${esc(zeit)}</span>`);
|
||||
if (a.level != null) badges.push(`<span class="badge">Level ${esc(String(a.level))}</span>`);
|
||||
@@ -826,6 +827,7 @@
|
||||
const actionBtns = type === 'user' ? `
|
||||
<div class="item-action-btns">
|
||||
<button class="btn-item-edit" onclick="openEditItemModal('${esc(a.aufgabeId)}',event)">✎ Bearbeiten</button>
|
||||
<button class="btn-item-copy" onclick="duplicateItem('aufgabe','${esc(a.aufgabeId)}','${esc(gruppenId)}',event)">⧉ Duplizieren</button>
|
||||
<button class="btn-item-delete" onclick="deleteItem('aufgabe','${esc(a.aufgabeId)}','${esc(gruppenId)}',event)">✕ Löschen</button>
|
||||
</div>` : '';
|
||||
|
||||
@@ -841,6 +843,7 @@
|
||||
function renderStrafe(s, type, gruppenId) {
|
||||
_itemData[s.strafeId] = { ...s, _kind: 'strafe', _gruppenId: gruppenId };
|
||||
const badges = [];
|
||||
(s.benoetigteToys || []).forEach(t => badges.push(`<span class="item-detail-chip item-detail-chip-toy">${esc(t.name || t)}</span>`));
|
||||
const zeit = formatSek(s.sekundenVon, s.sekundenBis);
|
||||
if (zeit) badges.push(`<span class="badge badge-neutral">${esc(zeit)}</span>`);
|
||||
if (s.level != null) badges.push(`<span class="badge">Level ${esc(String(s.level))}</span>`);
|
||||
@@ -853,6 +856,7 @@
|
||||
const actionBtns = type === 'user' ? `
|
||||
<div class="item-action-btns">
|
||||
<button class="btn-item-edit" onclick="openEditItemModal('${esc(s.strafeId)}',event)">✎ Bearbeiten</button>
|
||||
<button class="btn-item-copy" onclick="duplicateItem('strafe','${esc(s.strafeId)}','${esc(gruppenId)}',event)">⧉ Duplizieren</button>
|
||||
<button class="btn-item-delete" onclick="deleteItem('strafe','${esc(s.strafeId)}','${esc(gruppenId)}',event)">✕ Löschen</button>
|
||||
</div>` : '';
|
||||
|
||||
@@ -868,8 +872,10 @@
|
||||
function renderZeitstrafe(z, type, gruppenId) {
|
||||
_itemData[z.sperreId] = { ...z, _kind: 'zeitstrafe', _gruppenId: gruppenId };
|
||||
const badges = [];
|
||||
(z.benoetigteToys || []).forEach(t => badges.push(`<span class="item-detail-chip item-detail-chip-toy">${esc(t.name || t)}</span>`));
|
||||
const zeit = formatMin(z.minutenVon, z.minutenBis);
|
||||
if (zeit) badges.push(`<span class="badge badge-neutral">${esc(zeit)}</span>`);
|
||||
if (z.level != null) badges.push(`<span class="badge">Level ${esc(String(z.level))}</span>`);
|
||||
|
||||
const detailRows = [];
|
||||
if (z.text) detailRows.push(`<div class="item-detail-text">${esc(z.text)}</div>`);
|
||||
@@ -879,6 +885,7 @@
|
||||
const actionBtns = type === 'user' ? `
|
||||
<div class="item-action-btns">
|
||||
<button class="btn-item-edit" onclick="openEditItemModal('${esc(z.sperreId)}',event)">✎ Bearbeiten</button>
|
||||
<button class="btn-item-copy" onclick="duplicateItem('zeitstrafe','${esc(z.sperreId)}','${esc(gruppenId)}',event)">⧉ Duplizieren</button>
|
||||
<button class="btn-item-delete" onclick="deleteItem('zeitstrafe','${esc(z.sperreId)}','${esc(gruppenId)}',event)">✕ Löschen</button>
|
||||
</div>` : '';
|
||||
|
||||
@@ -896,6 +903,7 @@
|
||||
function renderFinisher(f, type, gruppenId) {
|
||||
_itemData[f.finisherId] = { ...f, _kind: 'finisher', _gruppenId: gruppenId };
|
||||
const badges = [];
|
||||
(f.benoetigteToys || []).forEach(t => badges.push(`<span class="item-detail-chip item-detail-chip-toy">${esc(t.name || t)}</span>`));
|
||||
if (f.geschlecht) badges.push(`<span class="badge badge-neutral">${esc(GESCHLECHT_LABEL[f.geschlecht] || f.geschlecht)}</span>`);
|
||||
|
||||
const detailRows = [];
|
||||
@@ -906,6 +914,7 @@
|
||||
const actionBtns = type === 'user' ? `
|
||||
<div class="item-action-btns">
|
||||
<button class="btn-item-edit" onclick="openEditItemModal('${esc(f.finisherId)}',event)">✎ Bearbeiten</button>
|
||||
<button class="btn-item-copy" onclick="duplicateItem('finisher','${esc(f.finisherId)}','${esc(gruppenId)}',event)">⧉ Duplizieren</button>
|
||||
<button class="btn-item-delete" onclick="deleteItem('finisher','${esc(f.finisherId)}','${esc(gruppenId)}',event)">✕ Löschen</button>
|
||||
</div>` : '';
|
||||
|
||||
@@ -944,10 +953,36 @@
|
||||
finisher: apiUrl('/finisher')
|
||||
};
|
||||
const ITEM_DELETE_FIELD = { aufgabe: 'aufgabeId', strafe: 'strafeId', zeitstrafe: 'sperreId', finisher: 'finisherId' };
|
||||
const ITEM_COPY_URL = {
|
||||
aufgabe: apiUrl('/aufgabe/copy'),
|
||||
strafe: '/strafe/copy',
|
||||
zeitstrafe: '/sperre/copy',
|
||||
finisher: apiUrl('/finisher/copy')
|
||||
};
|
||||
|
||||
function duplicateItem(kind, itemId, gruppenId, event) {
|
||||
event.stopPropagation();
|
||||
const copyUrl = ITEM_COPY_URL[kind];
|
||||
if (!copyUrl) return;
|
||||
fetch(`${copyUrl}/${itemId}`, { method: 'POST' }).then(r => {
|
||||
if (r.ok) {
|
||||
pendingExpandId = gruppenId;
|
||||
pendingExpandType = 'user';
|
||||
_notifyOnLoad = true; loadUserGruppen();
|
||||
} else {
|
||||
document.getElementById('userActionError').textContent = 'Fehler beim Duplizieren (HTTP ' + r.status + ').';
|
||||
}
|
||||
}).catch(() => {
|
||||
document.getElementById('userActionError').textContent = 'Verbindungsfehler.';
|
||||
});
|
||||
}
|
||||
|
||||
function deleteItem(kind, itemId, gruppenId, event) {
|
||||
event.stopPropagation();
|
||||
if (!confirm('Eintrag wirklich löschen?')) return;
|
||||
openConfirmModal('Eintrag wirklich löschen?', () => _doDeleteItem(kind, itemId, gruppenId));
|
||||
}
|
||||
|
||||
function _doDeleteItem(kind, itemId, gruppenId) {
|
||||
const deleteUrl = ITEM_DELETE_URL[kind];
|
||||
if (!deleteUrl) return;
|
||||
const body = { [ITEM_DELETE_FIELD[kind]]: itemId };
|
||||
@@ -1430,7 +1465,7 @@
|
||||
const lbl = document.querySelector(`#iSperreFuer input[value="${v}"]`)?.closest('label');
|
||||
if (lbl) lbl.style.display = isChastity ? 'none' : '';
|
||||
});
|
||||
document.getElementById('iTempUnlockRow').style.display = (isZeit && isChastity) ? 'block' : 'none';
|
||||
document.getElementById('iTempUnlockRow').style.display = ((isZeit || isFinisher) && isChastity) ? 'block' : 'none';
|
||||
document.getElementById('iReleaseTextRow').style.display = isZeit ? 'block' : 'none';
|
||||
}
|
||||
|
||||
@@ -1449,8 +1484,7 @@
|
||||
document.querySelectorAll('#iWerkzeugFinisherPassiv input').forEach(cb => cb.checked = false);
|
||||
document.querySelectorAll('#iSperreFuer input').forEach(cb => cb.checked = false);
|
||||
document.querySelectorAll('#iGeschlecht input').forEach(rb => rb.checked = false);
|
||||
document.getElementById('iTempUnlockBefore').checked = false;
|
||||
document.getElementById('iTempUnlockAfter').checked = false;
|
||||
document.getElementById('iTempUnlockRequired').checked = false;
|
||||
_selectedToys = [];
|
||||
renderSelectedToys();
|
||||
document.getElementById('itemModalError').style.display = 'none';
|
||||
@@ -1495,6 +1529,9 @@
|
||||
const rb = document.querySelector(`#iGeschlecht input[value="${d.geschlecht}"]`);
|
||||
if (rb) rb.checked = true;
|
||||
}
|
||||
if (_isChastityMode) {
|
||||
document.getElementById('iTempUnlockRequired').checked = d.tempUnlockRequired === true;
|
||||
}
|
||||
} else {
|
||||
document.getElementById('iMinVon').value = d.minutenVon != null ? d.minutenVon : '';
|
||||
document.getElementById('iMinBis').value = d.minutenBis != null ? d.minutenBis : '';
|
||||
@@ -1502,8 +1539,7 @@
|
||||
(d.sperreFuer || []).forEach(w => { const cb = document.querySelector(`#iSperreFuer input[value="${w}"]`); if (cb) cb.checked = true; });
|
||||
if (_isChastityMode) {
|
||||
document.getElementById('iLevel').value = d.level != null ? d.level : '';
|
||||
document.getElementById('iTempUnlockBefore').checked = d.tempUnlockBeforeRequired === true;
|
||||
document.getElementById('iTempUnlockAfter').checked = d.tempUnlockAfterRequired === true;
|
||||
document.getElementById('iTempUnlockRequired').checked = d.tempUnlockRequired === true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1666,11 +1702,12 @@
|
||||
if (!_isChastityMode && !geschlecht) { showItemError('Bitte ein Geschlecht auswählen.'); return; }
|
||||
payload = {
|
||||
kurzText, text,
|
||||
geschlecht: geschlecht || null,
|
||||
gruppeId: isEdit ? undefined : currentItemGruppeId,
|
||||
benoetigtAktiv: _isChastityMode ? [] : checkedValues('iWerkzeugFinisherAktiv'),
|
||||
benoetigtPassiv: _isChastityMode ? [] : checkedValues('iWerkzeugFinisherPassiv'),
|
||||
benoetigteToys: _selectedToys.map(t => ({ toyId: t.toyId }))
|
||||
geschlecht: geschlecht || null,
|
||||
gruppeId: isEdit ? undefined : currentItemGruppeId,
|
||||
benoetigtAktiv: _isChastityMode ? [] : checkedValues('iWerkzeugFinisherAktiv'),
|
||||
benoetigtPassiv: _isChastityMode ? [] : checkedValues('iWerkzeugFinisherPassiv'),
|
||||
benoetigteToys: _selectedToys.map(t => ({ toyId: t.toyId })),
|
||||
tempUnlockRequired: _isChastityMode ? document.getElementById('iTempUnlockRequired').checked : null
|
||||
};
|
||||
url = isEdit ? apiUrl(`/finisher/${currentItemEditId}`) : apiUrl('/finisher');
|
||||
method = isEdit ? 'PUT' : 'POST';
|
||||
@@ -1698,8 +1735,7 @@
|
||||
releaseText: document.getElementById('iReleaseText').value.trim() || null,
|
||||
sperreFuer,
|
||||
level: zeitLevel,
|
||||
tempUnlockBeforeRequired: _isChastityMode ? document.getElementById('iTempUnlockBefore').checked : null,
|
||||
tempUnlockAfterRequired: _isChastityMode ? document.getElementById('iTempUnlockAfter').checked : null,
|
||||
tempUnlockRequired: _isChastityMode ? document.getElementById('iTempUnlockRequired').checked : null,
|
||||
benoetigteToys: _selectedToys.map(t => ({ toyId: t.toyId }))
|
||||
};
|
||||
url = isEdit ? `/sperre/${currentItemEditId}` : '/sperre'; // BDSM-only
|
||||
|
||||
Reference in New Issue
Block a user