add Multible Images to News
This commit is contained in:
303
admin.php
303
admin.php
@@ -1,8 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
// admin.php - Multi-User Login, Google Authenticator 2FA, Cropper, News Verwaltung & AES-256 VERSCHLÜSSELUNG
|
// admin.php - Multi-User Login, Google Authenticator 2FA, 4-Bilder Upload & News Verwaltung
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
// Fehleranzeige (für Live-Betrieb auf 0 setzen - oder anlassen, wenn du Schmerzen magst)
|
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
@@ -13,7 +12,6 @@ error_reporting(E_ALL);
|
|||||||
class MiniTOTP {
|
class MiniTOTP {
|
||||||
public static function verify($secret, $code) {
|
public static function verify($secret, $code) {
|
||||||
$time = floor(time() / 30);
|
$time = floor(time() / 30);
|
||||||
// Prüft aktuelles, vorheriges und nächstes Zeitfenster (Toleranz)
|
|
||||||
for ($i = -1; $i <= 1; $i++) {
|
for ($i = -1; $i <= 1; $i++) {
|
||||||
if (self::getCode($secret, $time + $i) === $code) return true;
|
if (self::getCode($secret, $time + $i) === $code) return true;
|
||||||
}
|
}
|
||||||
@@ -61,13 +59,18 @@ try {
|
|||||||
$db = new PDO('sqlite:news_database.sqlite');
|
$db = new PDO('sqlite:news_database.sqlite');
|
||||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
// News Tabelle
|
// News Tabelle initialisieren
|
||||||
$db->exec("CREATE TABLE IF NOT EXISTS news (
|
$db->exec("CREATE TABLE IF NOT EXISTS news (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, department TEXT, title TEXT, content TEXT, full_text TEXT, image TEXT, link TEXT
|
id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, department TEXT, title TEXT, content TEXT, full_text TEXT, image TEXT, link TEXT
|
||||||
)");
|
)");
|
||||||
try { $db->exec("ALTER TABLE news ADD COLUMN full_text TEXT"); } catch(PDOException $e) {}
|
|
||||||
|
|
||||||
// Benutzer Tabelle
|
// DB-Schema Updates (Falls noch alte Version)
|
||||||
|
try { $db->exec("ALTER TABLE news ADD COLUMN full_text TEXT"); } catch(PDOException $e) {}
|
||||||
|
try { $db->exec("ALTER TABLE news ADD COLUMN image2 TEXT"); } catch(PDOException $e) {}
|
||||||
|
try { $db->exec("ALTER TABLE news ADD COLUMN image3 TEXT"); } catch(PDOException $e) {}
|
||||||
|
try { $db->exec("ALTER TABLE news ADD COLUMN image4 TEXT"); } catch(PDOException $e) {}
|
||||||
|
try { $db->exec("ALTER TABLE news ADD COLUMN title_index INTEGER DEFAULT 1"); } catch(PDOException $e) {}
|
||||||
|
|
||||||
$db->exec("CREATE TABLE IF NOT EXISTS users (
|
$db->exec("CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, password_hash TEXT, totp_secret TEXT
|
id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, password_hash TEXT, totp_secret TEXT
|
||||||
)");
|
)");
|
||||||
@@ -78,17 +81,14 @@ try {
|
|||||||
$userCount = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
$userCount = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// 3. ERSTEINRICHTUNG (Wenn keine Nutzer existieren)
|
// 3. ERSTEINRICHTUNG
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
if ($userCount == 0) {
|
if ($userCount == 0) {
|
||||||
$setup_msg = "";
|
|
||||||
$new_secret = MiniTOTP::generateSecret();
|
$new_secret = MiniTOTP::generateSecret();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['do_setup'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['do_setup'])) {
|
||||||
$user = trim($_POST['username']);
|
$user = trim($_POST['username']);
|
||||||
$pass = $_POST['password'];
|
$pass = $_POST['password'];
|
||||||
$secret = $_POST['totp_secret'];
|
$secret = $_POST['totp_secret'];
|
||||||
|
|
||||||
if (!empty($user) && !empty($pass)) {
|
if (!empty($user) && !empty($pass)) {
|
||||||
$stmt = $db->prepare("INSERT INTO users (username, password_hash, totp_secret) VALUES (?, ?, ?)");
|
$stmt = $db->prepare("INSERT INTO users (username, password_hash, totp_secret) VALUES (?, ?, ?)");
|
||||||
$stmt->execute([$user, password_hash($pass, PASSWORD_DEFAULT), $secret]);
|
$stmt->execute([$user, password_hash($pass, PASSWORD_DEFAULT), $secret]);
|
||||||
@@ -99,15 +99,10 @@ if ($userCount == 0) {
|
|||||||
?>
|
?>
|
||||||
<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><title>Setup | SG 07</title>
|
<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><title>Setup | SG 07</title>
|
||||||
<style>body{font-family:sans-serif;background:#f4f4f4;display:flex;justify-content:center;align-items:center;height:100vh;} .box{background:#fff;padding:30px;border-radius:8px;box-shadow:0 4px 15px rgba(0,0,0,0.1);max-width:400px;text-align:center;} input,button{width:100%;padding:10px;margin:10px 0;box-sizing:border-box;} button{background:#d32f2f;color:white;border:none;font-weight:bold;cursor:pointer;} .qr{margin:20px 0;}</style></head>
|
<style>body{font-family:sans-serif;background:#f4f4f4;display:flex;justify-content:center;align-items:center;height:100vh;} .box{background:#fff;padding:30px;border-radius:8px;box-shadow:0 4px 15px rgba(0,0,0,0.1);max-width:400px;text-align:center;} input,button{width:100%;padding:10px;margin:10px 0;box-sizing:border-box;} button{background:#d32f2f;color:white;border:none;font-weight:bold;cursor:pointer;} .qr{margin:20px 0;}</style></head>
|
||||||
<body><div class="box"><h1 style="color:#d32f2f;">Ersteinrichtung</h1><p>Erstelle den ersten Admin-Zugang.</p>
|
<body><div class="box"><h1 style="color:#d32f2f;">Ersteinrichtung</h1>
|
||||||
<img src="<?= MiniTOTP::getQRCodeUrl('Admin', $new_secret) ?>" class="qr" alt="QR Code">
|
<img src="<?= MiniTOTP::getQRCodeUrl('Admin', $new_secret) ?>" class="qr" alt="QR Code">
|
||||||
<p style="font-size:0.9rem;color:#666;">1. Scanne diesen QR-Code mit dem <b>Google Authenticator</b> oder <b>Authy</b>.</p>
|
<p style="font-size:0.9rem;color:#666;">1. Scanne diesen QR-Code mit dem <b>Google Authenticator</b> oder <b>Authy</b>.</p>
|
||||||
<form method="POST">
|
<form method="POST"><input type="text" name="username" placeholder="Benutzername" required><input type="password" name="password" placeholder="Sicheres Passwort" required><input type="hidden" name="totp_secret" value="<?= $new_secret ?>"><button type="submit" name="do_setup">Admin anlegen & weiter</button></form></div></body></html>
|
||||||
<input type="text" name="username" placeholder="Benutzername" required>
|
|
||||||
<input type="password" name="password" placeholder="Sicheres Passwort" required>
|
|
||||||
<input type="hidden" name="totp_secret" value="<?= $new_secret ?>">
|
|
||||||
<button type="submit" name="do_setup">Admin anlegen & weiter</button>
|
|
||||||
</form></div></body></html>
|
|
||||||
<?php exit;
|
<?php exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,12 +138,7 @@ if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
|
|||||||
<style>body{font-family:'Segoe UI',sans-serif;background:#f4f4f4;display:flex;justify-content:center;align-items:center;height:100vh;} .login-box{background:#fff;padding:40px;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,0.1);max-width:350px;width:100%;text-align:center;border-top:5px solid #d32f2f;} input{width:100%;padding:12px;margin-bottom:15px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;} button{width:100%;padding:14px;background:#d32f2f;color:white;border:none;font-weight:bold;border-radius:4px;cursor:pointer;} button:hover{background:#9a0007;} .err{color:red;margin-bottom:15px;}</style></head>
|
<style>body{font-family:'Segoe UI',sans-serif;background:#f4f4f4;display:flex;justify-content:center;align-items:center;height:100vh;} .login-box{background:#fff;padding:40px;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,0.1);max-width:350px;width:100%;text-align:center;border-top:5px solid #d32f2f;} input{width:100%;padding:12px;margin-bottom:15px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;} button{width:100%;padding:14px;background:#d32f2f;color:white;border:none;font-weight:bold;border-radius:4px;cursor:pointer;} button:hover{background:#9a0007;} .err{color:red;margin-bottom:15px;}</style></head>
|
||||||
<body><div class="login-box"><div style="font-size:3rem;">🔒</div><h1 style="color:#d32f2f;margin-bottom:20px;">Admin Login</h1>
|
<body><div class="login-box"><div style="font-size:3rem;">🔒</div><h1 style="color:#d32f2f;margin-bottom:20px;">Admin Login</h1>
|
||||||
<?php if($login_error) echo "<div class='err'>$login_error</div>"; ?>
|
<?php if($login_error) echo "<div class='err'>$login_error</div>"; ?>
|
||||||
<form method="POST">
|
<form method="POST"><input type="text" name="username" placeholder="Benutzername" required autofocus><input type="password" name="password" placeholder="Passwort" required><input type="text" name="totp_code" placeholder="6-stelliger Authenticator Code" pattern="\d{6}" maxlength="6" required autocomplete="off"><button type="submit" name="do_login">Sicher einloggen</button></form></div></body></html>
|
||||||
<input type="text" name="username" placeholder="Benutzername" required autofocus>
|
|
||||||
<input type="password" name="password" placeholder="Passwort" required>
|
|
||||||
<input type="text" name="totp_code" placeholder="6-stelliger Authenticator Code" pattern="\d{6}" maxlength="6" required autocomplete="off">
|
|
||||||
<button type="submit" name="do_login">Sicher einloggen</button>
|
|
||||||
</form></div></body></html>
|
|
||||||
<?php exit;
|
<?php exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,65 +147,73 @@ if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
$message = "";
|
$message = "";
|
||||||
|
|
||||||
// --- BILD-UPLOAD FUNKTION (mit Base64 Crop-Unterstützung) ---
|
// Bild-Upload Helper für 4 Slots
|
||||||
function handleImageUpload() {
|
function handleSingleImage($index) {
|
||||||
if (!empty($_POST['cropped_image_data'])) {
|
$final_path = '';
|
||||||
$data = $_POST['cropped_image_data'];
|
|
||||||
list($type, $data) = explode(';', $data);
|
|
||||||
list(, $data) = explode(',', $data);
|
|
||||||
$data = base64_decode($data);
|
|
||||||
|
|
||||||
|
// Altes Bild behalten, falls im Edit-Modus und nichts Neues hochgeladen wird
|
||||||
|
if (isset($_POST['existing_image_'.$index]) && !empty($_POST['existing_image_'.$index])) {
|
||||||
|
$final_path = $_POST['existing_image_'.$index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Priorität: Neuer Datei-Upload
|
||||||
|
if (isset($_FILES['image_file_'.$index]) && $_FILES['image_file_'.$index]['error'] === UPLOAD_ERR_OK) {
|
||||||
$year = date('Y');
|
$year = date('Y');
|
||||||
$upload_dir = __DIR__ . '/img/news/' . $year;
|
$upload_dir = __DIR__ . '/img/news/' . $year;
|
||||||
if (!is_dir($upload_dir)) {
|
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||||
mkdir($upload_dir, 0777, true); // Erstellt den Ordner, wenn er fehlt
|
|
||||||
|
$ext = strtolower(pathinfo($_FILES['image_file_'.$index]['name'], PATHINFO_EXTENSION));
|
||||||
|
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||||
|
|
||||||
|
if (in_array($ext, $allowed)) {
|
||||||
|
$filename = date('Ymd') . '_' . rand(10000, 99999) . '_img' . $index . '.' . $ext;
|
||||||
|
if (move_uploaded_file($_FILES['image_file_'.$index]['tmp_name'], $upload_dir . '/' . $filename)) {
|
||||||
|
$final_path = 'img/news/' . $year . '/' . $filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. Priorität: Bild-URL
|
||||||
|
elseif (isset($_POST['image_url_'.$index]) && !empty($_POST['image_url_'.$index])) {
|
||||||
|
$final_path = str_replace(['http://new.sg07-stleon.de/', 'https://new.sg07-stleon.de/', 'new.sg07-stleon.de/', 'new.sg07-stleon.de\\'], '', trim($_POST['image_url_'.$index]));
|
||||||
|
}
|
||||||
|
// 3. Priorität: Platzhalter
|
||||||
|
elseif (isset($_POST['placeholder_image_'.$index]) && !empty($_POST['placeholder_image_'.$index])) {
|
||||||
|
$final_path = $_POST['placeholder_image_'.$index];
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = date('Ymd') . '_' . rand(10000, 99999) . '.jpg';
|
// Leeres Bild zurücksetzen, wenn der Nutzer explizit "löschen" wollte (hier vereinfacht: wenn URL und Platzhalter leer sind und kein Upload stattfand)
|
||||||
$target_file = $upload_dir . '/' . $filename;
|
if (empty($_FILES['image_file_'.$index]['name']) && empty($_POST['image_url_'.$index]) && empty($_POST['placeholder_image_'.$index]) && !isset($_POST['keep_existing_'.$index])) {
|
||||||
|
// Logik zum Behalten wird via Checkboxen geregelt, siehe Formular
|
||||||
|
}
|
||||||
|
|
||||||
if (file_put_contents($target_file, $data)) {
|
return $final_path;
|
||||||
return 'img/news/' . $year . '/' . $filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- AKTION: NEWS AKTUALISIEREN (EDIT) ---
|
// --- AKTION: NEWS AKTUALISIEREN (EDIT) ---
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_news'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_news'])) {
|
||||||
$final_image_path = $_POST['existing_image'];
|
$img1 = handleSingleImage(1);
|
||||||
|
$img2 = handleSingleImage(2);
|
||||||
|
$img3 = handleSingleImage(3);
|
||||||
|
$img4 = handleSingleImage(4);
|
||||||
|
$title_idx = (int)$_POST['title_index'];
|
||||||
|
|
||||||
$uploaded_img = handleImageUpload();
|
$stmt = $db->prepare("UPDATE news SET date=?, department=?, title=?, content=?, full_text=?, image=?, image2=?, image3=?, image4=?, title_index=?, link=? WHERE id=?");
|
||||||
if ($uploaded_img) {
|
if ($stmt->execute([$_POST['date'], $_POST['department'], $_POST['title'], $_POST['content'], $_POST['full_text'], $img1, $img2, $img3, $img4, $title_idx, $_POST['link'], $_POST['news_id']])) {
|
||||||
$final_image_path = $uploaded_img;
|
$message = "<div class='success'>✓ News (inkl. Galerie) erfolgreich aktualisiert!</div>";
|
||||||
} elseif (isset($_POST['image_url']) && !empty($_POST['image_url'])) {
|
|
||||||
$final_image_path = str_replace(['http://new.sg07-stleon.de/', 'https://new.sg07-stleon.de/', 'new.sg07-stleon.de/', 'new.sg07-stleon.de\\'], '', trim($_POST['image_url']));
|
|
||||||
} elseif (isset($_POST['placeholder_image']) && !empty($_POST['placeholder_image'])) {
|
|
||||||
$final_image_path = $_POST['placeholder_image'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt = $db->prepare("UPDATE news SET date=?, department=?, title=?, content=?, full_text=?, image=?, link=? WHERE id=?");
|
|
||||||
if ($stmt->execute([$_POST['date'], $_POST['department'], $_POST['title'], $_POST['content'], $_POST['full_text'], $final_image_path, $_POST['link'], $_POST['news_id']])) {
|
|
||||||
$message = "<div class='success'>✓ News erfolgreich aktualisiert!</div>";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- AKTION: NEWS SPEICHERN (NEU) ---
|
// --- AKTION: NEWS SPEICHERN (NEU) ---
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_news'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_news'])) {
|
||||||
$final_image_path = '';
|
$img1 = handleSingleImage(1);
|
||||||
|
$img2 = handleSingleImage(2);
|
||||||
|
$img3 = handleSingleImage(3);
|
||||||
|
$img4 = handleSingleImage(4);
|
||||||
|
$title_idx = (int)$_POST['title_index'];
|
||||||
|
|
||||||
$uploaded_img = handleImageUpload();
|
$stmt = $db->prepare("INSERT INTO news (date, department, title, content, full_text, image, image2, image3, image4, title_index, link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||||
if ($uploaded_img) {
|
if ($stmt->execute([$_POST['date'], $_POST['department'], $_POST['title'], $_POST['content'], $_POST['full_text'], $img1, $img2, $img3, $img4, $title_idx, $_POST['link']])) {
|
||||||
$final_image_path = $uploaded_img;
|
$message = "<div class='success'>✓ News (inkl. Galerie) erfolgreich veröffentlicht!</div>";
|
||||||
} elseif (isset($_POST['image_url']) && !empty($_POST['image_url'])) {
|
|
||||||
$final_image_path = str_replace(['http://new.sg07-stleon.de/', 'https://new.sg07-stleon.de/', 'new.sg07-stleon.de/', 'new.sg07-stleon.de\\'], '', trim($_POST['image_url']));
|
|
||||||
} elseif (isset($_POST['placeholder_image']) && !empty($_POST['placeholder_image'])) {
|
|
||||||
$final_image_path = $_POST['placeholder_image'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt = $db->prepare("INSERT INTO news (date, department, title, content, full_text, image, link) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
||||||
if ($stmt->execute([$_POST['date'], $_POST['department'], $_POST['title'], $_POST['content'], $_POST['full_text'], $final_image_path, $_POST['link']])) {
|
|
||||||
$message = "<div class='success'>✓ News erfolgreich veröffentlicht!</div>";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,23 +225,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_news'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- AKTION: NEUEN BENUTZER ANLEGEN ---
|
|
||||||
$new_user_qr = "";
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_user'])) {
|
|
||||||
$new_user = trim($_POST['new_username']);
|
|
||||||
$new_pass = $_POST['new_password'];
|
|
||||||
$new_secret = MiniTOTP::generateSecret();
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $db->prepare("INSERT INTO users (username, password_hash, totp_secret) VALUES (?, ?, ?)");
|
|
||||||
$stmt->execute([$new_user, password_hash($new_pass, PASSWORD_DEFAULT), $new_secret]);
|
|
||||||
$url = MiniTOTP::getQRCodeUrl($new_user, $new_secret);
|
|
||||||
$new_user_qr = "<div class='qr-box'><h3>Benutzer '$new_user' angelegt!</h3><p>Bitte lasse den neuen Benutzer <b>jetzt sofort</b> diesen QR Code scannen.</p><img src='$url' alt='QR Code'><p>Geheimer Schlüssel (falls QR nicht geht): <b>$new_secret</b></p></div>";
|
|
||||||
} catch(PDOException $e) {
|
|
||||||
$message = "<div class='error'>Fehler: Benutzername existiert evtl. schon.</div>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Edit-Modus prüfen
|
// Edit-Modus prüfen
|
||||||
$is_edit = false;
|
$is_edit = false;
|
||||||
$edit_news = null;
|
$edit_news = null;
|
||||||
@@ -251,53 +232,80 @@ if (isset($_GET['edit_id'])) {
|
|||||||
$stmt = $db->prepare("SELECT * FROM news WHERE id = ?");
|
$stmt = $db->prepare("SELECT * FROM news WHERE id = ?");
|
||||||
$stmt->execute([$_GET['edit_id']]);
|
$stmt->execute([$_GET['edit_id']]);
|
||||||
$edit_news = $stmt->fetch(PDO::FETCH_ASSOC);
|
$edit_news = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
if ($edit_news) {
|
if ($edit_news) $is_edit = true;
|
||||||
$is_edit = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alle bestehenden News abrufen für die Übersichtstabelle
|
|
||||||
$existing_news = $db->query("SELECT id, date, department, title FROM news ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
|
$existing_news = $db->query("SELECT id, date, department, title FROM news ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// HTML Block für einen der 4 Bilder-Uploads
|
||||||
|
function renderImageSlot($index, $is_edit, $edit_news) {
|
||||||
|
$img_key = $index === 1 ? 'image' : 'image'.$index;
|
||||||
|
$current_val = $is_edit ? ($edit_news[$img_key] ?? '') : '';
|
||||||
|
$title_idx = $is_edit ? (int)($edit_news['title_index'] ?? 1) : 1;
|
||||||
|
$is_title = ($title_idx === $index);
|
||||||
|
|
||||||
|
echo "<div class='img-slot'>";
|
||||||
|
echo "<h4>Bild Slot $index</h4>";
|
||||||
|
|
||||||
|
// Radio für Titelbild
|
||||||
|
echo "<label style='color: #d32f2f;'><input type='radio' name='title_index' value='$index' " . ($is_title ? 'checked' : '') . "> <b>Als Titelbild (Cover) nutzen</b></label><hr style='border:0; height:1px; background:#ddd; margin:10px 0;'>";
|
||||||
|
|
||||||
|
if($is_edit && $current_val) {
|
||||||
|
echo "<input type='hidden' name='existing_image_$index' value='".htmlspecialchars($current_val)."'>";
|
||||||
|
echo "<label><input type='checkbox' name='keep_existing_$index' checked> Altes Bild behalten: <br><small>".htmlspecialchars(substr($current_val, 0, 30))."...</small></label><br>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<label>1. Datei hochladen</label>";
|
||||||
|
echo "<input type='file' name='image_file_$index' accept='image/*' style='background: white; margin-bottom: 5px;'>";
|
||||||
|
|
||||||
|
echo "<label>2. ODER Link (URL)</label>";
|
||||||
|
echo "<input type='text' name='image_url_$index' placeholder='https://...'>";
|
||||||
|
|
||||||
|
echo "<label>3. ODER Platzhalter</label>";
|
||||||
|
echo "<select name='placeholder_image_$index' style='width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;'>";
|
||||||
|
echo "<option value=''>-- Kein Bild in diesem Slot --</option>";
|
||||||
|
echo "<option value=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23f4f4f4'/%3E%3Ccircle cx='50' cy='50' r='35' fill='%23d32f2f'/%3E%3Ctext x='50' y='57' font-size='20' fill='white' text-anchor='middle' font-weight='bold'%3ESG 07%3C/text%3E%3C/svg%3E\">Neutral (SG 07 Logo)</option>";
|
||||||
|
echo "<option value=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23e3f2fd'/%3E%3Ccircle cx='50' cy='50' r='35' fill='%232196f3'/%3E%3Ctext x='50' y='60' font-size='30' fill='white' text-anchor='middle' font-weight='bold' font-family='serif'%3Ei%3C/text%3E%3C/svg%3E\">Info (Blaues i)</option>";
|
||||||
|
echo "</select>";
|
||||||
|
echo "</div>";
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Admin Dashboard | SG 07 St. Leon</title>
|
<title>Admin Dashboard | SG 07 St. Leon</title>
|
||||||
<!-- Cropper.js für Bildzuschnitt -->
|
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.css" rel="stylesheet">
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js"></script>
|
|
||||||
<style>
|
<style>
|
||||||
body { font-family: 'Segoe UI', sans-serif; background: #f4f4f4; padding: 40px 20px; margin: 0; }
|
body { font-family: 'Segoe UI', sans-serif; background: #f4f4f4; padding: 40px 20px; margin: 0; }
|
||||||
.container { max-width: 1000px; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.05); margin: 0 auto; }
|
.container { max-width: 1200px; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.05); margin: 0 auto; }
|
||||||
.header-bar { display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #f4f4f4; padding-bottom: 20px; margin-bottom: 30px; }
|
.header-bar { display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #f4f4f4; padding-bottom: 20px; margin-bottom: 30px; }
|
||||||
.header-bar h1 { color: #d32f2f; margin: 0; }
|
.header-bar h1 { color: #d32f2f; margin: 0; }
|
||||||
.logout-btn { background: #555; color: white; padding: 8px 15px; border-radius: 4px; text-decoration: none; font-weight: bold;}
|
.logout-btn { background: #555; color: white; padding: 8px 15px; border-radius: 4px; text-decoration: none; font-weight: bold;}
|
||||||
.grid-2 { display: grid; grid-template-columns: 2fr 1fr; gap: 40px; }
|
.grid-2 { display: grid; grid-template-columns: 3fr 1fr; gap: 40px; }
|
||||||
label { font-weight: 600; display: block; margin-top: 15px; margin-bottom: 5px; color: #333;}
|
label { font-weight: 600; display: block; margin-top: 15px; margin-bottom: 5px; color: #333; font-size: 0.9rem;}
|
||||||
input[type="text"], input[type="password"], textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; font-family: inherit; }
|
input[type="text"], input[type="password"], textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; font-family: inherit; }
|
||||||
button { margin-top: 20px; padding: 15px; background: #d32f2f; color: white; border: none; font-weight: bold; border-radius: 4px; cursor: pointer; width: 100%; transition: background 0.2s; }
|
button { margin-top: 20px; padding: 15px; background: #d32f2f; color: white; border: none; font-weight: bold; border-radius: 4px; cursor: pointer; width: 100%; transition: background 0.2s; }
|
||||||
button:hover { background: #9a0007; }
|
button:hover { background: #9a0007; }
|
||||||
.success { background: #4CAF50; color: white; padding: 15px; border-radius: 4px; margin-bottom: 20px; font-weight: bold;}
|
.success { background: #4CAF50; color: white; padding: 15px; border-radius: 4px; margin-bottom: 20px; font-weight: bold;}
|
||||||
.error { background: #d32f2f; color: white; padding: 15px; border-radius: 4px; margin-bottom: 20px; font-weight: bold;}
|
|
||||||
.sidebar-box { background: #fafafa; padding: 20px; border-radius: 8px; border: 1px solid #ddd; }
|
.img-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; background: #fafafa; padding: 20px; border: 1px solid #ddd; border-radius: 8px; margin-top: 10px;}
|
||||||
.qr-box { background: #fff3cd; color: #856404; padding: 20px; border-radius: 8px; text-align: center; margin-bottom: 20px; border: 1px solid #ffeeba;}
|
.img-slot { background: white; padding: 15px; border: 1px solid #ccc; border-radius: 4px; }
|
||||||
|
.img-slot h4 { margin-top: 0; margin-bottom: 10px; color: #555; border-bottom: 2px solid #eee; padding-bottom: 5px;}
|
||||||
|
|
||||||
.news-table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 0.95rem; }
|
.news-table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 0.95rem; }
|
||||||
.news-table th { background: #f4f4f4; padding: 12px; text-align: left; border-bottom: 2px solid #ddd; color: #333; }
|
.news-table th { background: #f4f4f4; padding: 12px; text-align: left; border-bottom: 2px solid #ddd; color: #333; }
|
||||||
.news-table td { padding: 12px; border-bottom: 1px solid #eee; vertical-align: middle; }
|
.news-table td { padding: 12px; border-bottom: 1px solid #eee; vertical-align: middle; }
|
||||||
.news-table tr:hover { background: #fafafa; }
|
|
||||||
.edit-btn { background: #2196F3; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; font-size: 0.9rem; }
|
.edit-btn { background: #2196F3; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; font-size: 0.9rem; }
|
||||||
.social-btn { background: #E1306C; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; font-size: 0.9rem; margin-right: 5px; }
|
.social-btn { background: #E1306C; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; font-size: 0.9rem; margin-right: 5px; }
|
||||||
.delete-btn { background: #d32f2f; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; margin: 0; width: auto; font-size: 0.9rem; }
|
.delete-btn { background: #d32f2f; color: white; padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; margin: 0; width: auto; font-size: 0.9rem; }
|
||||||
|
|
||||||
@media(max-width: 768px) { .grid-2 { grid-template-columns: 1fr; } }
|
@media(max-width: 900px) { .grid-2 { grid-template-columns: 1fr; } }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<h1>SG 07 Dashboard</h1>
|
<h1>SG 07 Dashboard <span style="font-size: 0.5em; background: #2196F3; color: white; padding: 3px 8px; border-radius: 10px; vertical-align: middle;">MULTIMEDIA EDITION</span></h1>
|
||||||
<div>
|
<div>
|
||||||
<span style="margin-right:15px; color:#666;">Hallo, <b><?= htmlspecialchars($_SESSION['username']) ?></b></span>
|
<span style="margin-right:15px; color:#666;">Hallo, <b><?= htmlspecialchars($_SESSION['username']) ?></b></span>
|
||||||
<a href="?action=logout" class="logout-btn">Abmelden</a>
|
<a href="?action=logout" class="logout-btn">Abmelden</a>
|
||||||
@@ -305,7 +313,6 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?= $message ?>
|
<?= $message ?>
|
||||||
<?= $new_user_qr ?>
|
|
||||||
|
|
||||||
<div class="grid-2">
|
<div class="grid-2">
|
||||||
<!-- News Eintragen / Ändern -->
|
<!-- News Eintragen / Ändern -->
|
||||||
@@ -314,7 +321,6 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
|||||||
<form method="POST" id="newsForm" enctype="multipart/form-data">
|
<form method="POST" id="newsForm" enctype="multipart/form-data">
|
||||||
<?php if($is_edit): ?>
|
<?php if($is_edit): ?>
|
||||||
<input type="hidden" name="news_id" value="<?= $edit_news['id'] ?>">
|
<input type="hidden" name="news_id" value="<?= $edit_news['id'] ?>">
|
||||||
<input type="hidden" name="existing_image" value="<?= htmlspecialchars($edit_news['image']) ?>">
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<label>Datum</label>
|
<label>Datum</label>
|
||||||
@@ -328,31 +334,19 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
|||||||
<label>Kompletter Artikel (Popup)</label>
|
<label>Kompletter Artikel (Popup)</label>
|
||||||
<textarea name="full_text" rows="8" required><?= $is_edit ? htmlspecialchars($edit_news['full_text']) : '' ?></textarea>
|
<textarea name="full_text" rows="8" required><?= $is_edit ? htmlspecialchars($edit_news['full_text']) : '' ?></textarea>
|
||||||
|
|
||||||
<label>Bild hochladen & zuschneiden</label>
|
<h3 style="margin-top: 30px; margin-bottom: 5px; color: #333;">Bilder-Galerie (Maximal 4)</h3>
|
||||||
<input type="file" id="image_file_input" accept="image/*" style="background: white; margin-bottom: 10px;">
|
<p style="font-size: 0.85rem; color: #666; margin-top: 0;">Du musst nicht alle Slots füllen. Vergiss nicht das <b>Titelbild</b> auszuwählen!</p>
|
||||||
|
|
||||||
<!-- Cropper Container -->
|
<!-- Die 4 Bilder Slots -->
|
||||||
<div id="cropper_container" style="display:none; margin-bottom: 15px; max-height: 400px; overflow: hidden; border: 1px dashed #ccc;">
|
<div class="img-grid">
|
||||||
<img id="image_to_crop" src="" style="max-width: 100%; display: block;">
|
<?php
|
||||||
|
for($i=1; $i<=4; $i++) {
|
||||||
|
renderImageSlot($i, $is_edit, $edit_news);
|
||||||
|
}
|
||||||
|
?>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="cropped_image_data" id="cropped_image_data">
|
|
||||||
|
|
||||||
<?php if($is_edit && $edit_news['image']): ?>
|
<label style="margin-top: 20px;">Weiterführender Link (Optional)</label>
|
||||||
<p style="font-size: 0.85rem; color: #666; margin-top: -10px; margin-bottom: 10px;">Aktuelles Bild: <b><?= htmlspecialchars($edit_news['image']) ?></b></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<label>ODER Bild-Link (URL)</label>
|
|
||||||
<input type="text" name="image_url" placeholder="https://..." value="<?= $is_edit ? htmlspecialchars($edit_news['image']) : '' ?>">
|
|
||||||
|
|
||||||
<label>ODER Platzhalter-Bild verwenden</label>
|
|
||||||
<select name="placeholder_image" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: inherit; margin-bottom: 15px; background: white;">
|
|
||||||
<option value="">-- Kein Platzhalter (Leeres Bild) --</option>
|
|
||||||
<option value="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23f4f4f4'/%3E%3Ccircle cx='50' cy='50' r='35' fill='%23d32f2f'/%3E%3Ctext x='50' y='57' font-size='20' fill='white' text-anchor='middle' font-weight='bold'%3ESG 07%3C/text%3E%3C/svg%3E">Neutral (SG 07 Logo)</option>
|
|
||||||
<option value="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23e3f2fd'/%3E%3Ccircle cx='50' cy='50' r='35' fill='%232196f3'/%3E%3Ctext x='50' y='60' font-size='30' fill='white' text-anchor='middle' font-weight='bold' font-family='serif'%3Ei%3C/text%3E%3C/svg%3E">Info (Blaues i)</option>
|
|
||||||
<option value="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%23fff3e0'/%3E%3Cpath d='M50 20 L85 80 L15 80 Z' fill='%23ff9800'/%3E%3Ctext x='50' y='70' font-size='30' fill='white' text-anchor='middle' font-weight='bold'%3E!%3C/text%3E%3C/svg%3E">Wichtig (Warnung)</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label>Weiterführender Link (Optional)</label>
|
|
||||||
<input type="text" name="link" value="<?= $is_edit ? htmlspecialchars($edit_news['link']) : '' ?>">
|
<input type="text" name="link" value="<?= $is_edit ? htmlspecialchars($edit_news['link']) : '' ?>">
|
||||||
|
|
||||||
<?php if($is_edit): ?>
|
<?php if($is_edit): ?>
|
||||||
@@ -366,23 +360,20 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Benutzerverwaltung -->
|
<!-- Randbereich Info -->
|
||||||
<div>
|
<div>
|
||||||
<div class="sidebar-box">
|
<div style="background: #fafafa; padding: 20px; border-radius: 8px; border: 1px solid #ddd;">
|
||||||
<h2 style="color: #333; margin-top: 0;">Neuen Admin anlegen</h2>
|
<h2 style="color: #333; margin-top: 0;">Tipps zur Galerie</h2>
|
||||||
<p style="font-size: 0.9rem; color: #666;">Lege einen Kollegen an. Ein QR-Code für dessen 2FA-App wird direkt danach <b>einmalig</b> angezeigt.</p>
|
<p style="font-size: 0.9rem; color: #666;">
|
||||||
<form method="POST">
|
Das <b>Titelbild</b> wird immer auf der Startseite in der kleinen Karte angezeigt.<br><br>
|
||||||
<label>Benutzername</label>
|
Wenn jemand auf "Weiterlesen" klickt, werden <b>alle</b> Bilder, die du hier hinterlegst, im Artikel angezeigt.<br><br>
|
||||||
<input type="text" name="new_username" required>
|
<b>Tipp:</b> Bilder werden nun automatisch vom System im perfekten Format zugeschnitten (CSS object-fit). Du sparst dir das nervige manuelle Zurechtschneiden!
|
||||||
<label>Passwort</label>
|
</p>
|
||||||
<input type="password" name="new_password" required>
|
|
||||||
<button type="submit" name="add_user" style="background: #333; padding: 10px;">Admin hinzufügen</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- News Liste zum Löschen / Posten / Ändern -->
|
<!-- News Liste -->
|
||||||
<div style="margin-top: 50px; border-top: 2px solid #eee; padding-top: 30px;">
|
<div style="margin-top: 50px; border-top: 2px solid #eee; padding-top: 30px;">
|
||||||
<h2 style="color: #333; margin-bottom: 10px;">Bestehende News verwalten</h2>
|
<h2 style="color: #333; margin-bottom: 10px;">Bestehende News verwalten</h2>
|
||||||
|
|
||||||
@@ -401,67 +392,29 @@ $existing_news = $db->query("SELECT id, date, department, title FROM news ORDER
|
|||||||
<td style="text-align: right; display: flex; justify-content: flex-end; gap: 5px;">
|
<td style="text-align: right; display: flex; justify-content: flex-end; gap: 5px;">
|
||||||
<button type="button" class="social-btn" onclick="copySocialMediaText('<?= htmlspecialchars(addslashes($news_item['title'])) ?>', '<?= htmlspecialchars(addslashes($news_item['department'])) ?>')">📲 Posten</button>
|
<button type="button" class="social-btn" onclick="copySocialMediaText('<?= htmlspecialchars(addslashes($news_item['title'])) ?>', '<?= htmlspecialchars(addslashes($news_item['department'])) ?>')">📲 Posten</button>
|
||||||
<a href="?edit_id=<?= $news_item['id'] ?>" class="edit-btn">Ändern</a>
|
<a href="?edit_id=<?= $news_item['id'] ?>" class="edit-btn">Ändern</a>
|
||||||
<form method="POST" style="margin: 0;" onsubmit="return confirm('Möchtest du diese News wirklich unwiderruflich löschen?');">
|
<form method="POST" style="margin: 0;" onsubmit="return confirm('Möchtest du diese News wirklich löschen?');">
|
||||||
<input type="hidden" name="delete_id" value="<?= $news_item['id'] ?>">
|
<input type="hidden" name="delete_id" value="<?= $news_item['id'] ?>">
|
||||||
<button type="submit" name="delete_news" class="delete-btn">Löschen</button>
|
<button type="submit" name="delete_news" class="delete-btn">Löschen</button>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php if(empty($existing_news)): ?>
|
|
||||||
<tr>
|
|
||||||
<td colspan="4" style="text-align: center; padding: 20px; color: #888;">Noch keine News vorhanden.</td>
|
|
||||||
</tr>
|
|
||||||
<?php endif; ?>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Javascript für Crop und Social Media -->
|
<!-- Javascript -->
|
||||||
<script>
|
<script>
|
||||||
// CROPPER LOGIK
|
|
||||||
let cropper;
|
|
||||||
document.getElementById('image_file_input').addEventListener('change', function(e) {
|
|
||||||
const file = e.target.files[0];
|
|
||||||
if (file) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = function(event) {
|
|
||||||
document.getElementById('image_to_crop').src = event.target.result;
|
|
||||||
document.getElementById('cropper_container').style.display = 'block';
|
|
||||||
|
|
||||||
if (cropper) cropper.destroy();
|
|
||||||
cropper = new Cropper(document.getElementById('image_to_crop'), {
|
|
||||||
aspectRatio: 4 / 3,
|
|
||||||
viewMode: 1,
|
|
||||||
autoCropArea: 1
|
|
||||||
});
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('newsForm').addEventListener('submit', function(e) {
|
|
||||||
if (cropper) {
|
|
||||||
const canvas = cropper.getCroppedCanvas({ width: 800, height: 600 });
|
|
||||||
if(canvas) {
|
|
||||||
document.getElementById('cropped_image_data').value = canvas.toDataURL('image/jpeg', 0.85);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// SOCIAL MEDIA EXPORT LOGIK
|
|
||||||
function copySocialMediaText(title, department) {
|
function copySocialMediaText(title, department) {
|
||||||
const cleanDept = department.replace(/\s+/g, '');
|
const cleanDept = department.replace(/\s+/g, '');
|
||||||
const text = `🚨 NEUE NEWS VON DER SG 07 🚨\n\n📢 ${title}\n\nLies jetzt den ganzen Bericht auf unserer Website!\n👉 sg07-stleon.de\n\n#SG07StLeon #Vereinsliebe #${cleanDept} #StLeonRot`;
|
const text = `🚨 NEUE NEWS VON DER SG 07 🚨\n\n📢 ${title}\n\nLies jetzt den ganzen Bericht auf unserer Website!\n👉 sg07-stleon.de\n\n#SG07StLeon #Vereinsliebe #${cleanDept} #StLeonRot`;
|
||||||
|
|
||||||
const tempInput = document.createElement("textarea");
|
const tempInput = document.createElement("textarea");
|
||||||
tempInput.value = text;
|
tempInput.value = text;
|
||||||
document.body.appendChild(tempInput);
|
document.body.appendChild(tempInput);
|
||||||
tempInput.select();
|
tempInput.select();
|
||||||
document.execCommand("copy");
|
document.execCommand("copy");
|
||||||
document.body.removeChild(tempInput);
|
document.body.removeChild(tempInput);
|
||||||
|
alert("✅ Der Text für Instagram & Facebook wurde kopiert!");
|
||||||
alert("✅ Der Text für Instagram & Facebook wurde in deine Zwischenablage kopiert!\n\nDu kannst jetzt einfach rüber zu Insta gehen, dein Bild einfügen und beim Text auf 'Einsetzen' drücken.");
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user