diff --git a/assets/css/forum-style.css b/assets/css/forum-style.css index df65f02..c553c54 100644 --- a/assets/css/forum-style.css +++ b/assets/css/forum-style.css @@ -163,6 +163,17 @@ color: var(--c-text-dim); } .wbf-btn--outline:hover { border-color: var(--c-primary); color: var(--c-primary); } +.wbf-btn--outline-poll { + background: rgba(251,191,36,.08); + border-color: rgba(251,191,36,.35); + color: #fbbf24; +} +.wbf-btn--outline-poll:hover { + background: rgba(251,191,36,.18); + border-color: #fbbf24; + color: #fbbf24; + box-shadow: 0 0 12px rgba(251,191,36,.25); +} .wbf-btn--sm { padding: .35rem .75rem; font-size: .78rem; } .wbf-btn--full { width: 100%; justify-content: center; padding: .7rem; } .wbf-btn:disabled { opacity: .45; cursor: not-allowed; } @@ -622,6 +633,9 @@ .wbf-form-row input[type="text"], .wbf-form-row input[type="email"], .wbf-form-row input[type="password"], +.wbf-form-row input[type="url"], +.wbf-form-row input[type="number"], +.wbf-form-row input[type="datetime-local"], .wbf-form-row textarea, .wbf-form-row select { width: 100%; @@ -632,6 +646,15 @@ font-family: inherit; font-size: .875rem; color: var(--c-text); transition: var(--transition); + box-sizing: border-box; + color-scheme: dark; +} +.wbf-form-row input[type="datetime-local"]::-webkit-calendar-picker-indicator { + filter: invert(1) opacity(.5); + cursor: pointer; +} +.wbf-form-row input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover { + filter: invert(1) opacity(1); } .wbf-form-row input::placeholder, .wbf-form-row textarea::placeholder { color: var(--c-muted); } @@ -639,6 +662,22 @@ .wbf-form-row textarea:focus, .wbf-form-row select:focus { outline: none; border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(0,180,216,.12); background: var(--c-bg); } .wbf-form-row select option { background: var(--c-surface2); color: var(--c-text); } +/* Custom profile field inputs */ +.wbf-cf-input { + display: block; + width: 100%; + background: var(--c-bg2); + border: 1.5px solid var(--c-border-d); + border-radius: var(--radius-sm); + padding: .6rem .85rem; + font-family: inherit; font-size: .875rem; + color: var(--c-text); + transition: var(--transition); + box-sizing: border-box; +} +.wbf-cf-input::placeholder { color: var(--c-muted); } +.wbf-cf-input:focus { outline: none; border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(0,180,216,.12); background: var(--c-bg); } +select.wbf-cf-input option { background: var(--c-surface2); color: var(--c-text); } /* ── Auth tabs ──────────────────────────────────────────────── */ .wbf-auth-tabs { display: flex; gap: .4rem; margin-bottom: 1rem; } @@ -655,33 +694,47 @@ .wbf-auth-panel.active { display: block; } /* ── Modal ──────────────────────────────────────────────────── */ +/* Modals are teleported to by JS — so no stacking-context issues */ .wbf-modal { position: fixed; inset: 0; - background: rgba(0,0,0,.75); - backdrop-filter: blur(5px); - z-index: 9999; + background: rgba(0,0,0,.82); + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); + z-index: 999999; display: flex; align-items: center; justify-content: center; - opacity: 0; pointer-events: none; transition: opacity .25s; padding: 1rem; + opacity: 0; pointer-events: none; + transition: opacity .22s ease; + padding: 1rem; } .wbf-modal.active { opacity: 1; pointer-events: all; } .wbf-modal__box { - background: var(--c-surface); - border: 1px solid rgba(0,180,216,.25); - border-radius: var(--radius); + background: var(--c-surface, #1e2330); + border: 1px solid rgba(0,180,216,.3); + border-radius: var(--radius, 10px); padding: 1.75rem; width: 100%; max-width: 440px; - box-shadow: var(--shadow-lg), 0 0 40px rgba(0,180,216,.08); + box-shadow: 0 24px 60px rgba(0,0,0,.8), 0 0 0 1px rgba(0,180,216,.1); position: relative; - transform: translateY(16px) scale(.98); transition: transform .25s; + transform: translateY(18px) scale(.97); + transition: transform .22s ease; + overflow: hidden; +} +.wbf-modal__box::before { + content: ''; + position: absolute; top: 0; left: 0; right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, #00b4d8, transparent); } .wbf-modal.active .wbf-modal__box { transform: translateY(0) scale(1); } -.wbf-modal__box--lg { max-width: 640px; } +.wbf-modal__box--lg { max-width: 680px; } .wbf-modal__close { position: absolute; top: .75rem; right: .9rem; - background: none; border: none; font-size: 1.4rem; - cursor: pointer; color: var(--c-muted); line-height: 1; padding: .2rem .4rem; + background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.1); + border-radius: 6px; font-size: 1.1rem; + cursor: pointer; color: var(--c-muted); line-height: 1; + padding: .25rem .5rem; transition: all .15s; } -.wbf-modal__close:hover { color: var(--c-text); } +.wbf-modal__close:hover { background: rgba(255,255,255,.12); color: var(--c-text); } /* ── Misc ───────────────────────────────────────────────────── */ .wbf-msg { font-size: .8rem; margin-left: .6rem; } @@ -2602,4 +2655,180 @@ @media (max-width: 480px) { .wbf-members-grid { grid-template-columns: repeat(2, 1fr); } +} +/* ════════════════════════════════════════════════════════════ + THREAD HOVER PREVIEW TOOLTIP + ════════════════════════════════════════════════════════════ */ +.wbf-thread-preview-tip { + position: absolute; + z-index: 9999; + max-width: 360px; + padding: .6rem .85rem; + background: var(--c-surface); + border: 1px solid var(--c-border-d); + border-radius: var(--radius-sm); + box-shadow: 0 8px 24px rgba(0,0,0,.35); + font-size: .8rem; + line-height: 1.55; + color: var(--c-text-dim); + pointer-events: none; + opacity: 0; + transform: translateY(4px); + transition: opacity .15s ease, transform .15s ease; + white-space: normal; + word-break: break-word; +} +.wbf-thread-preview-tip.visible { + opacity: 1; + transform: translateY(0); +} + +/* ════════════════════════════════════════════════════════════ + REGISTRIERUNG — DEAKTIVIERTER TAB + ════════════════════════════════════════════════════════════ */ +.wbf-auth-tab--muted { + opacity: .45; + cursor: not-allowed !important; +} +.wbf-auth-tab--muted:hover { opacity: .45; } +/* ── Forum-Regeln Seite ─────────────────────────────────── */ +.wbf-rules-body { line-height: 1.75; } +.wbf-rules-section { display: flex; align-items: center; gap: .75rem; margin: 2rem 0 .6rem; } +.wbf-rules-num { + width: 32px; height: 32px; border-radius: 50%; + background: var(--c-primary-l); color: var(--c-primary); + border: 1.5px solid rgba(0,180,216,.3); + display: flex; align-items: center; justify-content: center; + font-size: .8rem; font-weight: 800; flex-shrink: 0; +} +.wbf-rules-heading { font-size: 1rem; font-weight: 700; color: var(--c-text); margin: 0; } +.wbf-rules-para { color: var(--c-text-dim); margin: 0 0 .9rem; padding-left: .25rem; } +.wbf-rules-para strong { color: var(--c-text); } + +/* ── Umfragen (Polls) ───────────────────────────────────── */ +.wbf-poll { + background: var(--c-surface); + border: 1px solid rgba(0,180,216,.2); + border-radius: var(--radius); + margin-bottom: 1.5rem; + overflow: hidden; +} +.wbf-poll__header { + display: flex; align-items: center; gap: .6rem; + padding: .85rem 1.1rem; + background: rgba(0,180,216,.07); + border-bottom: 1px solid rgba(0,180,216,.15); + font-size: .88rem; +} +.wbf-poll__header i { color: var(--c-primary); } +.wbf-poll__title { font-weight: 700; color: var(--c-text); flex: 1; } +.wbf-poll__badge { + font-size: .68rem; font-weight: 700; padding: 2px 8px; + border-radius: 20px; + background: rgba(0,180,216,.15); color: var(--c-primary); + border: 1px solid rgba(0,180,216,.25); +} +.wbf-poll__badge--ended { + background: rgba(148,163,184,.12); color: var(--c-muted); + border-color: rgba(148,163,184,.2); +} +.wbf-poll__body { padding: 1rem 1.1rem; } +/* Voting form */ +.wbf-poll__option { + display: flex; align-items: center; gap: .6rem; + padding: .6rem .75rem; margin-bottom: .4rem; + border: 1.5px solid var(--c-border-d); + border-radius: var(--radius-sm); + cursor: pointer; font-size: .875rem; + transition: border-color .15s, background .15s; +} +.wbf-poll__option:hover { border-color: var(--c-primary); background: var(--c-primary-l); } +/* Results */ +.wbf-poll__result { + position: relative; overflow: hidden; + border-radius: var(--radius-sm); margin-bottom: .4rem; + border: 1.5px solid var(--c-border-d); + background: var(--c-bg2); + min-height: 40px; +} +.wbf-poll__result--mine { border-color: rgba(0,180,216,.4); } +.wbf-poll__result-bar { + position: absolute; top: 0; left: 0; bottom: 0; + background: var(--c-primary-l); + transition: width .5s ease; + border-radius: var(--radius-sm); +} +.wbf-poll__result--mine .wbf-poll__result-bar { background: rgba(0,180,216,.18); } +.wbf-poll__result-content { + position: relative; z-index: 1; + display: flex; align-items: center; + justify-content: space-between; + padding: .55rem .85rem; font-size: .875rem; +} +.wbf-poll__result-label { color: var(--c-text); } +.wbf-poll__result-pct { font-weight: 700; color: var(--c-primary); font-size: .82rem; white-space: nowrap; } +.wbf-poll__footer { + margin-top: .75rem; font-size: .78rem; + color: var(--c-muted); display: flex; align-items: center; gap: .4rem; +} +/* Poll option builder rows in modal */ +.wbf-poll-opt-row { + display: flex; gap: .4rem; margin-bottom: .4rem; +} +.wbf-poll-opt-row input { flex: 1; } +/* ── Forum-Regeln ────────────────────────────────────────────── */ +.wbf-rule-item { + display: flex; + gap: .6rem; + margin-bottom: .9rem; + padding: .6rem .85rem; + background: var(--c-bg2); + border-radius: var(--radius-sm); + border-left: 3px solid var(--c-primary); + line-height: 1.6; +} +.wbf-rule-num { + color: var(--c-primary); + font-weight: 800; + flex-shrink: 0; + min-width: 1.5rem; +} +/* ── Thread-Präfixe ──────────────────────────────────────────── */ +.wbf-prefix-badge { + display: inline-flex; + align-items: center; + padding: 1px 8px; + border-radius: 4px; + font-size: .7rem; + font-weight: 800; + letter-spacing: .04em; + text-transform: uppercase; + white-space: nowrap; + flex-shrink: 0; +} + +/* ── Lesezeichen-Button ─────────────────────────────────────── */ +.wbf-bookmark-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; height: 30px; + border: 1.5px solid var(--c-border); + border-radius: var(--radius-sm); + background: transparent; + color: var(--c-muted); + font-size: .85rem; + cursor: pointer; + transition: var(--transition); + flex-shrink: 0; +} +.wbf-bookmark-btn:hover { + border-color: #fbbf24; + color: #fbbf24; + background: rgba(251,191,36,.08); +} +.wbf-bookmark-btn.wbf-bookmarked { + border-color: #fbbf24; + color: #fbbf24; + background: rgba(251,191,36,.12); } \ No newline at end of file diff --git a/assets/js/forum-script.js b/assets/js/forum-script.js index 444e768..21e9b49 100644 --- a/assets/js/forum-script.js +++ b/assets/js/forum-script.js @@ -6,8 +6,10 @@ data.action = action; data.nonce = WBF.nonce; $.post(WBF.ajax_url, data, function (res) { - if (res.success) cb(res.data); - else if (errCb) errCb(res.data); + 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 + ')'}); }); } @@ -51,10 +53,12 @@ $(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() + 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) { @@ -68,22 +72,85 @@ /* ── Neuer Thread Modal ─────────────────────────────────────── */ window.wbfShowNewThread = function (catId) { - if (WBF.logged_in !== 'yes') { - $('#wbfAuthModal').addClass('active'); - return; - } + 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(''); - wbfPost('wbf_new_thread', { + var data = { category_id: $('#wbfThreadCat').val(), + prefix_id: $('#wbfThreadPrefix').val() || '', title: $('#wbfThreadTitle').val(), content: $('#wbfThreadContent').val(), tags: $('#wbfThreadTags').val() - }, function (d) { + }; + 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; @@ -93,6 +160,148 @@ }); }); + /* ── 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 ══════════════════════════════════════════════════════════ */ @@ -302,18 +511,24 @@ }); /* ── Profil speichern ───────────────────────────────────────── */ - $(document).on('click', '#wbfSaveProfile', function () { + $(document).on('click', '#wbfSaveProfile, #wbfSaveProfileCf', function () { var $btn = $(this).prop('disabled', true); - wbfPost('wbf_update_profile', { + var $msg = $(this).siblings('.wbf-msg').length ? $(this).siblings('.wbf-msg') : $('#wbfProfileMsg'); + var data = { display_name: $('#wbfEditName').val(), bio: $('#wbfEditBio').val(), signature: $('#wbfEditSignature').val(), new_password: $('#wbfNewPassword').val() - }, function (d) { - showMsg($('#wbfProfileMsg'), d.message, true); + }; + // Benutzerdefinierte Profilfelder 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($('#wbfProfileMsg'), d.message || 'Fehler', false); + showMsg($msg, d.message || 'Fehler', false); $btn.prop('disabled', false); }); }); @@ -1139,17 +1354,17 @@ /* ── Login: Remember-Me ─────────────────────────────────── */ $(document).on('click', '.wbf-login-submit-btn', function () { - var $btn = $(this).prop('disabled', true).html(''); + var $btn = $(this).prop('disabled', true).html(''); + var $box = $(this).closest('.wbf-auth-box'); wbfPost('wbf_login', { - username: $(this).closest('.wbf-auth-box').find('.wbf-field-username').val(), - password: $(this).closest('.wbf-auth-box').find('.wbf-field-password').val(), - remember_me: $(this).closest('.wbf-auth-box').find('.wbf-field-remember').is(':checked') ? '1' : '' + 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($btn.closest('.wbf-auth-box').find('.wbf-login-msg'), d.message || 'Fehler', false); + showMsg($box.find('.wbf-login-msg'), d.message || 'Fehler', false); $btn.prop('disabled', false).html(' Einloggen'); - }); }); @@ -1180,7 +1395,7 @@ var $summary = $bar.find('.wbf-reaction-summary'); var $picker = $bar.find('.wbf-reaction-picker'); // Rebuild summary - var order = ['👍','❤️','😂','😮','😢','😡']; + var order = (WBF.reactions && WBF.reactions.length) ? WBF.reactions : ['👍','❤️','😂','😮','😢','😡']; var html = ''; order.forEach(function(e) { if (d.counts[e]) { @@ -1567,4 +1782,181 @@ }); + + /* ══════════════════════════════════════════════════════════ + 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'); + }); + }); + + /* ── 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'); + } + }); + }); + }(jQuery)); \ No newline at end of file