ghost rider
This commit is contained in:
+224
-61
@@ -972,12 +972,53 @@ window.cancelAnimFrame = (function () {
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent left-click navigation on timestamp links
|
||||
const fallbackCopy = (text, msg) => {
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = text;
|
||||
textarea.style.position = "fixed";
|
||||
textarea.style.left = "-9999px";
|
||||
textarea.style.top = "0";
|
||||
document.body.appendChild(textarea);
|
||||
textarea.focus();
|
||||
textarea.select();
|
||||
try {
|
||||
document.execCommand("copy");
|
||||
if (typeof window.flashMessage === 'function') {
|
||||
window.flashMessage(msg);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Fallback copy failed:", err);
|
||||
}
|
||||
document.body.removeChild(textarea);
|
||||
};
|
||||
|
||||
const copyCurrentUrl = () => {
|
||||
const url = window.location.href;
|
||||
const msg = (window.f0ckI18n && window.f0ckI18n.copied) || 'URL copied to clipboard';
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(url).then(() => {
|
||||
if (typeof window.flashMessage === 'function') {
|
||||
window.flashMessage(msg);
|
||||
}
|
||||
}).catch(() => {
|
||||
fallbackCopy(url, msg);
|
||||
});
|
||||
} else {
|
||||
fallbackCopy(url, msg);
|
||||
}
|
||||
};
|
||||
window.copyCurrentUrl = copyCurrentUrl;
|
||||
|
||||
// Left-click on timestamp copies the current URL to clipboard and shows toast (same as pressing "y")
|
||||
document.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.timestamp-link')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
const tsTarget = e.target.closest('.timestamp-link, time.timeago');
|
||||
if (tsTarget) {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
copyCurrentUrl();
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
@@ -5492,26 +5533,7 @@ window.cancelAnimFrame = (function () {
|
||||
"i": clickOnElementBinding("a#a_addtag"),
|
||||
"l": () => window.toggleBackground(),
|
||||
"y": () => {
|
||||
const url = window.location.href;
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(url).then(() => window.flashMessage('URL copied to clipboard'));
|
||||
} else {
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = url;
|
||||
textarea.style.position = "fixed";
|
||||
textarea.style.left = "-9999px";
|
||||
textarea.style.top = "0";
|
||||
document.body.appendChild(textarea);
|
||||
textarea.focus();
|
||||
textarea.select();
|
||||
try {
|
||||
document.execCommand("copy");
|
||||
window.flashMessage((window.f0ckI18n && window.f0ckI18n.copied) || 'URL copied to clipboard');
|
||||
} catch (err) {
|
||||
console.error("Fallback copy failed:", err);
|
||||
}
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
copyCurrentUrl();
|
||||
},
|
||||
" ": () => {
|
||||
if (video && typeof video.play === 'function') { // Check if video wrapper exists/is valid
|
||||
@@ -7683,8 +7705,8 @@ window.cancelAnimFrame = (function () {
|
||||
document.querySelector('.messages-convo-page')
|
||||
);
|
||||
const sel = hasDedicatedWrapper
|
||||
? '.index-layout-wrapper, .meme-layout-wrapper, .messages-convo-page, .pagination-container-fluid'
|
||||
: '.pagination-container-fluid, .pagewrapper';
|
||||
? '.index-layout-wrapper, .meme-layout-wrapper, .messages-convo-page, .pagination-container-fluid, .admin-bar'
|
||||
: '.pagination-container-fluid, .pagewrapper, .admin-bar';
|
||||
return document.querySelectorAll(sel);
|
||||
};
|
||||
|
||||
@@ -7705,10 +7727,10 @@ window.cancelAnimFrame = (function () {
|
||||
const wrappers = getSidebarWrappers();
|
||||
if (animateWrappers) {
|
||||
wrappers.forEach(w => {
|
||||
const isPagination = w.classList.contains('pagination-container-fluid');
|
||||
const isRightEdge = w.classList.contains('pagination-container-fluid') || w.classList.contains('admin-bar');
|
||||
const isMessages = w.classList.contains('messages-convo-page');
|
||||
|
||||
const prop = (isPagination || isMessages) ? 'right' : 'padding-right';
|
||||
const prop = (isRightEdge || isMessages) ? 'right' : 'padding-right';
|
||||
const targetVal = isHidden ? sidebarWidth + 'px' : '0px';
|
||||
|
||||
w.style.setProperty('transition', `${prop} 0.3s ease-in-out`, 'important');
|
||||
@@ -11166,6 +11188,82 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const reportUserInput = document.getElementById('report-user-id');
|
||||
const reportReason = document.getElementById('report-reason');
|
||||
const reportError = document.getElementById('report-error');
|
||||
let _reportRcWidgetId = null;
|
||||
|
||||
const showReportError = (msg, targetEl) => {
|
||||
if (!reportError) return;
|
||||
reportError.innerHTML = '';
|
||||
const icon = document.createElement('i');
|
||||
icon.className = 'fa fa-circle-exclamation';
|
||||
icon.style.marginRight = '6px';
|
||||
reportError.appendChild(icon);
|
||||
reportError.appendChild(document.createTextNode(' ' + msg));
|
||||
reportError.style.display = 'block';
|
||||
|
||||
if (targetEl) {
|
||||
targetEl.classList.remove('field-error');
|
||||
void targetEl.offsetWidth; // Force reflow to re-trigger CSS shake animation
|
||||
targetEl.classList.add('field-error');
|
||||
if (typeof targetEl.focus === 'function') {
|
||||
try { targetEl.focus(); } catch (e) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const clearReportError = () => {
|
||||
if (reportError) {
|
||||
reportError.innerHTML = '';
|
||||
reportError.style.display = 'none';
|
||||
}
|
||||
if (reportReason) reportReason.classList.remove('field-error');
|
||||
const rcEl = document.getElementById('modal-report-recaptcha');
|
||||
if (rcEl) rcEl.classList.remove('field-error');
|
||||
};
|
||||
|
||||
if (reportReason) {
|
||||
reportReason.addEventListener('input', () => {
|
||||
if (reportReason.value.trim()) {
|
||||
reportReason.classList.remove('field-error');
|
||||
const rcEl = document.getElementById('modal-report-recaptcha');
|
||||
if (!rcEl || !rcEl.classList.contains('field-error')) {
|
||||
clearReportError();
|
||||
}
|
||||
}
|
||||
});
|
||||
reportReason.addEventListener('keydown', (e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
const submitBtn = document.getElementById('report-submit');
|
||||
if (submitBtn && !submitBtn.disabled) submitBtn.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.renderReportRecaptcha = function() {
|
||||
const rcEl = document.getElementById('modal-report-recaptcha');
|
||||
if (!rcEl || !window.grecaptcha || typeof grecaptcha.render !== 'function') return;
|
||||
if (_reportRcWidgetId !== null) {
|
||||
try { grecaptcha.reset(_reportRcWidgetId); } catch(e) {}
|
||||
} else {
|
||||
const sitekey = rcEl.dataset.sitekey || (window.f0ckConfig && window.f0ckConfig.recaptcha_site_key);
|
||||
if (sitekey) {
|
||||
try {
|
||||
_reportRcWidgetId = grecaptcha.render(rcEl, {
|
||||
sitekey: sitekey,
|
||||
theme: 'dark',
|
||||
callback: function() {
|
||||
rcEl.classList.remove('field-error');
|
||||
if (!reportReason || !reportReason.classList.contains('field-error')) {
|
||||
clearReportError();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch(e) {
|
||||
console.warn('[REPORT] Failed to render recaptcha:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Open item report
|
||||
document.addEventListener('click', (e) => {
|
||||
@@ -11176,9 +11274,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
reportCommentInput.value = '';
|
||||
reportUserInput.value = '';
|
||||
reportReason.value = '';
|
||||
reportError.textContent = '';
|
||||
clearReportError();
|
||||
reportModal.style.display = 'flex';
|
||||
document.body.classList.add('modal-open');
|
||||
setTimeout(() => { try { reportReason.focus(); } catch(err){} }, 50);
|
||||
if (window.renderReportRecaptcha) window.renderReportRecaptcha();
|
||||
}
|
||||
|
||||
const commentBtn = e.target.closest('.report-comment-btn');
|
||||
@@ -11188,9 +11288,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
reportCommentInput.value = commentBtn.dataset.id;
|
||||
reportUserInput.value = '';
|
||||
reportReason.value = '';
|
||||
reportError.textContent = '';
|
||||
clearReportError();
|
||||
reportModal.style.display = 'flex';
|
||||
document.body.classList.add('modal-open');
|
||||
setTimeout(() => { try { reportReason.focus(); } catch(err){} }, 50);
|
||||
if (window.renderReportRecaptcha) window.renderReportRecaptcha();
|
||||
}
|
||||
|
||||
const userBtn = e.target.closest('.report-user-btn'); // for future
|
||||
@@ -11200,32 +11302,58 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
reportCommentInput.value = '';
|
||||
reportUserInput.value = userBtn.dataset.userId;
|
||||
reportReason.value = '';
|
||||
reportError.textContent = '';
|
||||
clearReportError();
|
||||
reportModal.style.display = 'flex';
|
||||
document.body.classList.add('modal-open');
|
||||
setTimeout(() => { try { reportReason.focus(); } catch(err){} }, 50);
|
||||
if (window.renderReportRecaptcha) window.renderReportRecaptcha();
|
||||
}
|
||||
|
||||
// Close logic
|
||||
if (e.target.matches('#report-cancel') || e.target.id === 'report-modal') {
|
||||
reportModal.style.display = 'none';
|
||||
document.body.classList.remove('modal-open');
|
||||
clearReportError();
|
||||
if (_reportRcWidgetId !== null && window.grecaptcha) {
|
||||
try { grecaptcha.reset(_reportRcWidgetId); } catch(e) {}
|
||||
}
|
||||
}
|
||||
|
||||
// Submit logic
|
||||
if (e.target.matches('#report-submit')) {
|
||||
clearReportError();
|
||||
const reason = reportReason.value.trim();
|
||||
if (!reason) {
|
||||
reportError.textContent = (window.f0ckI18n && window.f0ckI18n.reason_required) || 'Please provide a reason.';
|
||||
showReportError((window.f0ckI18n && window.f0ckI18n.reason_required) || 'Please provide a reason.', reportReason);
|
||||
return;
|
||||
}
|
||||
|
||||
const rcEl = document.getElementById('modal-report-recaptcha');
|
||||
let rcToken = '';
|
||||
if (rcEl) {
|
||||
if (_reportRcWidgetId === null || !window.grecaptcha) {
|
||||
showReportError((window.f0ckI18n && window.f0ckI18n.captcha_loading) || 'CAPTCHA is still loading. Please wait a moment.', rcEl);
|
||||
return;
|
||||
}
|
||||
rcToken = grecaptcha.getResponse(_reportRcWidgetId);
|
||||
if (!rcToken) {
|
||||
showReportError((window.f0ckI18n && window.f0ckI18n.captcha_required) || 'Please complete the CAPTCHA.', rcEl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const payload = new URLSearchParams();
|
||||
if (reportItemInput.value) payload.append('item_id', reportItemInput.value);
|
||||
if (reportCommentInput.value) payload.append('comment_id', reportCommentInput.value);
|
||||
if (reportUserInput.value) payload.append('reported_user_id', reportUserInput.value);
|
||||
payload.append('reason', reason);
|
||||
if (rcToken) payload.append('g-recaptcha-response', rcToken);
|
||||
|
||||
const submitBtn = e.target;
|
||||
const originalBtnText = submitBtn.innerHTML;
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.innerHTML = '<i class="fa fa-spinner fa-spin" style="margin-right: 5px;"></i>' + ((window.f0ckI18n && window.f0ckI18n.processing) || 'Processing...');
|
||||
|
||||
e.target.disabled = true;
|
||||
fetch('/api/v2/report', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
@@ -11235,20 +11363,28 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
reportModal.style.display = 'none';
|
||||
document.body.classList.remove('modal-open');
|
||||
clearReportError();
|
||||
if (window.showFlash) window.showFlash((window.f0ckI18n && window.f0ckI18n.report_success) || 'Report submitted successfully.', 'success');
|
||||
// Reset fields for future reports
|
||||
reportReason.value = '';
|
||||
} else {
|
||||
reportError.textContent = data.msg || (window.f0ckI18n && window.f0ckI18n.report_error) || 'An error occurred.';
|
||||
if (window.showFlash) window.showFlash(data.msg || (window.f0ckI18n && window.f0ckI18n.report_error) || 'An error occurred.', 'error');
|
||||
const errMsg = data.msg || (window.f0ckI18n && window.f0ckI18n.report_error) || 'An error occurred.';
|
||||
showReportError(errMsg);
|
||||
if (window.showFlash) window.showFlash(errMsg, 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
reportError.textContent = (window.f0ckI18n && window.f0ckI18n.network_error) || 'Network error.';
|
||||
if (window.showFlash) window.showFlash((window.f0ckI18n && window.f0ckI18n.network_error) || 'Network error.', 'error');
|
||||
const errMsg = (window.f0ckI18n && window.f0ckI18n.network_error) || 'Network error.';
|
||||
showReportError(errMsg);
|
||||
if (window.showFlash) window.showFlash(errMsg, 'error');
|
||||
})
|
||||
.finally(() => {
|
||||
e.target.disabled = false;
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.innerHTML = originalBtnText;
|
||||
if (_reportRcWidgetId !== null && window.grecaptcha) {
|
||||
try { grecaptcha.reset(_reportRcWidgetId); } catch(e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -12585,9 +12721,9 @@ document.addEventListener('click', (e) => {
|
||||
visSaveBtn.textContent = origText;
|
||||
if (data.success) {
|
||||
const visVal = parseInt(data.visibility, 10);
|
||||
const titles = ['Public', 'Unlisted', 'Private'];
|
||||
const icons = ['fa-globe', 'fa-link', 'fa-lock'];
|
||||
const colors = ['var(--color-success, #00C851)', 'var(--color-warning, #ffbb33)', 'var(--color-danger, #ff4444)'];
|
||||
const titles = ['Public', 'Unlisted', 'Private', 'Unavailable'];
|
||||
const icons = ['fa-globe', 'fa-link', 'fa-lock', 'fa-ban'];
|
||||
const colors = ['var(--color-success, #00C851)', 'var(--color-warning, #ffbb33)', 'var(--color-danger, #ff4444)', 'var(--color-danger, #ff4444)'];
|
||||
|
||||
const visBtn = document.getElementById('a_visibility');
|
||||
if (visBtn) {
|
||||
@@ -12595,6 +12731,14 @@ document.addEventListener('click', (e) => {
|
||||
visBtn.setAttribute('title', `Visibility: ${titles[visVal]} (Click to change)`);
|
||||
}
|
||||
|
||||
const unavBtn = document.getElementById('a_unavailable');
|
||||
if (unavBtn) {
|
||||
unavBtn.dataset.visibility = visVal;
|
||||
unavBtn.classList.toggle('active', visVal === 3);
|
||||
unavBtn.style.color = visVal === 3 ? 'var(--danger, #ff4444)' : '';
|
||||
unavBtn.setAttribute('title', visVal === 3 ? 'Make Available (Public)' : 'Make Unavailable (451)');
|
||||
}
|
||||
|
||||
const infoVisBtn = document.getElementById('info-visibility-edit-btn');
|
||||
if (infoVisBtn) {
|
||||
infoVisBtn.dataset.visibility = visVal;
|
||||
@@ -12627,8 +12771,9 @@ document.addEventListener('click', (e) => {
|
||||
const saveBtn = e.target.closest('#info-title-save');
|
||||
if (saveBtn) {
|
||||
e.preventDefault();
|
||||
const input = document.getElementById('info-title-input');
|
||||
const status = document.getElementById('info-title-status');
|
||||
const container = saveBtn.closest('.item_title') || document;
|
||||
const input = container.querySelector('#info-title-input') || document.getElementById('info-title-input');
|
||||
const status = container.querySelector('#info-title-status') || document.getElementById('info-title-status');
|
||||
if (!input) return;
|
||||
|
||||
const itemId = input.dataset.itemId;
|
||||
@@ -12652,25 +12797,27 @@ document.addEventListener('click', (e) => {
|
||||
saveBtn.disabled = false;
|
||||
saveBtn.innerHTML = origIcon;
|
||||
if (data.success) {
|
||||
// Update the live .item_title bar below the ID bar
|
||||
const titleBar = document.querySelector('.item_title');
|
||||
if (titleBar) {
|
||||
titleBar.textContent = data.title || '';
|
||||
} else if (data.title) {
|
||||
// Fallback: create it if somehow missing (e.g. enable_item_title was toggled)
|
||||
const idBar = document.querySelector('.item-main-content > ._204863');
|
||||
if (idBar) {
|
||||
const newBar = document.createElement('div');
|
||||
newBar.className = 'item_title';
|
||||
newBar.textContent = data.title;
|
||||
idBar.insertAdjacentElement('afterend', newBar);
|
||||
}
|
||||
// Keep input form intact and update its value
|
||||
input.value = data.title || '';
|
||||
|
||||
// Update any plain-text title display element
|
||||
const textEl = container.querySelector('.item_title_text') || document.querySelector('.item_title_text');
|
||||
if (textEl) {
|
||||
textEl.textContent = data.title || '';
|
||||
}
|
||||
|
||||
// Invalidate cache so navigating next/prev fetches fresh HTML from server
|
||||
if (window.invalidateItemCache) {
|
||||
window.invalidateItemCache(itemId);
|
||||
}
|
||||
|
||||
if (status) {
|
||||
status.textContent = '✓ Saved';
|
||||
status.style.color = 'var(--accent, #5cb85c)';
|
||||
status.style.display = 'inline';
|
||||
setTimeout(() => { status.style.display = 'none'; }, 2000);
|
||||
status.style.display = 'none';
|
||||
status.textContent = '';
|
||||
}
|
||||
|
||||
if (window.flashMessage) {
|
||||
window.flashMessage('Title saved', 2000, 'success');
|
||||
}
|
||||
} else {
|
||||
if (status) {
|
||||
@@ -12678,6 +12825,9 @@ document.addEventListener('click', (e) => {
|
||||
status.style.color = '#e84040';
|
||||
status.style.display = 'inline';
|
||||
}
|
||||
if (window.flashMessage) {
|
||||
window.flashMessage('Error while saving Title', 3000, 'error');
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -12688,6 +12838,9 @@ document.addEventListener('click', (e) => {
|
||||
status.style.color = '#e84040';
|
||||
status.style.display = 'inline';
|
||||
}
|
||||
if (window.flashMessage) {
|
||||
window.flashMessage('Error while saving Title', 3000, 'error');
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -12823,6 +12976,16 @@ document.addEventListener('click', (e) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Enter key on title input
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && e.target && e.target.id === 'info-title-input') {
|
||||
e.preventDefault();
|
||||
const container = e.target.closest('.item_title') || document;
|
||||
const saveBtn = container.querySelector('#info-title-save') || document.getElementById('info-title-save');
|
||||
if (saveBtn) saveBtn.click();
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure any navigation event restores the scroll state
|
||||
window.addEventListener('pjax:start', () => {
|
||||
if (window.resetGlobalScrollState) window.resetGlobalScrollState();
|
||||
|
||||
Reference in New Issue
Block a user