Re: Gästebuch Block
Verfasst: Di 9. Jun 2026, 16:40
Ja - auf jeden Fall, ich verweise als Download auf Deine Seite:
https://www.mobirise-tutorials.com/AI-B ... tbuch.html
https://www.mobirise-tutorials.com/AI-B ... tbuch.html
Forum für Mobirise und NOF
https://www.mobirise-tutorials.com/Forum/
https://www.mobirise-tutorials.com/Forum/viewtopic.php?t=2127
Code: Alles auswählen
<script>
(function() {
var inBuilder = (typeof MbrsiteApp !== 'undefined') || (window.self !== window.top && /mobirise/i.test(document.referrer));
if (inBuilder) return;
var apiPath = 'guestbook-api.php';
var feedContainer = document.getElementById('js-guestbook-feed');
var paginationContainer = document.getElementById('js-gb-pagination');
var form = document.getElementById('js-guestbook-form');
var statusDiv = document.getElementById('gb-status');
var msgField = document.getElementById('gb-message');
var currentSection = document.getElementById('js-guestbook-feed') ? document.getElementById('js-guestbook-feed').closest('section') : null;
var allEntries = [];
var currentPage = 1;
var itemsPerPage = parseInt('{{perPage}}') || 5;
var isAdmin = false;
var enteredPassword = '';
if (currentSection) {
var titleEl = currentSection.querySelector('.js-gb-main-title');
if (titleEl) {
titleEl.addEventListener('dblclick', function(e) {
e.preventDefault();
var pwCheck = prompt('Bitte Admin-Passwort eingeben:');
if (pwCheck !== null && pwCheck.trim() !== '') {
fetch(apiPath, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'checkLogin', password: pwCheck.trim() })
})
.then(response => response.json())
.then(data => {
if (data.success) {
isAdmin = true;
enteredPassword = pwCheck.trim();
alert('Login erfolgreich! Ungeprüfte Beiträge zeigen jetzt das Freischaltfeld. 🔓');
loadEntries();
} else {
alert(data.error);
}
});
}
});
}
// 🔥 FIX: Hier ist das Bindungs-Skript für deine Emoji-Bar!
var emojiButtons = currentSection.querySelectorAll('.emoji-bar .emoji-btn');
emojiButtons.forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.preventDefault();
var chosenEmoji = btn.textContent.replace('Anzeigen', '').trim(); // Bereinigt eventuelle Rückstände
if (msgField) {
var start = msgField.selectionStart;
var end = msgField.selectionEnd;
var text = msgField.value;
msgField.value = text.substring(0, start) + chosenEmoji + text.substring(end);
msgField.focus();
msgField.selectionStart = msgField.selectionEnd = start + chosenEmoji.length;
}
});
});
}
function renderFeed() {
if (!feedContainer) return;
if (!allEntries || allEntries.length === 0) {
feedContainer.innerHTML = '<div class="text-center py-4 text-fallback">Noch keine freigeschalteten Einträge vorhanden.</div>';
if (paginationContainer) paginationContainer.innerHTML = '';
return;
}
var startIndex = (currentPage - 1) * itemsPerPage;
var endIndex = startIndex + itemsPerPage;
var pageEntries = allEntries.slice(startIndex, endIndex);
var html = '';
pageEntries.forEach(function(entry) {
var date = new Date(entry.created_at.replace(/-/g, "/"));
var formattedDate = date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }) + ' - ' + date.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }) + ' Uhr';
var styleOverride = (entry.status == 0) ? 'style="border: 1px solid #eab308 !important; background: rgba(234, 179, 8, 0.08) !important;"' : '';
var titleAddon = (entry.status == 0) ? ' <span style="color:#eab308;font-size:0.75rem;">(Wartet auf Freischaltung)</span>' : '';
html += '<div class="guestbook-entry-card mb-3 glass-card" data-id="' + entry.id + '" ' + styleOverride + '>';
html += ' <div class="entry-header">';
html += ' <strong class="entry-author">' + entry.name + titleAddon + '</strong>';
html += ' <div class="d-flex align-items-center gap-3">';
html += ' <span class="entry-date">' + formattedDate + '</span>';
if (isAdmin) {
html += ' <button class="btn-edit-entry" title="Eintrag bearbeiten" style="background:none; border:none; cursor:pointer; font-size:1.1rem; padding:0; line-height:1;">✏️</button>';
html += ' <button class="btn-delete-entry" title="Eintrag löschen" style="background:none; border:none; cursor:pointer; font-size:1.1rem; padding:0; line-height:1;">🗑️</button>';
}
html += ' </div>';
html += ' </div>';
html += ' <p class="entry-text js-entry-text-target">' + entry.message.replace(/\n/g, '<br>') + '</p>';
if (isAdmin && entry.status == 0) {
html += ' <div class="mt-3 text-end js-approve-wrapper">';
html += ' <button class="btn btn-sm btn-success btn-approve-action" style="padding: 6px 14px; font-size: 0.85rem; font-weight: bold; border-radius: 6px; border: none; background-color: #22c55e !important; color: #fff !important;">';
html += ' ✅ Eintrag freischalten';
html += ' </button>';
html += ' </div>';
}
html += '</div>';
});
feedContainer.innerHTML = html;
if (isAdmin) {
feedContainer.querySelectorAll('.btn-approve-action').forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.stopPropagation();
var card = btn.closest('.guestbook-entry-card');
var id = card.getAttribute('data-id');
approveEntry(id, card);
});
});
feedContainer.querySelectorAll('.btn-delete-entry').forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.stopPropagation();
var card = btn.closest('.guestbook-entry-card');
var id = card.getAttribute('data-id');
if (confirm('Möchtest du diesen Eintrag wirklich unwiderruflich löschen?')) {
deleteEntry(id, card);
}
});
});
feedContainer.querySelectorAll('.btn-edit-entry').forEach(function(btn) {
btn.addEventListener('click', function(e) {
e.stopPropagation();
var card = btn.closest('.guestbook-entry-card');
var id = card.getAttribute('data-id');
var textP = card.querySelector('.js-entry-text-target');
if (card.classList.contains('is-editing')) return;
card.classList.add('is-editing');
var origEntry = allEntries.find(item => item.id == id);
var currentRawText = origEntry ? origEntry.message : textP.innerText;
textP.innerHTML = '<textarea class="form-control mb-2 js-edit-textarea" rows="4" style="color:#000 !important; background:#fff !important;">' + currentRawText + '</textarea>' +
'<button class="btn btn-sm btn-success js-save-edit-btn" style="padding:4px 10px; font-size:0.8rem;">💾 Speichern</button> ' +
'<button class="btn btn-sm btn-danger js-cancel-edit-btn" style="padding:4px 10px; font-size:0.8rem;">Abbrechen</button>';
card.querySelector('.js-save-edit-btn').addEventListener('click', function() {
var newText = card.querySelector('.js-edit-textarea').value;
updateEntryText(id, newText, card);
});
card.querySelector('.js-cancel-edit-btn').addEventListener('click', function() {
renderFeed();
});
});
});
}
renderPaginationControls();
}
function approveEntry(id, card) {
fetch(apiPath, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'approve', id: id, password: enteredPassword })
})
.then(response => response.json())
.then(data => {
if (data.success) {
var entry = allEntries.find(item => item.id == id);
if (entry) entry.status = 1;
renderFeed();
} else {
alert(data.error);
}
})
.catch(err => alert('Fehler bei der Freischaltung.'));
}
function updateEntryText(id, newText, card) {
fetch(apiPath, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'update', id: id, message: newText, password: enteredPassword })
})
.then(response => response.json())
.then(data => {
if (data.success) {
var entry = allEntries.find(item => item.id == id);
if (entry) entry.message = newText;
renderFeed();
} else {
alert(data.error);
}
})
.catch(err => alert('Fehler beim Speichern.'));
}
function renderPaginationControls() {
if (!paginationContainer) return;
var totalPages = Math.ceil(allEntries.length / itemsPerPage);
if (totalPages <= 1) {
paginationContainer.innerHTML = '';
return;
}
var html = '';
html += '<button class="pag-btn" data-page="' + (currentPage - 1) + '"' + (currentPage === 1 ? ' disabled' : '') + '>«</button>';
for (var i = 1; i <= totalPages; i++) {
html += '<button class="pag-btn' + (i === currentPage ? ' active' : '') + '" data-page="' + i + '">' + i + '</button>';
}
html += '<button class="pag-btn" data-page="' + (currentPage + 1) + '"' + (currentPage === totalPages ? ' disabled' : '') + '>»</button>';
paginationContainer.innerHTML = html;
paginationContainer.querySelectorAll('.pag-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var targetPage = parseInt(btn.getAttribute('data-page'));
if (targetPage >= 1 && targetPage <= totalPages) {
currentPage = targetPage;
renderFeed();
feedContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
});
});
}
function loadEntries() {
var url = apiPath + (isAdmin ? '?adminCheck=' + encodeURIComponent(enteredPassword) : '');
fetch(url)
.then(response => response.json())
.then(data => {
if (!data.success) {
feedContainer.innerHTML = '<div class="alert alert-danger">' + data.error + '</div>';
return;
}
allEntries = data.entries || [];
renderFeed();
})
.catch(err => {
if(feedContainer) {
feedContainer.innerHTML = '<div class="text-center py-4 text-fallback">Warte auf ersten Eintrag...</div>';
}
});
}
function deleteEntry(id, card) {
fetch(apiPath, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'delete', id: id, password: enteredPassword })
})
.then(response => response.json())
.then(data => {
if (data.success) {
card.style.transition = 'all 0.3s ease';
card.style.opacity = '0';
card.style.transform = 'scale(0.9)';
setTimeout(function() {
allEntries = allEntries.filter(entry => entry.id != id);
var totalPages = Math.ceil(allEntries.length / itemsPerPage);
if (currentPage > totalPages && currentPage > 1) {
currentPage = totalPages;
}
renderFeed();
}, 300);
} else {
alert(data.error);
}
});
}
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
var nameVal = document.getElementById('gb-name').value;
var msgVal = msgField.value;
statusDiv.style.display = 'block';
statusDiv.className = 'mt-3 small text-fallback';
statusDiv.textContent = 'Eintrag wird zur Prüfung gesendet... ⏳';
fetch(apiPath, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: nameVal, message: msgVal })
})
.then(response => response.json())
.then(data => {
if (data.success) {
statusDiv.textContent = 'Vielen Dank! Dein Eintrag wird geprüft und bald freigeschaltet. 🎉';
form.reset();
currentPage = 1;
loadEntries();
setTimeout(function() { statusDiv.style.display = 'none'; }, 5000);
} else {
statusDiv.textContent = data.error;
}
})
.catch(err => {
statusDiv.textContent = 'Fehler beim Senden.';
});
});
}
loadEntries();
})();
</script>Code: Alles auswählen
// 🔒 1. DEIN ADMIN-PASSWORT FÜR BROWSER-LOGIN (DOPPELKLICK)
$apiPassword = 'DeinSicheresPasswort';
// 📧 2. SMTP & MAIL EMPFÄNGER CONFIGURATION
$adminEmail = 'mail@DeineDomain.de';
$websiteUrl = 'https://www.DeineDomain.de/eventuelles-Projekt-Verzeichnis/'; // Wichtig für den Freischaltlink!
// 📧 SMTP KONFIGURATION - Leer lassen, wenn du normales PHP-Mail nutzen willst!
// oder jede Zeile mit zwei // deaktivieren, wenn normales PHP-Mail verwendet wird.
define('SMTP_HOST', 'smtp.ionos.de'); // z.B. smtp.ionos.de
define('SMTP_PORT', 465); // 465 (SSL) oder 587 (TLS)
define('SMTP_CRYPT', 'ssl'); // 'ssl', 'tls' oder ''
define('SMTP_USER', 'mail@DeineDomain.de'); // Deine SMTP-Mailadresse
define('SMTP_PASS', '**SMTP-Passwort**'); // Dein echtes Mail-Passwort (leer lassen für PHP-Mail)