fix: more edge cases

This commit is contained in:
Barış Soner Uşaklı
2025-06-10 13:36:23 -04:00
parent 0ebb31fe87
commit 32faaba0e5

View File

@@ -307,16 +307,16 @@ define('forum/topic', [
if (!ajaxify.data.showPostPreviewsOnHover || utils.isMobile()) { if (!ajaxify.data.showPostPreviewsOnHover || utils.isMobile()) {
return; return;
} }
let timeoutId = 0; let renderTimeout = 0;
let destroyed = false; let destroyed = false;
let cursorOnPreviewTooltip = false; let link = null;
const postCache = {}; const postCache = {};
function destroyTooltip() { function destroyTooltip() {
clearTimeout(timeoutId); clearTimeout(renderTimeout);
timeoutId = 0; renderTimeout = 0;
$('#post-tooltip').remove(); $('#post-tooltip').remove();
destroyed = true; destroyed = true;
cursorOnPreviewTooltip = false;
} }
function onClickOutside(ev) { function onClickOutside(ev) {
@@ -327,79 +327,72 @@ define('forum/topic', [
} }
$(window).one('action:ajaxify.start', destroyTooltip); $(window).one('action:ajaxify.start', destroyTooltip);
$('[component="topic"]').on('mouseenter', 'a[component="post/parent"], [component="post/parent/content"] a,[component="post/content"] a, [component="topic/event"] a', async function () { $('[component="topic"]').on('mouseenter', 'a[component="post/parent"], [component="post/parent/content"] a,[component="post/content"] a, [component="topic/event"] a', async function () {
const link = $(this); link = $(this);
link.removeAttr('over-tooltip');
link.one('mouseleave', function () { link.one('mouseleave', function () {
clearTimeout(renderTimeout);
renderTimeout = 0;
setTimeout(() => { setTimeout(() => {
// If the mouse leaves the link and it's not on a tooltip, destroy the tooltip after a short delay if (!link.attr('over-tooltip') && !renderTimeout) {
if (!cursorOnPreviewTooltip) {
destroyTooltip(); destroyTooltip();
} }
}, 300); }, 100);
// if mouse leaves the link before the tooltip is rendered, clear the timeout
if (timeoutId > 0) {
clearTimeout(timeoutId);
timeoutId = 0;
}
}); });
clearTimeout(renderTimeout);
destroyed = false; destroyed = false;
async function renderPost(pid) { renderTimeout = setTimeout(async () => {
const postData = postCache[pid] || await api.get(`/posts/${encodeURIComponent(pid)}/summary`); async function renderPost(pid) {
$('#post-tooltip').remove(); const postData = postCache[pid] || await api.get(`/posts/${encodeURIComponent(pid)}/summary`);
if (postData && ajaxify.data.template.topic) { $('#post-tooltip').remove();
postCache[pid] = postData; if (postData && ajaxify.data.template.topic) {
const tooltip = await app.parseAndTranslate('partials/topic/post-preview', { post: postData }); postCache[pid] = postData;
if (destroyed) { const tooltip = await app.parseAndTranslate('partials/topic/post-preview', { post: postData });
return; if (destroyed) {
return;
}
tooltip.hide().find('.timeago').timeago();
tooltip.appendTo($('body')).fadeIn(300);
const postContent = link.parents('[component="topic"]').find('[component="post/content"]').first();
const postRect = postContent.offset();
const postWidth = postContent.width();
const linkRect = link.offset();
const { top } = link.get(0).getBoundingClientRect();
const dropup = top > window.innerHeight / 2;
tooltip.on('mouseenter', function () {
link.attr('over-tooltip', 1);
});
tooltip.one('mouseleave', destroyTooltip);
$(window).off('click', onClickOutside).one('click', onClickOutside);
tooltip.css({
top: dropup ? linkRect.top - tooltip.outerHeight() : linkRect.top + 30,
left: postRect.left,
width: postWidth,
});
} }
tooltip.hide().find('.timeago').timeago();
tooltip.appendTo($('body')).fadeIn(300);
const postContent = link.parents('[component="topic"]').find('[component="post/content"]').first();
const postRect = postContent.offset();
const postWidth = postContent.width();
const linkRect = link.offset();
const { top } = link.get(0).getBoundingClientRect();
const dropup = top > window.innerHeight / 2;
tooltip.on('mouseenter', function () {
onPreviewTooltip = true;
});
tooltip.one('mouseleave', destroyTooltip);
$(window).off('click', onClickOutside).one('click', onClickOutside);
tooltip.css({
top: dropup ? linkRect.top - tooltip.outerHeight() : linkRect.top + 30,
left: postRect.left,
width: postWidth,
});
}
}
const href = link.attr('href');
const location = utils.urlToLocation(href);
const pathname = location.pathname;
const validHref = href && href !== '#' && window.location.hostname === location.hostname;
$('#post-tooltip').remove();
const postMatch = validHref && pathname && pathname.match(/\/post\/([\d]+|(?:[\w_.~!$&'()*+,;=:@-]|%[\dA-F]{2})+)/);
const topicMatch = validHref && pathname && pathname.match(/\/topic\/([\da-z-]+)/);
if (postMatch) {
const pid = postMatch[1];
if (encodeURIComponent(link.parents('[component="post"]').attr('data-pid')) === encodeURIComponent(pid)) {
return; // dont render self post
} }
timeoutId = setTimeout(async () => { const href = link.attr('href');
timeoutId = 0; const location = utils.urlToLocation(href);
const pathname = location.pathname;
const validHref = href && href !== '#' && window.location.hostname === location.hostname;
$('#post-tooltip').remove();
const postMatch = validHref && pathname && pathname.match(/\/post\/([\d]+|(?:[\w_.~!$&'()*+,;=:@-]|%[\dA-F]{2})+)/);
const topicMatch = validHref && pathname && pathname.match(/\/topic\/([\da-z-]+)/);
if (postMatch) {
const pid = postMatch[1];
if (encodeURIComponent(link.parents('[component="post"]').attr('data-pid')) === encodeURIComponent(pid)) {
return; // dont render self post
}
renderPost(pid); renderPost(pid);
}, 300); } else if (topicMatch) {
} else if (topicMatch) {
timeoutId = setTimeout(async () => {
timeoutId = 0;
const tid = topicMatch[1]; const tid = topicMatch[1];
const topicData = await api.get('/topics/' + tid, {}); const topicData = await api.get('/topics/' + tid, {});
renderPost(topicData.mainPid); renderPost(topicData.mainPid);
}, 300); }
} }, 300);
}); });
} }