(function ($) { 'use strict'; /* ── Utilities ──────────────────────────────────────────────── */ function wbfPost(action, data, cb, errCb) { data.action = action; data.nonce = WBF.nonce; $.post(WBF.ajax_url, data, function (res) { if (res && res.success) cb(res.data); else if (errCb) errCb(res ? res.data : {message: 'Server-Fehler'}); }, 'json').fail(function(xhr) { if (errCb) errCb({message: 'Verbindungsfehler (' + xhr.status + ')'}); }); } function showMsg($el, msg, ok) { $el.text(msg).css('color', ok ? '#56cf7e' : '#f05252').show(); setTimeout(function () { $el.fadeOut(); }, 4000); } /* ── Auth Tabs ──────────────────────────────────────────────── */ $(document).on('click', '.wbf-auth-tab', function () { var tab = $(this).data('tab'); $('.wbf-auth-tab').removeClass('active'); $(this).addClass('active'); $('.wbf-auth-panel').removeClass('active'); $('[data-panel="' + tab + '"]').addClass('active'); }); /* ── Auth Modal öffnen ──────────────────────────────────────── */ $(document).on('click', '#wbfOpenLogin, .wbf-login-link', function (e) { e.preventDefault(); $('[data-tab="login"]').trigger('click'); $('#wbfAuthModal').addClass('active'); }); $(document).on('click', '#wbfOpenRegister, .wbf-register-link', function (e) { e.preventDefault(); $('[data-tab="register"]').trigger('click'); $('#wbfAuthModal').addClass('active'); }); /* ── Modal schließen bei Klick außerhalb ────────────────────── */ $(document).on('click', '.wbf-modal', function (e) { if ($(e.target).hasClass('wbf-modal')) $(this).removeClass('active'); }); /* ── Login ──────────────────────────────────────────────────── */ $(document).on('keydown', '.wbf-field-password', function (e) { if (e.key === 'Enter') $(this).closest('.wbf-auth-box').find('.wbf-login-submit-btn').trigger('click'); }); /* ── Registrieren ───────────────────────────────────────────── */ $(document).on('click', '.wbf-reg-submit-btn', function () { var $btn = $(this).prop('disabled', true).html(''); wbfPost('wbf_register', { username: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-user').val(), display_name: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-name').val(), email: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-email').val(), password: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-pass').val(), invite_code: $(this).closest('.wbf-auth-box').find('.wbf-field-invite-code').val().toUpperCase().trim(), rules_accepted: $(this).closest('.wbf-auth-box').find('.wbf-field-rules-accept').is(':checked') ? '1' : '' }, function () { location.reload(); }, function (d) { showMsg($btn.closest('.wbf-auth-box').find('.wbf-reg-msg'), d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Konto erstellen'); }); }); /* ── Logout — direkt via Link (?wbf_do_logout=1) ───────────── */ // Kein JS nötig — Logout-Button ist jetzt ein Link /* ── Neuer Thread Modal ─────────────────────────────────────── */ window.wbfShowNewThread = function (catId) { if (WBF.logged_in !== 'yes') { $('#wbfAuthModal').addClass('active'); return; } if (catId) $('#wbfThreadCat').val(catId); // Thread mode: alle Felder sichtbar $('#wbfModalTitle').html(' Neuen Thread erstellen'); $('#wbfThreadTitle').attr('placeholder', 'Titel deines Threads'); $('#wbfContentRow, #wbfTagsRow').show(); $('#wbfPollSection').hide(); $('#wbfThreadSubmitRow').show(); $('#wbfNewThreadModal').addClass('active'); }; window.wbfShowNewPoll = function (catId) { if (WBF.logged_in !== 'yes') { $('#wbfAuthModal').addClass('active'); return; } if (catId) $('#wbfThreadCat').val(catId); // Poll mode: Inhalt + Tags ausblenden $('#wbfModalTitle').html(' Neue Umfrage erstellen'); $('#wbfThreadTitle').attr('placeholder', 'Titel der Umfrage'); $('#wbfContentRow, #wbfTagsRow').hide(); $('#wbfThreadSubmitRow').hide(); $('#wbfPollSection').show(); $('#wbfNewThreadModal').addClass('active'); setTimeout(function() { $('#wbfPollSection')[0].scrollIntoView({behavior:'smooth', block:'nearest'}); }, 150); }; // Show poll section → Inhalt+Tags ausblenden $(document).on('click', '#wbfShowPollSection', function () { $('#wbfModalTitle').html(' Neue Umfrage erstellen'); $('#wbfThreadTitle').attr('placeholder', 'Titel der Umfrage'); $('#wbfContentRow, #wbfTagsRow').hide(); $('#wbfThreadSubmitRow').hide(); $('#wbfPollSection').show(); }); // Entfernen → zurück zu Thread-Modus $(document).on('click', '#wbfRemovePollSection', function () { $('#wbfModalTitle').html(' Neuen Thread erstellen'); $('#wbfThreadTitle').attr('placeholder', 'Titel deines Threads'); $('#wbfContentRow, #wbfTagsRow').show(); $('#wbfPollSection').hide(); $('#wbfThreadSubmitRow').show(); // Poll-Felder zurücksetzen $('#wbfNewThreadPollQuestion').val(''); $('#wbfNTPollEndsAt').val(''); $('#wbfNTPollMulti').prop('checked', false); $('#wbfNewThreadPollOptions .wbf-poll-opt-row').slice(2).remove(); $('#wbfNewThreadPollOptions .wbf-nt-poll-opt').val(''); }); // Poll option add/remove for new-thread poll window.wbfRemoveNTPollOpt = function(btn) { var $rows = $('#wbfNewThreadPollOptions .wbf-poll-opt-row'); if ($rows.length <= 2) return; $(btn).closest('.wbf-poll-opt-row').remove(); }; $(document).on('click', '#wbfNTPollAddOpt', function () { var count = $('#wbfNewThreadPollOptions .wbf-poll-opt-row').length; if (count >= 10) return; var n = count + 1; $('#wbfNewThreadPollOptions').append( '
' + '' + '
' ); }); $(document).on('click', '#wbfSubmitThread', function () { var $btn = $(this).prop('disabled', true).html(''); var data = { category_id: $('#wbfThreadCat').val(), prefix_id: $('#wbfThreadPrefix').val() || '', title: $('#wbfThreadTitle').val(), content: $('#wbfThreadContent').val(), tags: $('#wbfThreadTags').val() }; wbfPost('wbf_new_thread', data, function (d) { var base = WBF.forum_url || window.location.href.split('?')[0]; var sep = base.indexOf('?') !== -1 ? '&' : '?'; window.location.href = base + sep + 'forum_thread=' + d.thread_id; }, function (d) { showMsg($('#wbfThreadMsg'), d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Thread erstellen'); }); }); /* ── Umfrage erstellen (eigener Submit-Button) ──────────────────────── */ $(document).on('click', '#wbfSubmitPollThread', function () { var $btn = $(this).prop('disabled', true).html(''); var $msg = $('#wbfPollThreadMsg'); var data = { category_id: $('#wbfThreadCat').val(), prefix_id: $('#wbfThreadPrefix').val() || '', title: $('#wbfThreadTitle').val(), content: $('#wbfThreadContent').val(), tags: $('#wbfThreadTags').val(), poll_question: $('#wbfNewThreadPollQuestion').val().trim(), poll_multi: $('#wbfNTPollMulti').is(':checked') ? '1' : '', poll_ends_at: $('#wbfNTPollEndsAt').val() }; var optIdx = 0; $('#wbfNewThreadPollOptions .wbf-nt-poll-opt').each(function () { var v = $(this).val().trim(); if (v) { data['poll_options[' + optIdx + ']'] = v; optIdx++; } }); if (!data.poll_question) { showMsg($msg, 'Bitte gib eine Umfrage-Frage ein.', false); $btn.prop('disabled', false).html(' Umfrage erstellen'); return; } if (optIdx < 2) { showMsg($msg, 'Mindestens 2 Antwortmöglichkeiten erforderlich.', false); $btn.prop('disabled', false).html(' Umfrage erstellen'); return; } wbfPost('wbf_new_thread', data, function (d) { var base = WBF.forum_url || window.location.href.split('?')[0]; var sep = base.indexOf('?') !== -1 ? '&' : '?'; window.location.href = base + sep + 'forum_thread=' + d.thread_id; }, function (d) { showMsg($msg, d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Umfrage erstellen'); }); }); /* ── Poll Option hinzufügen / entfernen ─────────────────────────── */ window.wbfRemovePollOpt = function(btn) { var $rows = $('#wbfPollOptions .wbf-poll-opt-row'); if ($rows.length <= 2) return; // min. 2 bleiben $(btn).closest('.wbf-poll-opt-row').remove(); }; $(document).on('click', '#wbfPollAddOpt', function () { var count = $('#wbfPollOptions .wbf-poll-opt-row').length; if (count >= 10) return; var n = count + 1; $('#wbfPollOptions').append( '
' + '' + '
' ); }); /* ── Poll erstellen (separates Modal) ───────────────────────────── */ $(document).on('click', '#wbfSubmitPoll', function () { var $btn = $(this).prop('disabled', true).html(''); var $msg = $('#wbfPollMsg'); var opts = []; $('.wbf-poll-opt').each(function () { var v = $(this).val().trim(); if (v) opts.push(v); }); var data = { thread_id: $('#wbfPollThreadId').val(), poll_question: $('#wbfPollQuestion').val(), poll_multi: $('#wbfPollMulti').is(':checked') ? '1' : '', poll_ends_at: $('#wbfPollEndsAt').val() }; $.each(opts, function (i, v) { data['poll_options[' + i + ']'] = v; }); wbfPost('wbf_create_poll', data, function (d) { showMsg($msg, d.message, true); setTimeout(function () { location.reload(); }, 1200); }, function (d) { showMsg($msg, d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Umfrage erstellen'); }); }); /* ── Poll Abstimmen ─────────────────────────────────────────────── */ $(document).on('submit', '.wbf-poll__form', function (e) { e.preventDefault(); var $form = $(this); var pollId = $form.data('poll-id'); var multi = $form.closest('.wbf-poll').data('multi'); var $btn = $form.find('button[type="submit"]').prop('disabled', true).html(''); var $msg = $form.find('.wbf-poll__msg'); var selected = []; if (multi) { $form.find('input[type="checkbox"]:checked').each(function () { selected.push($(this).val()); }); } else { var val = $form.find('input[type="radio"]:checked').val(); if (val !== undefined) selected.push(val); } if (!selected.length) { showMsg($msg, 'Bitte eine Option wählen.', false); $btn.prop('disabled', false).html(' Abstimmen'); return; } var postData = { poll_id: pollId }; $.each(selected, function (i, v) { postData['options[' + i + ']'] = v; }); wbfPost('wbf_vote_poll', postData, function (d) { // Formular durch Ergebnisse ersetzen var html = wbfRenderPollResults(d.results, d.my_votes, d.total, $form.closest('.wbf-poll').find('.wbf-poll__header')); $form.replaceWith(html); }, function (d) { showMsg($msg, d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Abstimmen'); }); }); function wbfRenderPollResults(results, myVotes, total, $header) { var options = []; $header.closest('.wbf-poll').find('.wbf-poll__form label').each(function () { options.push($(this).text().trim()); }); var html = ''; $.each(options, function (i, label) { var votes = results[i] || 0; var pct = total > 0 ? Math.round(votes / total * 100) : 0; var mine = myVotes.indexOf(i) !== -1 || myVotes.indexOf('' + i) !== -1; html += '
' + '
' + '
' + '' + (mine ? ' ' : '') + label + '' + '' + pct + '% (' + votes + ')' + '
'; }); html += ''; return html; } /* ══════════════════════════════════════════════════════════ FEATURE: Tag-Input Widget ══════════════════════════════════════════════════════════ */ var wbfTagList = []; // aktuell ausgewählte Tags var wbfTagTimer = null; function wbfUpdateTagHidden() { $('#wbfThreadTags').val(wbfTagList.join(', ')); } function wbfAddTag(name) { name = name.replace(/^#+/, '').trim().toLowerCase(); if (!name || name.length < 2 || name.length > 30) return; if (wbfTagList.length >= 10) { return; } if (wbfTagList.indexOf(name) !== -1) return; wbfTagList.push(name); wbfUpdateTagHidden(); wbfRenderTagPills(); $('#wbfTagInput').val(''); $('#wbfTagSuggest').hide().empty(); } function wbfRemoveTag(name) { wbfTagList = wbfTagList.filter(function(t){ return t !== name; }); wbfUpdateTagHidden(); wbfRenderTagPills(); } function wbfRenderTagPills() { var $pills = $('#wbfTagPills'); $pills.empty(); wbfTagList.forEach(function(tag) { $pills.append( $('') .text('#' + tag) .append($('').on('click', function(){ wbfRemoveTag(tag); })) ); }); // Show/hide count hint var remaining = 10 - wbfTagList.length; if (remaining <= 3 && remaining > 0) { $pills.append('' + remaining + ' übrig'); } } // Keydown on tag input $(document).on('keydown', '#wbfTagInput', function(e) { var val = $(this).val().trim(); if (e.key === 'Enter' || e.key === ',' || e.key === ' ') { e.preventDefault(); if (val) wbfAddTag(val); } else if (e.key === 'Backspace' && !val && wbfTagList.length) { wbfRemoveTag(wbfTagList[wbfTagList.length - 1]); } }); // Autocomplete on input $(document).on('input', '#wbfTagInput', function() { var q = $(this).val().replace(/^#+/, '').trim(); clearTimeout(wbfTagTimer); if (q.length < 1) { $('#wbfTagSuggest').hide().empty(); return; } wbfTagTimer = setTimeout(function() { wbfPost('wbf_tag_suggest', { q: q }, function(d) { var $s = $('#wbfTagSuggest'); if (!d.tags || !d.tags.length) { $s.hide().empty(); return; } $s.empty(); d.tags.forEach(function(tag) { if (wbfTagList.indexOf(tag.slug) !== -1) return; $s.append( $('
') .html('' + $('').text(tag.name).html() + '' + tag.use_count + '') .on('click', function(){ wbfAddTag(tag.name); }) ); }); $s.show(); }); }, 200); }); // Click on tag input wrap focuses input $(document).on('click', '#wbfTagInputWrap', function(e) { if (!$(e.target).is('button')) $('#wbfTagInput').focus(); }); // Reset tags when modal closes $(document).on('click', '#wbfNewThreadModal .wbf-modal__close, #wbfNewThreadModal', function(e) { if ($(e.target).hasClass('wbf-modal') || $(e.target).hasClass('wbf-modal__close')) { wbfTagList = []; wbfRenderTagPills(); $('#wbfTagInput').val(''); $('#wbfTagSuggest').hide(); } }); // Hide suggest on outside click $(document).on('click', function(e) { if (!$(e.target).closest('#wbfTagInputWrap').length) { $('#wbfTagSuggest').hide(); } }); /* ── Antwort senden ─────────────────────────────────────────── */ $(document).on('input', '#wbfReplyContent', function () { $('#wbfReplyCounter').text($(this).val().length + ' Zeichen'); }); $(document).on('click', '#wbfSubmitReply', function () { var $btn = $(this).prop('disabled', true).html(''); var threadId = $(this).data('thread'); wbfPost('wbf_new_post', { thread_id: threadId, content: $('#wbfReplyContent').val() }, function (d) { $('#wbfPosts').append(d.html); $('#wbfReplyContent').val(''); $('#wbfReplyCounter').text('0 Zeichen'); $btn.prop('disabled', false).html(' Antwort senden'); $('html, body').animate({ scrollTop: $('#post-' + d.post_id).offset().top - 80 }, 400); $(document).trigger('wbf:post_added', [d.post_id]); }, function (d) { alert(d.message || 'Fehler beim Senden.'); $btn.prop('disabled', false).html(' Antwort senden'); }); }); /* ── Like ───────────────────────────────────────────────────── */ $(document).on('click', '.wbf-like-btn', function () { if (WBF.logged_in !== 'yes') { $('#wbfAuthModal').addClass('active'); return; } var $btn = $(this); wbfPost('wbf_toggle_like', { object_id: $btn.data('id'), object_type: $btn.data('type') }, function (d) { $btn.find('.wbf-like-count').text(d.count); $btn.toggleClass('wbf-liked', d.action === 'liked'); }); }); /* ── Mod-Aktionen ───────────────────────────────────────────── */ $(document).on('click', '.wbf-mod-btn', function () { var action = $(this).data('action'); var id = $(this).data('id'); var $btn = $(this); // Move modal — open inline, no AJAX yet if (action === 'open_move') { $('#wbfMoveThreadId').val(id); $('#wbfMoveMsg').hide(); $('#wbfMoveModal').addClass('active'); return; } var confirmMsgs = { 'delete_thread': 'Thread wirklich löschen? Alle Antworten werden entfernt.', 'delete_post': 'Post wirklich löschen?', 'archive_thread': 'Thread archivieren? Er wird aus der Kategorie ausgeblendet.' }; if (confirmMsgs[action] && !confirm(confirmMsgs[action])) return; $btn.prop('disabled', true).css('opacity', '.5'); wbfPost('wbf_mod_action', { mod_action: action, object_id: id }, function (d) { if (d.action === 'deleted') { window.location.href = window.location.pathname; } else if (d.action === 'archived') { // Redirect back — page.reload keeps the archived thread visible until refresh history.back(); } else if (d.action === 'post_deleted') { $('#post-' + id).fadeOut(300, function () { $(this).remove(); }); } else { location.reload(); } }, function (d) { alert(d.message || 'Aktion fehlgeschlagen.'); $btn.prop('disabled', false).css('opacity', '1'); }); }); /* ── Thread verschieben ─────────────────────────────────────── */ $(document).on('click', '#wbfSubmitMove', function () { var $btn = $(this).prop('disabled', true).html(''); var threadId = $('#wbfMoveThreadId').val(); var catId = $('#wbfMoveCatSelect').val(); wbfPost('wbf_move_thread', { thread_id: threadId, category_id: catId }, function (d) { showMsg($('#wbfMoveMsg'), '✔ ' + (d.message || 'Verschoben!'), true); $btn.prop('disabled', false).html(' Verschieben'); setTimeout(function () { $('#wbfMoveModal').removeClass('active'); location.reload(); }, 1200); }, function (d) { showMsg($('#wbfMoveMsg'), d.message || 'Fehler.', false); $btn.prop('disabled', false).html(' Verschieben'); }); }); /* ── Profil speichern (alles auf einmal) ───────────────────── */ $(document).on('click', '#wbfSaveProfile', function () { var $btn = $(this).prop('disabled', true); var $msg = $('#wbfProfileMsg'); var data = { display_name: $('#wbfEditName').val(), bio: $('#wbfEditBio').val(), signature: $('#wbfEditSignature').val() }; // Alle benutzerdefinierten Felder (alle Kategorien) einsammeln $('.wbf-cf-input').each(function () { data[$(this).data('field')] = $(this).val(); }); wbfPost('wbf_update_profile', data, function (d) { showMsg($msg, d.message, true); $btn.prop('disabled', false); }, function (d) { showMsg($msg, d.message || 'Fehler', false); $btn.prop('disabled', false); }); }); /* ── Passwort ändern ────────────────────────────────────────── */ $(document).on('click', '#wbfSavePassword', function () { var $btn = $(this).prop('disabled', true); var $msg = $('#wbfPasswordMsg'); var cur = $('#wbfCurrentPassword').val(); var pw1 = $('#wbfNewPassword').val(); var pw2 = $('#wbfNewPassword2').val(); if (!cur) { showMsg($msg, 'Bitte aktuelles Passwort eingeben.', false); return $btn.prop('disabled', false); } if (pw1.length < 6) { showMsg($msg, 'Neues Passwort mindestens 6 Zeichen.', false); return $btn.prop('disabled', false); } if (pw1 !== pw2) { showMsg($msg, 'Die Passwörter stimmen nicht überein.', false); return $btn.prop('disabled', false); } wbfPost('wbf_update_profile', { current_password: cur, new_password: pw1 }, function (d) { showMsg($msg, d.message, true); $('#wbfCurrentPassword, #wbfNewPassword, #wbfNewPassword2').val(''); $btn.prop('disabled', false); }, function (d) { showMsg($msg, d.message || 'Fehler', false); $btn.prop('disabled', false); }); }); /* ── Signatur Zeichenzähler ─────────────────────────────────── */ $(document).on('input', '#wbfEditSignature', function () { $('#wbfSigCount').text($(this).val().length); }); /* ── Avatar Upload ──────────────────────────────────────────── */ $(document).on('change', '#wbfAvatarFile', function () { var file = this.files[0]; if (!file) return; // Sofort-Vorschau — synchron, kein Callback, kein Warten var objectUrl = URL.createObjectURL(file); $('#wbfProfileAvatar').attr('src', objectUrl).css('opacity', '.6'); var fd = new FormData(); fd.append('action', 'wbf_upload_avatar'); fd.append('nonce', WBF.nonce); fd.append('avatar', file); $.ajax({ url: WBF.ajax_url, type: 'POST', data: fd, processData: false, contentType: false, success: function (res) { $('#wbfProfileAvatar').css('opacity', '1'); if (res.success) { // Object-URL freigeben, endgültige Server-URL setzen URL.revokeObjectURL(objectUrl); var finalUrl = res.data.avatar_url + '?v=' + Date.now(); $('#wbfProfileAvatar').attr('src', finalUrl); // Topbar-Avatar ebenfalls aktualisieren $('.wbf-topbar__user img').attr('src', finalUrl); $('.wbf-profile-widget__avatar img').attr('src', finalUrl); } }, error: function () { $('#wbfProfileAvatar').css('opacity', '1'); } }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Ungelesene Beiträge ══════════════════════════════════════════════════════════ */ var WBF_STORAGE_KEY = 'wbf_last_seen'; function wbfGetLastSeen() { try { return JSON.parse(localStorage.getItem(WBF_STORAGE_KEY) || '{}'); } catch (e) { return {}; } } function wbfSetLastSeen(data) { try { localStorage.setItem(WBF_STORAGE_KEY, JSON.stringify(data)); } catch (e) {} } function wbfMarkNewThreads() { var lastSeen = wbfGetLastSeen(); $('.wbf-thread-row[data-thread-id]').each(function () { var $row = $(this); var threadId = $row.data('thread-id').toString(); var lastReply = $row.data('last-reply'); if (!lastReply) return; var seenAt = lastSeen[threadId]; var isNew = !seenAt || new Date(lastReply) > new Date(seenAt); if (isNew) { $row.addClass('wbf-thread-row--has-new'); $row.find('.wbf-new-badge').show(); } }); } function wbfMarkNewPosts() { var $container = $('[data-thread-view]'); if (!$container.length) return; var threadId = $container.data('thread-view').toString(); var lastSeen = wbfGetLastSeen(); var seenAt = lastSeen[threadId]; $('.wbf-post[data-created]').each(function () { var created = $(this).data('created'); if (!created) return; if (seenAt && new Date(created) > new Date(seenAt)) { $(this).addClass('wbf-post--new'); } }); lastSeen[threadId] = new Date().toISOString(); wbfSetLastSeen(lastSeen); } $(function () { wbfMarkNewThreads(); wbfMarkNewPosts(); }); $(document).on('wbf:post_added', function (e, postId) { $('#post-' + postId).addClass('wbf-post--new'); var $container = $('[data-thread-view]'); if (!$container.length) return; var threadId = $container.data('thread-view').toString(); var lastSeen = wbfGetLastSeen(); lastSeen[threadId] = new Date().toISOString(); wbfSetLastSeen(lastSeen); }); /* ══════════════════════════════════════════════════════════ FEATURE: Editor-Toolbar — Bold, Italic, Bild, Smilies ══════════════════════════════════════════════════════════ */ function wbfInsertAtCursor($ta, text) { var el = $ta[0]; var start = el.selectionStart; var end = el.selectionEnd; var val = el.value; el.value = val.slice(0, start) + text + val.slice(end); el.selectionStart = el.selectionEnd = start + text.length; $ta.trigger('input'); el.focus(); } function wbfWrapSelection($ta, before, after) { var el = $ta[0]; var sel = el.value.slice(el.selectionStart, el.selectionEnd) || 'Text'; wbfInsertAtCursor($ta, before + sel + after); } function wbfGetTargetTextarea($toolbar) { return $('#' + $toolbar.data('target')); } // ── BBCode-Wrap-Helfer ──────────────────────────────────────── function wbfBBWrap($ta, tag) { var el = $ta[0]; var sel = el.value.slice(el.selectionStart, el.selectionEnd) || 'Text'; wbfInsertAtCursor($ta, '[' + tag + ']' + sel + '[/' + tag + ']'); } $(document).on('click', '.wbf-tb-btn', function (e) { e.preventDefault(); e.stopPropagation(); var $btn = $(this); var action = $btn.data('action'); var $toolbar = $btn.closest('.wbf-editor-toolbar'); var $ta = wbfGetTargetTextarea($toolbar); // ── Standard BBCode wrap [tag]sel[/tag] ─────────────────── if (action === 'bb') { var bb = $btn.data('bb'); if (bb === 'hr') { wbfInsertAtCursor($ta, '\n[hr]\n'); } else { wbfBBWrap($ta, bb); } // ── Dropdown-Toggle ─────────────────────────────────────── } else if (action === 'dropdown') { var panelId = 'wbf-' + $btn.data('target') + '-panel-' + $toolbar.data('target'); var $panel = $('#' + panelId); var wasOpen = $panel.is(':visible'); $('.wbf-tb-dropdown__panel').hide(); if (!wasOpen) $panel.show(); // ── Farbe ───────────────────────────────────────────────── } else if (action === 'bb-color') { var color = $btn.data('color'); var el = $ta[0]; var sel = el.value.slice(el.selectionStart, el.selectionEnd) || 'Text'; wbfInsertAtCursor($ta, '[color=' + color + ']' + sel + '[/color]'); $('.wbf-tb-dropdown__panel').hide(); // ── Größe ───────────────────────────────────────────────── } else if (action === 'bb-size') { var size = $btn.data('size'); var el2 = $ta[0]; var sel2 = el2.value.slice(el2.selectionStart, el2.selectionEnd) || 'Text'; wbfInsertAtCursor($ta, '[size=' + size + ']' + sel2 + '[/size]'); $('.wbf-tb-dropdown__panel').hide(); // ── Liste ───────────────────────────────────────────────── } else if (action === 'bb-list') { var ordered = $btn.data('ordered') ? '=1' : ''; wbfInsertAtCursor($ta, '[list' + ordered + ']\n[*] Punkt 1\n[*] Punkt 2\n[/list]'); // ── Spoiler ─────────────────────────────────────────────── } else if (action === 'bb-spoiler') { var title = prompt('Spoiler-Titel (optional):', '') || ''; var el3 = $ta[0]; var sel3 = el3.value.slice(el3.selectionStart, el3.selectionEnd) || 'Inhalt hier'; var tag3 = title ? '[spoiler=' + title + ']' : '[spoiler]'; wbfInsertAtCursor($ta, tag3 + sel3 + '[/spoiler]'); // ── Link ────────────────────────────────────────────────── } else if (action === 'bb-url') { var href = prompt('URL eingeben:', 'https://'); if (href && href.length > 7) { var el4 = $ta[0]; var sel4 = el4.value.slice(el4.selectionStart, el4.selectionEnd) || href; wbfInsertAtCursor($ta, '[url=' + href + ']' + sel4 + '[/url]'); } // ── Bild-URL ────────────────────────────────────────────── } else if (action === 'bb-img') { var imgUrl = prompt('Bild-URL eingeben:', 'https://'); if (imgUrl && imgUrl.length > 8) { wbfInsertAtCursor($ta, '[img]' + imgUrl + '[/img]'); } // ── Bild hochladen ──────────────────────────────────────── } else if (action === 'img-upload') { $btn.find('.wbf-img-file-input').trigger('click'); // ── Emoji-Picker ────────────────────────────────────────── } else if (action === 'emoji') { var $picker = $toolbar.find('.wbf-emoji-picker'); var wasOpen2 = $picker.is(':visible'); $('.wbf-emoji-picker, .wbf-tb-dropdown__panel').hide(); if (!wasOpen2) $picker.show(); } }); // Dropdown-Panel schließen bei Klick außerhalb $(document).on('click', function (e) { if (!$(e.target).closest('.wbf-tb-dropdown, .wbf-tb-dropdown__panel').length) { $('.wbf-tb-dropdown__panel').hide(); } }); /* ── Bild hochladen ─────────────────────────────────────────── */ $(document).on('change', '.wbf-img-file-input', function () { var file = this.files[0]; if (!file) return; var $input = $(this); var $btn = $input.closest('.wbf-tb-btn'); var $toolbar = $input.closest('.wbf-editor-toolbar'); var $ta = wbfGetTargetTextarea($toolbar); $btn.addClass('wbf-tb-btn--loading'); var $prog = $toolbar.find('.wbf-tb-upload-progress'); if (!$prog.length) { $prog = $(' Wird hochgeladen…'); $toolbar.append($prog); } $prog.addClass('active'); var fd = new FormData(); fd.append('action', 'wbf_upload_post_image'); fd.append('nonce', WBF.nonce); fd.append('image', file); $.ajax({ url: WBF.ajax_url, type: 'POST', data: fd, processData: false, contentType: false, success: function (res) { if (res.success) { wbfInsertAtCursor($ta, '[img]' + res.data.url + '[/img]'); } else { alert(res.data.message || 'Fehler beim Hochladen.'); } }, error: function () { alert('Verbindungsfehler beim Hochladen.'); }, complete: function () { $btn.removeClass('wbf-tb-btn--loading'); $prog.removeClass('active'); $input.val(''); } }); }); /* ── Emoji einfügen ─────────────────────────────────────────── */ $(document).on('click', '.wbf-emoji-item', function (e) { e.stopPropagation(); var $toolbar = $(this).closest('.wbf-editor-toolbar'); wbfInsertAtCursor(wbfGetTargetTextarea($toolbar), $(this).data('emoji')); $toolbar.find('.wbf-emoji-picker').hide(); }); $(document).on('click', function (e) { if (!$(e.target).closest('.wbf-editor-toolbar').length) { $('.wbf-emoji-picker').hide(); } }); /* ══════════════════════════════════════════════════════════ FEATURE: Beitrag melden (auch eigene) ══════════════════════════════════════════════════════════ */ $(document).on('click', '.wbf-report-btn', function (e) { e.preventDefault(); if (WBF.logged_in !== 'yes') { $('#wbfAuthModal').addClass('active'); return; } $('#wbfReportId').val($(this).data('id')); $('#wbfReportType').val($(this).data('type') || 'post'); $('#wbfReportReason').val(''); $('#wbfReportNote').val(''); $('#wbfReportMsg').hide(); $('#wbfReportModal').addClass('active'); }); $(document).on('click', '#wbfSubmitReport', function () { var reason = $('#wbfReportReason').val(); if (!reason) { showMsg($('#wbfReportMsg'), 'Bitte einen Grund auswählen.', false); return; } var $btn = $(this).prop('disabled', true).html(''); wbfPost('wbf_report_post', { object_id: $('#wbfReportId').val(), object_type: $('#wbfReportType').val(), reason: reason, note: $('#wbfReportNote').val() }, function (d) { showMsg($('#wbfReportMsg'), d.message, true); var postId = $('#wbfReportId').val(); $('.wbf-report-btn[data-id="' + postId + '"]') .replaceWith(''); setTimeout(function () { $('#wbfReportModal').removeClass('active'); }, 1800); $btn.prop('disabled', false).html(' Melden'); }, function (d) { showMsg($('#wbfReportMsg'), d.message || 'Fehler beim Melden.', false); $btn.prop('disabled', false).html(' Melden'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Beitrag inline bearbeiten ══════════════════════════════════════════════════════════ */ $(document).on('click', '.wbf-edit-post-btn', function (e) { e.preventDefault(); var postId = $(this).data('id'); $('#wbf-post-content-' + postId).hide(); $('#wbf-post-edit-' + postId).show().find('textarea').focus(); }); $(document).on('click', '.wbf-cancel-edit-btn', function () { var postId = $(this).data('id'); $('#wbf-post-content-' + postId).show(); $('#wbf-post-edit-' + postId).hide(); }); $(document).on('click', '.wbf-save-edit-btn', function () { var $btn = $(this).prop('disabled', true).html(''); var postId = $btn.data('id'); var $wrap = $('#wbf-post-edit-' + postId); var $msg = $wrap.find('.wbf-edit-msg'); wbfPost('wbf_edit_post', { post_id: postId, content: $wrap.find('textarea').val() }, function (d) { $('#wbf-post-content-' + postId).html(d.content).show(); $wrap.hide(); $btn.prop('disabled', false).html(' Speichern'); $msg.css('color', '#56cf7e').text(d.message || 'Gespeichert!').show(); setTimeout(function () { $msg.fadeOut(); }, 2500); }, function (d) { $msg.css('color', '#f05252').text(d.message || 'Fehler').show(); $btn.prop('disabled', false).html(' Speichern'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Zitieren (BBCode) ══════════════════════════════════════════════════════════ */ $(document).on('click', '.wbf-quote-btn', function () { if (WBF.logged_in !== 'yes') { $('#wbfAuthModal').addClass('active'); return; } var sourceId = $(this).data('source'); var author = $(this).data('author'); var $content = $('#' + sourceId); if (!$content.length) return; // Strip HTML tags to get plain text, skip nested blockquotes var rawText = $content.clone().find('blockquote, .wbf-bb-quote').remove().end().text().trim(); if (rawText.length > 600) rawText = rawText.substring(0, 600) + '…'; var quote = '[quote=' + author + ']\n' + rawText + '\n[/quote]\n\n'; var $ta = $('#wbfReplyContent'); var $replyBox = $('#wbfReplyBox'); if (!$ta.length) return; var el = $ta[0]; var start = el.selectionStart; var end = el.selectionEnd; var val = el.value; el.value = val.slice(0, start) + quote + val.slice(end); el.selectionStart = el.selectionEnd = start + quote.length; $ta.trigger('input').focus(); $('html, body').animate({ scrollTop: $replyBox.offset().top - 80 }, 350); }); /* ══════════════════════════════════════════════════════════ FEATURE: Bild-Lightbox ══════════════════════════════════════════════════════════ */ $(document).on('click', '.wbf-post__content img', function () { var $lb = $('
' + '' + '' + ($(this).attr('alt') || '') + '' + '
'); $('body').append($lb).css('overflow', 'hidden'); }); $(document).on('click', '.wbf-lightbox', function (e) { if ($(e.target).hasClass('wbf-lightbox') || $(e.target).hasClass('wbf-lightbox__close')) { $(this).remove(); $('body').css('overflow', ''); } }); $(document).on('keydown', function (e) { if (e.key === 'Escape') { $('.wbf-lightbox').remove(); $('body').css('overflow', ''); $('.wbf-emoji-picker').hide(); $('.wbf-tb-dropdown__panel').hide(); } }); /* ══════════════════════════════════════════════════════════ FEATURE: Thread-Inhalt (OP) inline bearbeiten ══════════════════════════════════════════════════════════ */ $(document).on('click', '.wbf-edit-thread-btn', function (e) { e.preventDefault(); var threadId = $(this).data('id'); $('#wbf-thread-content-' + threadId).hide(); $('#wbf-thread-edit-' + threadId).show().find('textarea').focus(); }); $(document).on('click', '.wbf-cancel-thread-btn', function () { var threadId = $(this).data('id'); $('#wbf-thread-content-' + threadId).show(); $('#wbf-thread-edit-' + threadId).hide(); }); $(document).on('click', '.wbf-save-thread-btn', function () { var $btn = $(this).prop('disabled', true).html(''); var threadId = $btn.data('id'); var $wrap = $('#wbf-thread-edit-' + threadId); var $msg = $wrap.find('.wbf-edit-msg'); wbfPost('wbf_edit_thread', { thread_id: threadId, title: $wrap.find('.wbf-edit-title-input').val(), content: $wrap.find('textarea').val() }, function (d) { $('#wbf-thread-content-' + threadId).html(d.content).show(); // Titel im DOM aktualisieren if (d.title) { $('.wbf-thread-title').first().text(d.title); } $wrap.hide(); $btn.prop('disabled', false).html(' Speichern'); $msg.css('color', '#56cf7e').text(d.message || 'Gespeichert!').show(); setTimeout(function () { $msg.fadeOut(); }, 2500); }, function (d) { $msg.css('color', '#f05252').text(d.message || 'Fehler').show(); $btn.prop('disabled', false).html(' Speichern'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Live-Suche ══════════════════════════════════════════════════════════ */ var wbfSearchTimer = null; function wbfTimeAgo(dateStr) { var diff = Math.floor((Date.now() - new Date(dateStr).getTime()) / 1000); if (diff < 60) return 'Gerade eben'; if (diff < 3600) return Math.floor(diff/60) + ' Min. ago'; if (diff < 86400) return Math.floor(diff/3600) + ' Std. ago'; return Math.floor(diff/86400) + ' Tage ago'; } $(document).on('input', '#wbfSearchInput', function () { var q = $(this).val().trim(); var $dd = $('#wbfSearchDropdown'); clearTimeout(wbfSearchTimer); if (q.length < 2) { $dd.hide().empty(); return; } wbfSearchTimer = setTimeout(function () { $dd.html('
Suche…
').show(); wbfPost('wbf_search', { query: q }, function (d) { if (!d.results || !d.results.length) { $dd.html('
Keine Ergebnisse für „' + $('').text(q).html() + '“
'); return; } var html = ''; var shown = d.results.slice(0, 6); shown.forEach(function (r) { var isThread = r.result_type === 'thread'; var base3 = WBF.forum_url || window.location.href.split('?')[0]; var sep3 = base3.indexOf('?') !== -1 ? '&' : '?'; var url = base3 + sep3 + 'forum_thread=' + r.id; var preview = r.content ? r.content.replace(/<[^>]+>/g,'').substring(0,80) : ''; var typeLabel = isThread ? ' Thread' : ' Antwort'; html += '
' + '
' + $('').text(r.title.substring(0,55)).html() + '
' + '
' + typeLabel + ' ' + $('').text(r.cat_name).html() + '' + '' + $('').text(r.display_name).html() + '' + '
' + (preview ? '
' + $('').text(preview).html() + '…
' : '') + '
'; }); if (d.results.length > 6) { html += ''; } $dd.html(html).show(); }, function () { $dd.html('
Fehler bei der Suche.
'); }); }, 320); }); // Alle Ergebnisse anzeigen → zur Suchseite $(document).on('click', '.wbf-search-dd-footer', function () { var q = $(this).data('query'); window.location.href = window.location.pathname + '?forum_search=1&q=' + encodeURIComponent(q); }); // Enter-Taste → Suchseite $(document).on('keydown', '#wbfSearchInput', function (e) { if (e.key === 'Enter') { var q = $(this).val().trim(); if (q.length >= 2) { window.location.href = window.location.pathname + '?forum_search=1&q=' + encodeURIComponent(q); } } if (e.key === 'Escape') { $('#wbfSearchDropdown').hide(); } }); // Dropdown schließen bei Klick außerhalb $(document).on('click', function (e) { if (!$(e.target).closest('#wbfSearchForm').length) { $('#wbfSearchDropdown').hide(); } }); /* ══════════════════════════════════════════════════════════ FEATURE: Benachrichtigungen ══════════════════════════════════════════════════════════ */ var wbfNotifLoaded = false; function wbfLoadNotifications() { wbfPost('wbf_get_notifications', {}, function (d) { var $list = $('#wbfNotifList'); if (!d.notifications || !d.notifications.length) { $list.html('

Keine Benachrichtigungen
'); return; } var html = ''; d.notifications.forEach(function (n) { var isUnread = n.is_read == 0; var avatar = $('').attr('src', n.actor_avatar || '').attr('alt', '').attr('class', 'wbf-dm-inbox-item__avatar')[0].outerHTML; var base = WBF.forum_url || window.location.href.split('?')[0]; var sep = base.indexOf('?') !== -1 ? '&' : '?'; var actor = '' + $('').text(n.actor_name).html() + ''; // URL + Text je nach Typ var url, text, sub; if (n.type === 'message') { url = base + sep + 'forum_dm=1'; text = actor + ' hat dir eine Nachricht gesendet'; sub = ''; } else if (n.type === 'mention') { url = base + sep + 'forum_thread=' + n.thread_id; text = actor + ' hat dich erwähnt'; sub = n.thread_title || ''; } else if (n.type === 'like') { url = base + sep + 'forum_thread=' + n.thread_id; text = actor + ' hat deinen Beitrag geliket'; sub = n.thread_title || ''; } else { // reply (default) url = base + sep + 'forum_thread=' + n.thread_id; text = actor + ' hat in deinem Thread geantwortet'; sub = n.thread_title || ''; } html += '' + '
' + avatar + '
' + '
' + '
' + text + (sub ? '
' + $('').text(sub).html() + '' : '') + '
' + '
' + wbfTimeAgo(n.created_at) + '
' + '
' + (isUnread ? '
' : '') + '
'; }); $list.html(html); // Badge aktualisieren var unread = d.unread || 0; var $badge = $('#wbfNotifBadge'); if (unread > 0) { $badge.text(Math.min(unread,99)).show(); } else { $badge.hide(); } }); wbfNotifLoaded = true; } // Glocke klicken → Dropdown öffnen + Nachrichten laden $(document).on('click', '#wbfNotifBtn', function (e) { e.stopPropagation(); var $dd = $('#wbfNotifDropdown'); if ($dd.is(':visible')) { $dd.hide(); } else { $dd.show(); if (!wbfNotifLoaded) wbfLoadNotifications(); } }); // Alle als gelesen markieren $(document).on('click', '#wbfMarkAllRead', function (e) { e.stopPropagation(); wbfPost('wbf_mark_notifications_read', {}, function () { $('#wbfNotifBadge').hide(); $('#wbfNotifList .wbf-notif-item').removeClass('wbf-notif-item--unread'); $('#wbfNotifList .wbf-notif-dot').remove(); wbfNotifLoaded = false; // neu laden beim nächsten Öffnen }); }); // Benachrichtigung klicken → als gelesen markieren + navigieren $(document).on('click', '.wbf-notif-item', function (e) { e.preventDefault(); var href = $(this).attr('href'); wbfPost('wbf_mark_notifications_read', {}, function () { window.location.href = href; }); }); // Dropdown schließen bei Klick außerhalb $(document).on('click', function (e) { if (!$(e.target).closest('#wbfNotifWrap').length) { $('#wbfNotifDropdown').hide(); } }); // ── Unified Smart Polling ───────────────────────────────────────────────── // Benachrichtigungen + DM-Badge + Live-Konversation in einem einzigen Interval if (WBF.logged_in === 'yes') { var wbfLastMsgId = 0; function wbfPoll() { // 1. Benachrichtigungs-Badge wbfPost('wbf_get_notifications', {}, function(d) { var $badge = $('#wbfNotifBadge'); var unread = d.unread || 0; if (unread > 0) { $badge.text(Math.min(unread,99)).show(); } else { $badge.hide(); } }); // 2. DM-Badge + Live-Nachrichten wbfPost('wbf_get_inbox', {}, function(d) { var unread = parseInt(d.unread) || 0; var $badge = $('.wbf-dm-btn .wbf-notif-badge'); if (unread > 0) { $badge.text(Math.min(unread,99)).css('display',''); } else { $badge.css('display','none'); } // 3. Wenn Konversation offen: neue Nachrichten live nachladen var $conv = $('#wbfDmConversation'); if (!$conv.length || !wbfLastMsgId) return; var partnerId = parseInt($conv.data('partner')); if (!partnerId) return; wbfPost('wbf_get_new_messages', { partner_id: partnerId, since_id: wbfLastMsgId }, function(r) { if (!r.messages || !r.messages.length) return; var $msgs = $('#wbfDmMessages'); var wasAtBottom = $msgs[0].scrollHeight - $msgs[0].scrollTop - $msgs[0].clientHeight < 60; r.messages.forEach(function(m) { if ($('[data-msg-id="' + m.id + '"]').length) return; // kein Duplikat var isMine = parseInt(m.from_id) === parseInt(WBF.my_id); var cls = isMine ? 'wbf-dm-msg wbf-dm-msg--out' : 'wbf-dm-msg wbf-dm-msg--in'; var time = wbfTimeAgo(m.created_at); var delBtn = ''; var html = '
'; if (!isMine) { html += $('').attr('src', m.sender_avatar || '').attr('class', 'wbf-dm-inbox-item__avatar')[0].outerHTML; } html += '
' + $('').text(m.content).html().replace(/\n/g,'
') + '
' + time + delBtn + '
'; $msgs.append(html); wbfLastMsgId = Math.max(wbfLastMsgId, parseInt(m.id)); }); if (wasAtBottom) $msgs[0].scrollTop = $msgs[0].scrollHeight; wbfPost('wbf_mark_messages_read', { partner_id: partnerId }); }); }); } // Nach dem Laden der Konversation: hoechste ID merken var origConvLoad = window.wbfConvLoaded; $(document).on('wbf:messages_loaded', function(e, msgs) { if (msgs && msgs.length) { wbfLastMsgId = Math.max.apply(null, msgs.map(function(m){ return parseInt(m.id)||0; })); } }); setTimeout(wbfPoll, 3000); setInterval(wbfPoll, 15000); } /* ══════════════════════════════════════════════════════════ FEATURE: Auto-Logout bei Inaktivität ══════════════════════════════════════════════════════════ */ if ( WBF.logged_in === 'yes' && WBF.auto_logout_minutes > 0 ) { var wbfIdleMs = WBF.auto_logout_minutes * 60 * 1000; var wbfWarnMs = 30 * 1000; // 30 Sek. Vorwarnung var wbfIdleTimer = null; var wbfWarnTimer = null; var wbfCountTimer = null; var wbfWarning = false; // ── Toast-Element ──────────────────────────────────────── var $wbfToast = $([ '
', '
', '', 'Sitzung läuft ab', '
', '

', 'Du wirst in 30 Sekunden', ' automatisch abgemeldet.', '

', '
', '', '', '
', '
' ].join('')).appendTo('body'); function wbfDoLogout() { clearTimeout(wbfIdleTimer); clearTimeout(wbfWarnTimer); clearInterval(wbfCountTimer); $wbfToast.hide(); wbfPost('wbf_logout', {}, function () { location.reload(); }); } function wbfShowWarning() { wbfWarning = true; var secs = 30; $('#wbfIdleCountdown').text(secs); $wbfToast.fadeIn(200); wbfCountTimer = setInterval(function () { secs--; $('#wbfIdleCountdown').text(secs); if (secs <= 0) { clearInterval(wbfCountTimer); wbfDoLogout(); } }, 1000); // Auto-logout after warning period wbfIdleTimer = setTimeout(wbfDoLogout, wbfWarnMs); } function wbfResetIdleTimer() { if (wbfWarning) return; // Nutzer hat aktiv Warnung bestätigt — nicht resetten clearTimeout(wbfIdleTimer); clearTimeout(wbfWarnTimer); // Warn 30 sec before timeout wbfWarnTimer = setTimeout(wbfShowWarning, wbfIdleMs - wbfWarnMs); } // "Bleiben" Button $(document).on('click', '#wbfIdleStay', function () { clearTimeout(wbfIdleTimer); clearInterval(wbfCountTimer); $wbfToast.fadeOut(200); wbfWarning = false; wbfResetIdleTimer(); }); // "Abmelden" Button $(document).on('click', '#wbfIdleLogout', function () { wbfDoLogout(); }); // Aktivitäts-Events überwachen var wbfActivityEvents = 'mousemove keydown mousedown touchstart scroll click'; $(document).on(wbfActivityEvents, function () { if (!wbfWarning) wbfResetIdleTimer(); }); // Start wbfResetIdleTimer(); } /* ── Login: Remember-Me ─────────────────────────────────── */ $(document).on('click', '.wbf-login-submit-btn', function () { var $btn = $(this).prop('disabled', true).html(''); var $box = $(this).closest('.wbf-auth-box'); wbfPost('wbf_login', { username: $box.find('.wbf-field-username').val(), password: $box.find('.wbf-field-password').val(), remember_me: $box.find('.wbf-field-remember').is(':checked') ? '1' : '' }, function () { location.reload(); }, function (d) { showMsg($box.find('.wbf-login-msg'), d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Einloggen'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Reaktionen ══════════════════════════════════════════════════════════ */ // Picker öffnen/schließen $(document).on('click', '.wbf-reaction-trigger', function (e) { e.stopPropagation(); var $picker = $(this).next('.wbf-reaction-picker'); var wasOpen = $picker.is(':visible'); $('.wbf-reaction-picker').hide(); if (!wasOpen) $picker.show(); }); // Reaktion wählen (aus Picker oder Summary) $(document).on('click', '.wbf-reaction-btn, .wbf-reaction-pill', function (e) { e.stopPropagation(); if (WBF.logged_in !== 'yes') { $('#wbfAuthModal').addClass('active'); return; } var $bar = $(this).closest('.wbf-reaction-bar'); var reaction = $(this).data('reaction'); wbfPost('wbf_set_reaction', { object_id: $bar.data('id'), object_type: $bar.data('type'), reaction: reaction }, function (d) { var $summary = $bar.find('.wbf-reaction-summary'); var $picker = $bar.find('.wbf-reaction-picker'); // Rebuild summary var order = (WBF.reactions && WBF.reactions.length) ? WBF.reactions : ['👍','❤️','😂','😮','😢','😡']; var html = ''; order.forEach(function(e) { if (d.counts[e]) { var active = (d.mine === e) ? ' wbf-reaction-active' : ''; html += ''; } }); if (!$summary.length) { $bar.prepend('
' + html + '
'); } else { $summary.html(html || '').toggle(!!html); } // Update picker active states $picker.find('.wbf-reaction-btn').each(function() { $(this).toggleClass('wbf-reaction-active', $(this).data('reaction') === d.mine); }); $picker.hide(); }); }); // Close pickers on outside click $(document).on('click', function() { $('.wbf-reaction-picker').hide(); }); /* ══════════════════════════════════════════════════════════ FEATURE: @Erwähnungen Autocomplete im Reply-Textarea ══════════════════════════════════════════════════════════ */ var wbfMentionTimer = null; var wbfMentionActive = false; var $wbfMentionDrop = null; function wbfCloseMention() { if ($wbfMentionDrop) $wbfMentionDrop.remove(); $wbfMentionDrop = null; wbfMentionActive = false; } $(document).on('input', '#wbfReplyContent, #wbfThreadContent', function () { var $ta = $(this); var val = $ta.val(); var pos = $ta[0].selectionStart; var before = val.slice(0, pos); var match = before.match(/@([a-zA-Z0-9_]{0,30})$/); if (!match) { wbfCloseMention(); return; } var q = match[1]; wbfMentionActive = true; clearTimeout(wbfMentionTimer); wbfMentionTimer = setTimeout(function() { wbfPost('wbf_user_suggest', { q: q }, function(d) { if (!d.users || !d.users.length) { wbfCloseMention(); return; } if ($wbfMentionDrop) $wbfMentionDrop.remove(); var html = ''; d.users.forEach(function(u) { html += '
' + $('').attr('src', u.avatar_url || '').attr('width', '22').attr('height', '22').css({'border-radius':'50%','flex-shrink':'0'})[0].outerHTML + '' + $('').text(u.display_name).html() + '' + '@' + $('').text(u.username).html() + '' + '
'; }); $wbfMentionDrop = $('
' + html + '
'); $ta.closest('.wbf-reply-form__input, .wbf-form-row').append($wbfMentionDrop); $wbfMentionDrop.show(); }); }, 200); }); $(document).on('click', '.wbf-mention-item', function(e) { e.stopPropagation(); var username = $(this).data('username'); var $ta = $('#wbfReplyContent:visible, #wbfThreadContent:visible').first(); if (!$ta.length) return; var val = $ta.val(), pos = $ta[0].selectionStart; var before = val.slice(0, pos); var after = val.slice(pos); var newBefore = before.replace(/@([a-zA-Z0-9_]*)$/, '@' + username + ' '); $ta.val(newBefore + after); $ta[0].selectionStart = $ta[0].selectionEnd = newBefore.length; wbfCloseMention(); $ta.focus(); }); $(document).on('click', function(e) { if (!$(e.target).closest('.wbf-mention-dropdown').length) wbfCloseMention(); }); /* ══════════════════════════════════════════════════════════ FEATURE: Private Nachrichten (DM) ══════════════════════════════════════════════════════════ */ // Helper: format messages in conversation function wbfRenderMessages(msgs, myId) { if (!msgs || !msgs.length) { return '

Noch keine Nachrichten.

'; } var html = ''; msgs.forEach(function(m) { var isMine = parseInt(m.from_id) === parseInt(myId); var cls = isMine ? 'wbf-dm-msg wbf-dm-msg--out' : 'wbf-dm-msg wbf-dm-msg--in'; var time = wbfTimeAgo(m.created_at); var delBtn = ''; if (!isMine) { html += '
' + $('').attr('src', m.sender_avatar || '').attr('class', 'wbf-dm-msg__avatar')[0].outerHTML + '
' + $('').text(m.content).html().replace(/\n/g,'
') + '
' + time + delBtn + '
'; } else { html += '
' + '
' + $('').text(m.content).html().replace(/\n/g,'
') + '
' + time + delBtn + '
'; } }); return html; } // Render inbox list function wbfRenderInbox(inbox, myId) { if (!inbox || !inbox.length) { return '
Keine Nachrichten.
'; } var html = ''; inbox.forEach(function(conv) { var href = window.location.pathname + '?forum_dm=inbox&with=' + conv.partner_id; var unread = parseInt(conv.unread_cnt) > 0; html += '' + $('').attr('src', conv.partner_avatar || '').attr('class', 'wbf-dm-inbox-item__avatar')[0].outerHTML + '
' + '' + $('').text(conv.partner_name).html() + '' + (unread ? '' + conv.unread_cnt + '' : '') + '
'; }); return html; } // Auto-load inbox if on DM page if ($('#wbfDmInbox').length && WBF.logged_in === 'yes') { wbfPost('wbf_get_inbox', {}, function(d) { $('#wbfDmInbox').html(wbfRenderInbox(d.inbox, WBF.my_id)); }); // Load conversation if partner given var $conv = $('#wbfDmConversation'); if ($conv.length) { var partnerId = $conv.data('partner'); wbfPost('wbf_get_conversation', { partner_id: partnerId }, function(d) { // Header var p = d.partner; if (p) { var backUrl = window.location.pathname + '?forum_dm=inbox'; $('#wbfDmHeader').html( '' + $('').attr('src', p.avatar_url || '').attr('class', 'wbf-dm-inbox-item__avatar')[0].outerHTML + '' + $('').text(p.display_name).html() + '' + '@' + $('').text(p.username).html() + '' ); } var html = wbfRenderMessages(d.messages, d.my_id); var $msgs = $('#wbfDmMessages').html(html); $msgs[0].scrollTop = $msgs[0].scrollHeight; $(document).trigger('wbf:messages_loaded', [d.messages]); // "Ältere laden" initialisieren — AJAX gibt total zurück if (d.total !== undefined) { $('#wbfDmLoadMore').data('offset', 0).data('partner', d.partner ? d.partner.id : 0); wbfUpdateLoadMoreBtn(d.total, d.messages.length); } }); } } // Send reply in open conversation $(document).on('click', '#wbfDmSendReply', function() { var toId = $(this).data('to'); var text = $('#wbfDmReplyText').val().trim(); if (!text) return; var $btn = $(this).prop('disabled', true); wbfPost('wbf_send_message', { to_id: toId, content: text }, function(d) { var delBtn = ''; var html = '
' + '
' + $('').text(d.content).html().replace(/\n/g,'
') + '
Gerade eben' + delBtn + '
'; var $msgs = $('#wbfDmMessages'); $msgs.append(html); $msgs[0].scrollTop = $msgs[0].scrollHeight; $('#wbfDmReplyText').val(''); $btn.prop('disabled', false); if (d.message_id) wbfLastMsgId = Math.max(wbfLastMsgId, parseInt(d.message_id)); }, function(e) { alert(e.message || 'Fehler'); $btn.prop('disabled', false); }); }); // Delete message $(document).on('click', '.wbf-dm-msg__del', function() { var msgId = $(this).data('id'); var $row = $(this).closest('[data-msg-id]'); if (!confirm('Nachricht löschen?')) return; wbfPost('wbf_delete_message', { message_id: msgId }, function() { $row.fadeOut(200, function() { $(this).remove(); }); }, function(e) { alert(e.message || 'Fehler beim Löschen.'); }); }); // Enter to send (Shift+Enter = newline) $(document).on('keydown', '#wbfDmReplyText', function(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); $('#wbfDmSendReply').trigger('click'); } }); // New DM button → open compose modal $(document).on('click', '#wbfNewDmBtn, #wbfNewDmBtn2', function() { $('#wbfDmRecipientInput').val(''); $('#wbfDmToId').val(''); $('#wbfDmComposeText').val(''); $('#wbfDmComposeMsg').hide(); $('#wbfDmComposeModal').addClass('active'); }); // Recipient autocomplete in compose modal var wbfDmSugTimer = null; $(document).on('input', '#wbfDmRecipientInput', function() { var q = $(this).val().trim(); clearTimeout(wbfDmSugTimer); if (!q) { $('#wbfDmSuggest').hide().empty(); return; } wbfDmSugTimer = setTimeout(function() { wbfPost('wbf_user_suggest', { q: q }, function(d) { var $s = $('#wbfDmSuggest'); if (!d.users || !d.users.length) { $s.hide().empty(); return; } var html = ''; d.users.forEach(function(u) { html += '
' + $('').attr('src', u.avatar_url || '').attr('width', '22').attr('height', '22').css({'border-radius':'50%','flex-shrink':'0'})[0].outerHTML + $('').text(u.display_name).html() + '@' + $('').text(u.username).html() + '' + '
'; }); $s.html(html).show(); }); }, 200); }); $(document).on('click', '#wbfDmSuggest .wbf-tag-suggest-item', function() { var id = $(this).data('id'); var name = $(this).data('name'); $('#wbfDmToId').val(id); $('#wbfDmRecipientInput').val(name); $('#wbfDmSuggest').hide().empty(); }); // Send from compose modal $(document).on('click', '#wbfDmComposeSend', function() { var toId = $('#wbfDmToId').val(); var text = $('#wbfDmComposeText').val().trim(); var $btn = $(this).prop('disabled', true).html(''); if (!toId) { showMsg($('#wbfDmComposeMsg'), 'Bitte Empfänger wählen.', false); $btn.prop('disabled', false).html(' Senden'); return; } if (!text) { showMsg($('#wbfDmComposeMsg'), 'Nachricht leer.', false); $btn.prop('disabled', false).html(' Senden'); return; } wbfPost('wbf_send_message', { to_id: toId, content: text }, function() { showMsg($('#wbfDmComposeMsg'), '✔ Gesendet!', true); setTimeout(function() { $('#wbfDmComposeModal').removeClass('active'); window.location.href = window.location.pathname + '?forum_dm=inbox&with=' + toId; }, 800); }, function(e) { showMsg($('#wbfDmComposeMsg'), e.message || 'Fehler', false); $btn.prop('disabled', false).html(' Senden'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Online-Nutzer (Notification polling erweitern) ══════════════════════════════════════════════════════════ */ /* ══════════════════════════════════════════════════════════ FEATURE: Passwort vergessen ══════════════════════════════════════════════════════════ */ // "Passwort vergessen?" → Panel wechseln $(document).on('click', '.wbf-forgot-link', function(e) { e.preventDefault(); $('.wbf-auth-tab').removeClass('active'); $('.wbf-auth-panel').removeClass('active'); $('[data-panel="forgot"]').addClass('active'); }); $(document).on('click', '.wbf-show-login', function(e) { e.preventDefault(); $('.wbf-auth-panel').removeClass('active'); $('[data-tab="login"]').addClass('active'); $('[data-panel="login"]').addClass('active'); }); // Reset-Link anfordern $(document).on('click', '.wbf-forgot-submit-btn', function() { var $btn = $(this).prop('disabled', true).html(''); wbfPost('wbf_forgot_password', { email: $(this).closest('.wbf-auth-box').find('.wbf-field-forgot-email').val() }, function(d) { showMsg($btn.closest('.wbf-auth-box').find('.wbf-forgot-msg'), d.message, true); $btn.prop('disabled', false).html(' Reset-Link senden'); }, function(d) { showMsg($btn.closest('.wbf-auth-box').find('.wbf-forgot-msg'), d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Reset-Link senden'); }); }); // Passwort-Reset Formular (separate Seite via ?wbf_reset_token=...) $(document).on('click', '#wbfResetSubmit', function() { var $btn = $(this).prop('disabled', true).html(''); wbfPost('wbf_reset_password', { token: $('#wbfResetToken').val(), password: $('#wbfResetPass1').val(), password2: $('#wbfResetPass2').val() }, function(d) { showMsg($('#wbfResetMsg'), d.message, true); $btn.html(' Passwort geändert!'); setTimeout(function() { window.location.href = WBF.forum_url || window.location.pathname.split('?')[0]; }, 2000); }, function(d) { showMsg($('#wbfResetMsg'), d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Passwort ändern'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Ältere Nachrichten laden (DM) ══════════════════════════════════════════════════════════ */ // Wird nach dem ersten Laden der Konversation aufgerufen function wbfUpdateLoadMoreBtn(total, currentCount) { var $wrap = $('#wbfDmLoadMoreWrap'); var $btn = $('#wbfDmLoadMore'); if (total > currentCount) { var remaining = total - currentCount; $btn.html(' ' + remaining + ' ältere Nachrichten laden'); $wrap.show(); } else { $wrap.hide(); } } $(document).on('click', '#wbfDmLoadMore', function() { var $btn = $(this).prop('disabled', true).html(''); var partnerId = $(this).data('partner'); var offset = parseInt($(this).data('offset')) || 0; var loadCount = 30; var newOffset = offset + loadCount; wbfPost('wbf_load_more_messages', { partner_id: partnerId, offset: newOffset }, function(d) { if (!d.messages || !d.messages.length) { $('#wbfDmLoadMoreWrap').hide(); return; } // Ältere Nachrichten oben einfügen var html = wbfRenderMessages(d.messages, d.my_id); var $msgs = $('#wbfDmMessages'); var oldHeight = $msgs[0].scrollHeight; $msgs.prepend(html); // Scroll-Position halten (nicht nach oben springen) $msgs.scrollTop($msgs[0].scrollHeight - oldHeight); // Offset aktualisieren $('#wbfDmLoadMore').data('offset', newOffset).prop('disabled', false); // Button update var loaded = newOffset + d.messages.length; wbfUpdateLoadMoreBtn(d.total, loaded); }, function() { $btn.prop('disabled', false).html(' Ältere laden'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Thread-Vorschau beim Hover ══════════════════════════════════════════════════════════ */ var $wbfPreviewTip = $('
').appendTo('body'); var wbfPreviewTimer = null; $(document).on('mouseenter', '.wbf-thread-row__title', function(e) { var $row = $(this).closest('.wbf-thread-row'); var preview = $row.data('preview'); if (!preview || preview.length < 10) return; clearTimeout(wbfPreviewTimer); wbfPreviewTimer = setTimeout(function() { $wbfPreviewTip.text(preview + (preview.length >= 160 ? '…' : '')).addClass('visible'); positionTip(e); }, 280); }); $(document).on('mousemove', '.wbf-thread-row__title', function(e) { if ($wbfPreviewTip.hasClass('visible')) positionTip(e); }); $(document).on('mouseleave', '.wbf-thread-row__title', function() { clearTimeout(wbfPreviewTimer); $wbfPreviewTip.removeClass('visible'); }); function positionTip(e) { var tipW = $wbfPreviewTip.outerWidth(); var left = Math.min(e.pageX + 12, $(window).width() - tipW - 16); var top = e.pageY + 18; $wbfPreviewTip.css({ left: left, top: top }); } /* ══════════════════════════════════════════════════════════ FEATURE: Ungelesene Threads markieren ══════════════════════════════════════════════════════════ */ /* ══════════════════════════════════════════════════════════ FEATURE: Thread-Abonnement ══════════════════════════════════════════════════════════ */ $(document).on('click', '.wbf-subscribe-btn', function(e) { e.preventDefault(); var $btn = $(this).prop('disabled', true); var threadId = $btn.data('thread'); wbfPost('wbf_toggle_subscribe', { thread_id: threadId }, function(d) { $btn.prop('disabled', false); if (d.subscribed) { $btn.addClass('wbf-btn--primary') .html(' Abonniert'); $btn.attr('title','Abonnement entfernen'); } else { $btn.removeClass('wbf-btn--primary') .html(' Abonnieren'); $btn.attr('title','Thread abonnieren'); } if (d.msg) { var $n = $('
'+d.msg+'
').appendTo('body'); setTimeout(function(){$n.remove();},3000); } }, function() { $btn.prop('disabled', false); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Profil-Sichtbarkeit ══════════════════════════════════════════════════════════ */ $(document).on('click', '#wbfToggleProfileVis', function() { var $btn = $(this).prop('disabled', true); wbfPost('wbf_toggle_profile_visibility', {}, function(d) { $btn.prop('disabled', false).data('state', d.public); if (d.public) { $btn.addClass('wbf-btn--primary').html(' Öffentlich'); } else { $btn.removeClass('wbf-btn--primary').html(' Privat'); } if (d.msg) { var $n = $('
'+d.msg+'
').appendTo('body'); setTimeout(function(){$n.remove();},3000); } }, function() { $btn.prop('disabled', false); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: DSGVO Konto-Löschung ══════════════════════════════════════════════════════════ */ $(document).on('click', '#wbfGdprSubmit', function () { var $btn = $(this); var password = $('#wbfGdprPassword').val(); var confirmed = $('#wbfGdprConfirm').is(':checked'); var $msg = $('#wbfGdprMsg'); if (!password) { showMsg($msg, 'Bitte Passwort eingeben.', false); return; } if (!confirmed) { showMsg($msg, 'Bitte Bestätigungs-Checkbox anhaken.', false); return; } if (!confirm('Letzter Schritt: Konto wirklich unwiderruflich löschen?')) return; $btn.prop('disabled', true).html(' Wird gelöscht…'); wbfPost('wbf_delete_account', { password: password, confirm: '1' }, function (d) { // Erfolgreich — kurze Meldung, dann Weiterleitung $('#wbfGdprBox').html( '

' + (d.message || 'Konto gelöscht.') + '

' ); setTimeout(function () { window.location.href = d.redirect || WBF.forum_url || '/'; }, 2500); }, function (d) { showMsg($msg, d.message || 'Fehler.', false); $btn.prop('disabled', false).html(' Konto endgültig löschen'); }); }); /* ══════════════════════════════════════════════════════════ FEATURE: Spam-Schutz — Formzeit + Honeypot ══════════════════════════════════════════════════════════ */ // Sende Honeypot + Zeitstempel mit Registrierung $(document).on('click', '.wbf-reg-submit-btn', function() { var $box = $(this).closest('.wbf-auth-box'); $box.find('[name="wbf_website"]').val(''); // Honeypot immer leer lassen }); /* ══════════════════════════════════════════════════════════ FIX: Modal Teleport — verschiebe alle Modals zu damit kein Stacking-Context (sticky/transform) das position:fixed Overlay blockieren kann. ══════════════════════════════════════════════════════════ */ $(function() { // CSS-Variablen aus .wbf-wrap auf die teleportierten Modals übertragen var wrapStyle = document.querySelector('.wbf-wrap'); $('.wbf-modal').each(function() { var $modal = $(this); // Klone den computed style für CSS-Variablen if (wrapStyle) { var vars = [ '--c-surface','--c-primary','--c-primary-l','--c-accent', '--c-text','--c-text-dim','--c-muted','--c-border', '--c-danger','--c-green','--c-warning','--radius','--radius-sm', '--c-bg','--c-bg2','--c-surface2' ]; vars.forEach(function(v) { var val = getComputedStyle(wrapStyle).getPropertyValue(v); if (val) $modal[0].style.setProperty(v, val.trim()); }); } $modal.appendTo('body'); }); }); /* ── E-Mail-Adresse ändern ──────────────────────────────────────────── */ $(document).on('click', '#wbfSaveEmail', function () { var $btn = $(this); var email = $('#wbfNewEmail').val().trim(); var password = $('#wbfEmailPassword').val(); var $msg = $('#wbfEmailMsg'); if (!email) { $msg.removeClass('wbf-ok').addClass('wbf-err').text('Bitte E-Mail eingeben.'); return; } if (!password) { $msg.removeClass('wbf-ok').addClass('wbf-err').text('Bitte Passwort eingeben.'); return; } $btn.prop('disabled', true); wbfPost('wbf_change_email', { new_email: email, password: password }, function (d) { $msg.removeClass('wbf-err').addClass('wbf-ok').text(d.message || 'E-Mail geaendert.'); $('#wbfNewEmail').val(''); $('#wbfEmailPassword').val(''); $btn.prop('disabled', false); }, function (d) { $msg.removeClass('wbf-ok').addClass('wbf-err').text(d.message || 'Fehler.'); $btn.prop('disabled', false); }); }); /* ── Toggle-Switch (Notification Prefs) ─────────────────────────────── */ $(document).on('click', '.wbf-toggle', function () { var $t = $(this); var on = String($t.data('state')) === '1'; var val = on ? '0' : '1'; $t.data('state', val).attr('data-state', val); if (val === '1') { $t.addClass('wbf-toggle--on'); } else { $t.removeClass('wbf-toggle--on'); } }); /* ── Benachrichtigungs-Einstellungen speichern ───────────────────────── */ $(document).on('click', '#wbfSaveNotifPrefs', function () { var $btn = $(this); var $msg = $('#wbfNotifPrefsMsg'); $btn.prop('disabled', true); wbfPost('wbf_save_notification_prefs', { notify_reply: String($('#wbfNotifReply').data('state')) === '1' ? '1' : '0', notify_mention: String($('#wbfNotifMention').data('state')) === '1' ? '1' : '0', notify_message: String($('#wbfNotifMessage').data('state')) === '1' ? '1' : '0' }, function (d) { $msg.removeClass('wbf-err').addClass('wbf-ok').text(d.message || 'Gespeichert!'); $btn.prop('disabled', false); }, function (d) { $msg.removeClass('wbf-ok').addClass('wbf-err').text(d.message || 'Fehler.'); $btn.prop('disabled', false); }); }); /* ── Lesezeichen ────────────────────────────────────────────────────── */ $(document).on('click', '.wbf-bookmark-btn', function () { var $btn = $(this); var threadId = $btn.data('thread'); wbfPost('wbf_toggle_bookmark', { thread_id: threadId }, function (d) { if (d.bookmarked) { $btn.addClass('wbf-bookmarked').attr('title', 'Lesezeichen entfernen'); $btn.find('i').removeClass('far').addClass('fas'); } else { $btn.removeClass('wbf-bookmarked').attr('title', 'Lesezeichen hinzufügen'); $btn.find('i').removeClass('fas').addClass('far'); } }); }); /* ── Nutzer ignorieren / Ignorierung aufheben ────────────────────────── */ $(document).on('click', '.wbf-ignore-btn', function () { var $btn = $(this); var ignoredId = parseInt($btn.data('id'), 10); var name = $btn.data('name') || 'diesen Nutzer'; var isIgnored = String($btn.data('ignored')) === '1'; // Bestätigung nur beim Ignorieren, nicht beim Entblocken if (!isIgnored) { if (!confirm(name + ' ignorieren?\n\nDessen Beiträge werden in Threads ausgeblendet und DMs werden blockiert.')) { return; } } $btn.prop('disabled', true); wbfPost('wbf_toggle_ignore', { ignored_id: ignoredId }, function (d) { var nowIgnored = d.ignored; // Alle Buttons mit dieser User-ID auf der Seite aktualisieren $('.wbf-ignore-btn[data-id="' + ignoredId + '"]').each(function () { var $b = $(this); $b.data('ignored', nowIgnored ? '1' : '0'); $b.attr('data-ignored', nowIgnored ? '1' : '0'); // Icon + Label aktualisieren $b.find('i').attr('class', 'fas fa-' + (nowIgnored ? 'eye' : 'eye-slash')); // Button-Variante (Post-Footer, klein ohne wbf-btn) if (!$b.hasClass('wbf-btn')) { $b.text(''); $b.append(' ' + (nowIgnored ? 'Entblocken' : 'Ignorieren')); } else { // Profil-Variante mit wbf-btn $b.html(' ' + (nowIgnored ? 'Ignorierung aufheben' : 'Nutzer ignorieren')); } $b.prop('disabled', false); }); // Posts des Users auf der aktuellen Seite ein-/ausblenden $('.wbf-post, .wbf-post--op').each(function () { var $post = $(this); // Buttons innerhalb dieses Posts mit der User-ID suchen var $ib = $post.find('.wbf-ignore-btn[data-id="' + ignoredId + '"]'); if (!$ib.length) return; if (nowIgnored) { // Ignoriert → Overlay zeigen wenn noch nicht vorhanden if (!$post.find('.wbf-ignored-bar').length) { var barHtml = '
' + ' Beitrag von ignoriertem Nutzer: ' + $('').text(name).html() + '' + '' + '
' + '