feat: Rubrik-Dropdown beim Live-Stellen — freie Kategoriewahl
- Neuer <select id='rubricSelect'> neben dem 🔴 Live Toggle
- Alle 10 Rubriken: Nachrichten, Angebot, Crowdfunding, Branche,
Neuerscheinungen, Ankündigungen, Zubehör, Brettspieltest, Magazin, Video, Podcast
- Bei Live+Haken: Rubrik-Wahl pflicht (Toast wenn 'Rubrik wählen…' gesetzt)
- Backend _handle_publish: nutzt rubric vom Client statt meta category-id
- SAFETY GATE bleibt: ohne Live-Haken → immer Korrektur (catid=61)
- Confirm-Dialog zeigt gewählte Rubrik an
This commit is contained in:
+32
-6
@@ -307,6 +307,9 @@ def build_index(articles: list[dict]) -> str:
|
|||||||
.live-toggle-label:hover {{ border-color: var(--accent); }}
|
.live-toggle-label:hover {{ border-color: var(--accent); }}
|
||||||
.live-toggle-label:has(input:checked) {{ background: #fef2f2; border-color: #dc3545; color: #dc3545; }}
|
.live-toggle-label:has(input:checked) {{ background: #fef2f2; border-color: #dc3545; color: #dc3545; }}
|
||||||
.live-toggle-label input {{ accent-color: #dc3545; }}
|
.live-toggle-label input {{ accent-color: #dc3545; }}
|
||||||
|
|
||||||
|
.rubric-live-select {{ font-family: var(--font); font-size: 0.8rem; padding: 0.35rem 0.7rem; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--text); cursor: pointer; }}
|
||||||
|
.rubric-live-select:focus {{ outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgba(32,34,138,0.15); }}
|
||||||
.upload-label {{ display: inline-flex; }}
|
.upload-label {{ display: inline-flex; }}
|
||||||
|
|
||||||
.token-indicator {{ font-size: 0.7rem; margin-left: 0.6rem; opacity: 0.8; }}
|
.token-indicator {{ font-size: 0.7rem; margin-left: 0.6rem; opacity: 0.8; }}
|
||||||
@@ -434,6 +437,20 @@ def build_index(articles: list[dict]) -> str:
|
|||||||
<input type="checkbox" id="liveToggle" onchange="updateLiveMode()">
|
<input type="checkbox" id="liveToggle" onchange="updateLiveMode()">
|
||||||
<span class="live-toggle-text">🔴 Live</span>
|
<span class="live-toggle-text">🔴 Live</span>
|
||||||
</label>
|
</label>
|
||||||
|
<select id="rubricSelect" class="rubric-live-select" onchange="updateLiveMode()">
|
||||||
|
<option value="0">📂 Rubrik wählen…</option>
|
||||||
|
<option value="9">📰 Nachrichten</option>
|
||||||
|
<option value="64" class="sub">└ Angebot</option>
|
||||||
|
<option value="65" class="sub">└ Crowdfunding</option>
|
||||||
|
<option value="66" class="sub">└ Branche</option>
|
||||||
|
<option value="67" class="sub">└ Neuerscheinungen</option>
|
||||||
|
<option value="68" class="sub">└ Ankündigungen</option>
|
||||||
|
<option value="69" class="sub">└ Zubehör</option>
|
||||||
|
<option value="8">🎲 Brettspieltest</option>
|
||||||
|
<option value="11">📖 Magazin</option>
|
||||||
|
<option value="10">🎬 Video</option>
|
||||||
|
<option value="55">🎙 Podcast</option>
|
||||||
|
</select>
|
||||||
<button class="btn btn-publish" id="publishBtn" onclick="publishSelected()" disabled{publish_title}>📢 Veröffentlichen</button>
|
<button class="btn btn-publish" id="publishBtn" onclick="publishSelected()" disabled{publish_title}>📢 Veröffentlichen</button>
|
||||||
<button class="btn btn-delete" id="deleteBtn" onclick="deleteSelected()" disabled>Markierte löschen</button>
|
<button class="btn btn-delete" id="deleteBtn" onclick="deleteSelected()" disabled>Markierte löschen</button>
|
||||||
<span class="counter" id="counter">0 markiert</span>
|
<span class="counter" id="counter">0 markiert</span>
|
||||||
@@ -612,6 +629,12 @@ def build_index(articles: list[dict]) -> str:
|
|||||||
const selected = Array.from(document.querySelectorAll('.article-check:checked')).map(cb => cb.value);
|
const selected = Array.from(document.querySelectorAll('.article-check:checked')).map(cb => cb.value);
|
||||||
if (selected.length === 0) return;
|
if (selected.length === 0) return;
|
||||||
const live = document.getElementById('liveToggle').checked;
|
const live = document.getElementById('liveToggle').checked;
|
||||||
|
const rubric = document.getElementById('rubricSelect').value;
|
||||||
|
|
||||||
|
if (live && rubric === '0') {{
|
||||||
|
showToast('❌ Bitte eine Rubrik wählen (Dropdown rechts neben 🔴 Live)', true);
|
||||||
|
return;
|
||||||
|
}}
|
||||||
|
|
||||||
// Readiness-Warnung (soft, blockiert nicht)
|
// Readiness-Warnung (soft, blockiert nicht)
|
||||||
const notReady = [];
|
const notReady = [];
|
||||||
@@ -623,7 +646,8 @@ def build_index(articles: list[dict]) -> str:
|
|||||||
}});
|
}});
|
||||||
let confirmMsg;
|
let confirmMsg;
|
||||||
if (live) {{
|
if (live) {{
|
||||||
confirmMsg = '🔴 LIVE: ' + selected.length + ' Artikel ÖFFENTLICH veröffentlichen?\\n\\nDies ist für 10.000+ Leser sichtbar!';
|
const rubricName = document.getElementById('rubricSelect').selectedOptions[0].text;
|
||||||
|
confirmMsg = '🔴 LIVE in »' + rubricName + '«: ' + selected.length + ' Artikel ÖFFENTLICH veröffentlichen?\\n\\nDies ist für 10.000+ Leser sichtbar!';
|
||||||
}} else {{
|
}} else {{
|
||||||
confirmMsg = selected.length + ' Artikel auf KORREKTUR hochladen?\\n\\nNur Redaktion sichtbar. Sicher.';
|
confirmMsg = selected.length + ' Artikel auf KORREKTUR hochladen?\\n\\nNur Redaktion sichtbar. Sicher.';
|
||||||
}}
|
}}
|
||||||
@@ -640,7 +664,7 @@ def build_index(articles: list[dict]) -> str:
|
|||||||
const resp = await fetch('/publish', {{
|
const resp = await fetch('/publish', {{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {{'Content-Type': 'application/json', 'Authorization': 'Basic ' + auth}},
|
headers: {{'Content-Type': 'application/json', 'Authorization': 'Basic ' + auth}},
|
||||||
body: JSON.stringify({{files: selected, live: live}})
|
body: JSON.stringify({{files: selected, live: live, rubric: parseInt(rubric)}})
|
||||||
}});
|
}});
|
||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
if (data.ok) {{
|
if (data.ok) {{
|
||||||
@@ -1011,6 +1035,7 @@ h1{color:#c0392b;}p{color:#888;}</style></head>
|
|||||||
data = json.loads(body)
|
data = json.loads(body)
|
||||||
files = data.get("files", [])
|
files = data.get("files", [])
|
||||||
allow_live = data.get("live", False) # SAFETY GATE: Nur wenn explizit true
|
allow_live = data.get("live", False) # SAFETY GATE: Nur wenn explizit true
|
||||||
|
rubric = data.get("rubric", 0) # 0 = nicht gesetzt
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
self._json_reply(400, {"ok": False, "error": "Invalid JSON"})
|
self._json_reply(400, {"ok": False, "error": "Invalid JSON"})
|
||||||
return
|
return
|
||||||
@@ -1091,10 +1116,11 @@ h1{color:#c0392b;}p{color:#888;}</style></head>
|
|||||||
jid_match = re.search(r'<meta\s+name="joomla-id"\s+content="(\d+)"', html_content, re.IGNORECASE)
|
jid_match = re.search(r'<meta\s+name="joomla-id"\s+content="(\d+)"', html_content, re.IGNORECASE)
|
||||||
joomla_id = jid_match.group(1) if jid_match else None
|
joomla_id = jid_match.group(1) if jid_match else None
|
||||||
|
|
||||||
# ── SAFETY GATE: Ohne live=true ALLES auf Korrektur ─────
|
# ── Kategorie: Rubrik vom Dropdown oder meta ──────────
|
||||||
# Extract category from meta – NUR wenn live explizit erlaubt
|
catid = 61 # Default: Korrektur
|
||||||
catid = 61 # Default: Korrektur (Redaktion-only, nicht öffentlich)
|
if allow_live and rubric > 0:
|
||||||
if allow_live:
|
catid = rubric
|
||||||
|
elif allow_live:
|
||||||
cat_match = re.search(r'<meta\s+name="category-id"\s+content="(\d+)"', html_content, re.IGNORECASE)
|
cat_match = re.search(r'<meta\s+name="category-id"\s+content="(\d+)"', html_content, re.IGNORECASE)
|
||||||
if cat_match:
|
if cat_match:
|
||||||
catid = int(cat_match.group(1))
|
catid = int(cat_match.group(1))
|
||||||
|
|||||||
Reference in New Issue
Block a user