comment safe guards
This commit is contained in:
@@ -4,6 +4,16 @@
|
|||||||
const _f0ckDebug = (...args) => (typeof window.f0ckDebug === 'function' ? window.f0ckDebug(...args) : void 0);
|
const _f0ckDebug = (...args) => (typeof window.f0ckDebug === 'function' ? window.f0ckDebug(...args) : void 0);
|
||||||
|
|
||||||
class CommentSystem {
|
class CommentSystem {
|
||||||
|
get isMainSubmitting() {
|
||||||
|
return this._globalState ? this._globalState.isMainSubmitting : false;
|
||||||
|
}
|
||||||
|
set isMainSubmitting(val) {
|
||||||
|
if (this._globalState) this._globalState.isMainSubmitting = val;
|
||||||
|
}
|
||||||
|
get pendingSubmissions() {
|
||||||
|
return this._globalState ? this._globalState.pendingSubmissions : new Set();
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.container = document.getElementById('comments-container');
|
this.container = document.getElementById('comments-container');
|
||||||
this.itemId = this.container ? this.container.dataset.itemId : null;
|
this.itemId = this.container ? this.container.dataset.itemId : null;
|
||||||
@@ -47,8 +57,24 @@ class CommentSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.initialLoadDone = false;
|
this.initialLoadDone = false;
|
||||||
this.pendingSubmissions = new Set();
|
|
||||||
this.isMainSubmitting = false;
|
// Retrieve or initialize global submission state for this item to survive f0ck:contentLoaded re-inits
|
||||||
|
if (this.itemId) {
|
||||||
|
window._f0ckActiveSubmissions = window._f0ckActiveSubmissions || {};
|
||||||
|
if (!window._f0ckActiveSubmissions[this.itemId]) {
|
||||||
|
window._f0ckActiveSubmissions[this.itemId] = {
|
||||||
|
isMainSubmitting: false,
|
||||||
|
pendingSubmissions: new Set()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this._globalState = window._f0ckActiveSubmissions[this.itemId];
|
||||||
|
} else {
|
||||||
|
this._globalState = {
|
||||||
|
isMainSubmitting: false,
|
||||||
|
pendingSubmissions: new Set()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this.scrollListenerAdded = false;
|
this.scrollListenerAdded = false;
|
||||||
this.commentCache = new Map();
|
this.commentCache = new Map();
|
||||||
this._anchorScrollDone = false; // true after the first hash-anchor scroll on initial load
|
this._anchorScrollDone = false; // true after the first hash-anchor scroll on initial load
|
||||||
@@ -280,6 +306,7 @@ class CommentSystem {
|
|||||||
saveState() {
|
saveState() {
|
||||||
const state = {
|
const state = {
|
||||||
mainText: '',
|
mainText: '',
|
||||||
|
isMainSubmitting: this.isMainSubmitting,
|
||||||
openReplies: [],
|
openReplies: [],
|
||||||
focused: null
|
focused: null
|
||||||
};
|
};
|
||||||
@@ -288,7 +315,7 @@ class CommentSystem {
|
|||||||
|
|
||||||
// 1. Save main input
|
// 1. Save main input
|
||||||
const mainInput = this.container.querySelector('.main-input textarea');
|
const mainInput = this.container.querySelector('.main-input textarea');
|
||||||
if (mainInput && !this.isMainSubmitting) {
|
if (mainInput) {
|
||||||
state.mainText = mainInput.value;
|
state.mainText = mainInput.value;
|
||||||
if (document.activeElement === mainInput) {
|
if (document.activeElement === mainInput) {
|
||||||
state.focused = { type: 'main', start: mainInput.selectionStart, end: mainInput.selectionEnd };
|
state.focused = { type: 'main', start: mainInput.selectionStart, end: mainInput.selectionEnd };
|
||||||
@@ -298,17 +325,19 @@ class CommentSystem {
|
|||||||
// 2. Save open replies
|
// 2. Save open replies
|
||||||
this.container.querySelectorAll('.reply-input').forEach(form => {
|
this.container.querySelectorAll('.reply-input').forEach(form => {
|
||||||
const parentId = form.dataset.parent;
|
const parentId = form.dataset.parent;
|
||||||
if (!parentId || this.pendingSubmissions.has(parentId)) return;
|
if (!parentId) return;
|
||||||
|
|
||||||
const textarea = form.querySelector('textarea');
|
const textarea = form.querySelector('textarea');
|
||||||
const text = textarea ? textarea.value : '';
|
const text = textarea ? textarea.value : '';
|
||||||
if (parentId) {
|
const replyState = {
|
||||||
const replyState = { parentId, text };
|
parentId,
|
||||||
if (document.activeElement === textarea) {
|
text,
|
||||||
state.focused = { type: 'reply', parentId, start: textarea.selectionStart, end: textarea.selectionEnd };
|
isPending: this.pendingSubmissions.has(parentId)
|
||||||
}
|
};
|
||||||
state.openReplies.push(replyState);
|
if (document.activeElement === textarea) {
|
||||||
|
state.focused = { type: 'reply', parentId, start: textarea.selectionStart, end: textarea.selectionEnd };
|
||||||
}
|
}
|
||||||
|
state.openReplies.push(replyState);
|
||||||
});
|
});
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
@@ -318,7 +347,7 @@ class CommentSystem {
|
|||||||
if (!this.container) return;
|
if (!this.container) return;
|
||||||
|
|
||||||
// 1. Restore open replies
|
// 1. Restore open replies
|
||||||
state.openReplies.forEach(({ parentId, text }) => {
|
state.openReplies.forEach(({ parentId, text, isPending }) => {
|
||||||
const commentBody = this.container.querySelector(`#c${parentId} > .comment-body`);
|
const commentBody = this.container.querySelector(`#c${parentId} > .comment-body`);
|
||||||
if (commentBody && !commentBody.querySelector('.reply-input')) {
|
if (commentBody && !commentBody.querySelector('.reply-input')) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
@@ -327,16 +356,37 @@ class CommentSystem {
|
|||||||
const newForm = commentBody.querySelector('.reply-input');
|
const newForm = commentBody.querySelector('.reply-input');
|
||||||
if (newForm) {
|
if (newForm) {
|
||||||
const textarea = newForm.querySelector('textarea');
|
const textarea = newForm.querySelector('textarea');
|
||||||
if (textarea) textarea.value = text;
|
if (textarea) {
|
||||||
|
textarea.value = text;
|
||||||
|
if (isPending) textarea.disabled = true;
|
||||||
|
}
|
||||||
|
if (isPending) {
|
||||||
|
const submitBtn = newForm.querySelector('.submit-comment');
|
||||||
|
if (submitBtn) {
|
||||||
|
submitBtn.classList.add('loading');
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i>';
|
||||||
|
}
|
||||||
|
}
|
||||||
this.setupEmojiPicker(newForm);
|
this.setupEmojiPicker(newForm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Restore main input text
|
// 2. Restore main input text & submitting state
|
||||||
const mainInput = this.container.querySelector('.main-input textarea');
|
const mainInput = this.container.querySelector('.main-input textarea');
|
||||||
if (mainInput && state.mainText) {
|
if (mainInput) {
|
||||||
mainInput.value = state.mainText;
|
mainInput.value = state.mainText;
|
||||||
|
if (state.isMainSubmitting) {
|
||||||
|
mainInput.disabled = true;
|
||||||
|
const wrap = mainInput.closest('.comment-input');
|
||||||
|
const submitBtn = wrap ? wrap.querySelector('.submit-comment') : null;
|
||||||
|
if (submitBtn) {
|
||||||
|
submitBtn.classList.add('loading');
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i>';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Restore focus
|
// 3. Restore focus
|
||||||
@@ -348,7 +398,7 @@ class CommentSystem {
|
|||||||
targetEl = this.container.querySelector(`#c${state.focused.parentId} .reply-input textarea`);
|
targetEl = this.container.querySelector(`#c${state.focused.parentId} .reply-input textarea`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetEl) {
|
if (targetEl && !targetEl.disabled) {
|
||||||
targetEl.focus();
|
targetEl.focus();
|
||||||
// Ensure selection is restored after focus
|
// Ensure selection is restored after focus
|
||||||
if (typeof targetEl.setSelectionRange === 'function') {
|
if (typeof targetEl.setSelectionRange === 'function') {
|
||||||
@@ -2149,11 +2199,15 @@ class CommentSystem {
|
|||||||
this.container.addEventListener('keydown', (e) => {
|
this.container.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Enter' && e.ctrlKey) {
|
if (e.key === 'Enter' && e.ctrlKey) {
|
||||||
const textarea = e.target.closest('textarea');
|
const textarea = e.target.closest('textarea');
|
||||||
if (!textarea) return;
|
if (!textarea || textarea.disabled) return;
|
||||||
const wrap = textarea.closest('.comment-input');
|
const wrap = textarea.closest('.comment-input');
|
||||||
if (!wrap) return;
|
if (!wrap) return;
|
||||||
const submitBtn = wrap.querySelector('.submit-comment');
|
const submitBtn = wrap.querySelector('.submit-comment');
|
||||||
if (submitBtn) submitBtn.click();
|
if (submitBtn && !submitBtn.disabled && !submitBtn.classList.contains('loading')) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
submitBtn.click();
|
||||||
|
}
|
||||||
} else if (e.key === 'Escape') {
|
} else if (e.key === 'Escape') {
|
||||||
const textarea = e.target.closest('textarea');
|
const textarea = e.target.closest('textarea');
|
||||||
if (textarea) textarea.blur();
|
if (textarea) textarea.blur();
|
||||||
@@ -2760,11 +2814,13 @@ class CommentSystem {
|
|||||||
const parentId = wrap.dataset.parent || null;
|
const parentId = wrap.dataset.parent || null;
|
||||||
|
|
||||||
if (!text.trim()) return;
|
if (!text.trim()) return;
|
||||||
if (submitBtn.classList.contains('loading')) return;
|
if (submitBtn.classList.contains('loading') || submitBtn.disabled) return;
|
||||||
if (wrap._pendingUploads > 0) return;
|
if (wrap._pendingUploads > 0) return;
|
||||||
|
|
||||||
// Start loading state
|
// Start loading state
|
||||||
submitBtn.classList.add('loading');
|
submitBtn.classList.add('loading');
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
textarea.disabled = true;
|
||||||
const originalBtnHtml = submitBtn.innerHTML;
|
const originalBtnHtml = submitBtn.innerHTML;
|
||||||
submitBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i>';
|
submitBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i>';
|
||||||
|
|
||||||
@@ -3038,15 +3094,35 @@ class CommentSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_finishSubmit(btn, originalHtml, parentId) {
|
_finishSubmit(btn, originalHtml, parentId) {
|
||||||
if (btn) {
|
|
||||||
btn.classList.remove('loading');
|
|
||||||
btn.innerHTML = originalHtml;
|
|
||||||
}
|
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
this.pendingSubmissions.delete(parentId);
|
this.pendingSubmissions.delete(parentId);
|
||||||
} else {
|
} else {
|
||||||
this.isMainSubmitting = false;
|
this.isMainSubmitting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Surgical lookup of the active wrap in the live DOM
|
||||||
|
let activeWrap = null;
|
||||||
|
if (this.container) {
|
||||||
|
if (parentId) {
|
||||||
|
activeWrap = this.container.querySelector(`#c${parentId} .reply-input`);
|
||||||
|
} else {
|
||||||
|
activeWrap = this.container.querySelector('.main-input');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrap = activeWrap || (btn ? btn.closest('.comment-input') : null);
|
||||||
|
if (wrap) {
|
||||||
|
const activeBtn = wrap.querySelector('.submit-comment');
|
||||||
|
const activeTextarea = wrap.querySelector('textarea');
|
||||||
|
if (activeBtn) {
|
||||||
|
activeBtn.classList.remove('loading');
|
||||||
|
activeBtn.disabled = false;
|
||||||
|
activeBtn.innerHTML = originalHtml;
|
||||||
|
}
|
||||||
|
if (activeTextarea) {
|
||||||
|
activeTextarea.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ window.initUploadForm = (selector) => {
|
|||||||
if (form._f0ckInit) return form._f0ckUploader;
|
if (form._f0ckInit) return form._f0ckUploader;
|
||||||
form._f0ckInit = true;
|
form._f0ckInit = true;
|
||||||
|
|
||||||
|
let isUploading = false;
|
||||||
|
|
||||||
// Use querySelector to find elements within this specific form instance
|
// Use querySelector to find elements within this specific form instance
|
||||||
const fileInput = form.querySelector('.file-input');
|
const fileInput = form.querySelector('.file-input');
|
||||||
const dropZone = form.querySelector('.drop-zone');
|
const dropZone = form.querySelector('.drop-zone');
|
||||||
@@ -643,6 +645,11 @@ window.initUploadForm = (selector) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateSubmitButton = () => {
|
const updateSubmitButton = () => {
|
||||||
|
if (isUploading) {
|
||||||
|
if (submitBtn) submitBtn.disabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isShitpost = !!window.f0ckShitpostMode;
|
const isShitpost = !!window.f0ckShitpostMode;
|
||||||
const rating = form.querySelector('input[name="rating"]:checked');
|
const rating = form.querySelector('input[name="rating"]:checked');
|
||||||
|
|
||||||
@@ -1795,7 +1802,7 @@ window.initUploadForm = (selector) => {
|
|||||||
if (e && e.preventDefault) e.preventDefault();
|
if (e && e.preventDefault) e.preventDefault();
|
||||||
|
|
||||||
// If already uploading, don't start again
|
// If already uploading, don't start again
|
||||||
if (submitBtn && submitBtn.disabled && submitBtn.querySelector('.btn-loading')?.style.display === 'inline') {
|
if (isUploading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1826,6 +1833,7 @@ window.initUploadForm = (selector) => {
|
|||||||
const isOc = form.querySelector('#upload-oc-checkbox')?.checked || false;
|
const isOc = form.querySelector('#upload-oc-checkbox')?.checked || false;
|
||||||
|
|
||||||
const setBtnLoading = (text) => {
|
const setBtnLoading = (text) => {
|
||||||
|
isUploading = true;
|
||||||
if (!submitBtn) return;
|
if (!submitBtn) return;
|
||||||
submitBtn.disabled = true;
|
submitBtn.disabled = true;
|
||||||
const btnText = submitBtn.querySelector('.btn-text');
|
const btnText = submitBtn.querySelector('.btn-text');
|
||||||
@@ -1838,12 +1846,14 @@ window.initUploadForm = (selector) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const restoreBtn = () => {
|
const restoreBtn = () => {
|
||||||
|
isUploading = false;
|
||||||
if (!submitBtn) return;
|
if (!submitBtn) return;
|
||||||
submitBtn.disabled = false;
|
submitBtn.disabled = false;
|
||||||
const btnText = submitBtn.querySelector('.btn-text');
|
const btnText = submitBtn.querySelector('.btn-text');
|
||||||
const btnLoading = submitBtn.querySelector('.btn-loading');
|
const btnLoading = submitBtn.querySelector('.btn-loading');
|
||||||
if (btnText) btnText.style.display = 'inline';
|
if (btnText) btnText.style.display = 'inline';
|
||||||
if (btnLoading) btnLoading.style.display = 'none';
|
if (btnLoading) btnLoading.style.display = 'none';
|
||||||
|
updateSubmitButton();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (activeMode === 'url') {
|
if (activeMode === 'url') {
|
||||||
@@ -2106,6 +2116,7 @@ window.initUploadForm = (selector) => {
|
|||||||
handleFile: handleFile,
|
handleFile: handleFile,
|
||||||
performUpload: performUpload,
|
performUpload: performUpload,
|
||||||
reset: () => {
|
reset: () => {
|
||||||
|
isUploading = false;
|
||||||
form.reset();
|
form.reset();
|
||||||
tags = [];
|
tags = [];
|
||||||
selectedFiles = [];
|
selectedFiles = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user