This commit is contained in:
ddrwode
2026-02-10 18:34:03 +08:00
parent 1f03f175f6
commit 41be920f59

View File

@@ -0,0 +1,113 @@
// Forum post detail interactions:
// - Track CTA/related/recommendation interactions
// - Track comment submissions
// - Smooth-scroll for in-page comment jump links
(function () {
'use strict';
var TRACK_ENDPOINT = '/api/event/track';
var bodyEl = document.body;
if (!bodyEl) {
return;
}
var rawPostId = bodyEl.getAttribute('data-post-id');
var parsedPostId = Number(rawPostId);
var postId = Number.isFinite(parsedPostId) ? parsedPostId : null;
function normalizeLabel(value) {
return String(value || '')
.trim()
.replace(/\s+/g, ' ')
.slice(0, 120);
}
function sendTrack(eventName, label) {
var normalizedName = String(eventName || '').trim().toLowerCase();
if (!normalizedName) {
return;
}
var payload = {
event_name: normalizedName,
label: normalizeLabel(label),
post_id: postId,
page_path: (window.location && window.location.pathname) || ''
};
var payloadText = JSON.stringify(payload);
if (navigator.sendBeacon) {
try {
var ok = navigator.sendBeacon(
TRACK_ENDPOINT,
new Blob([payloadText], { type: 'application/json' })
);
if (ok) {
return;
}
} catch (err) {
// Fallback to fetch below.
}
}
fetch(TRACK_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin',
keepalive: true,
body: payloadText
}).catch(function () {
// Silent failure: tracking should never block UX.
});
}
function resolveTrackNode(target) {
if (!target || typeof target.closest !== 'function') {
return null;
}
return target.closest('[data-track-event]');
}
document.addEventListener('click', function (evt) {
var node = resolveTrackNode(evt.target);
if (!node) {
return;
}
var eventName = node.getAttribute('data-track-event');
var label = node.getAttribute('data-track-label') || node.textContent || '';
sendTrack(eventName, label);
});
var commentForm = document.querySelector('form.comment-form');
if (commentForm) {
commentForm.addEventListener('submit', function () {
sendTrack('post_detail_comment_submit', 'comment_form');
});
}
var reducedMotionQuery = null;
if (typeof window.matchMedia === 'function') {
reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
}
var enableSmoothScroll = !(reducedMotionQuery && reducedMotionQuery.matches);
if (!enableSmoothScroll) {
return;
}
var jumpLinks = document.querySelectorAll('a[href="#comments-panel"]');
if (!jumpLinks.length) {
return;
}
jumpLinks.forEach(function (link) {
link.addEventListener('click', function () {
var panel = document.getElementById('comments-panel');
if (!panel) {
return;
}
window.setTimeout(function () {
panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, 0);
});
});
})();