Fix errors on js and add grouped messages
parent
9749457e2f
commit
78a2875958
|
|
@ -47,10 +47,10 @@ function enableEnterToSubmit(input, form) {
|
|||
form.requestSubmit();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Optimistic UI for like/dislike buttons
|
||||
document.querySelectorAll('form[action*="/like/"]').forEach(form => {
|
||||
// Optimistic UI for like/dislike buttons
|
||||
document.querySelectorAll('form[action*="/like/"]').forEach(form => {
|
||||
form.addEventListener('submit', (e) => {
|
||||
const button = form.querySelector('button[type="submit"]');
|
||||
if (button) {
|
||||
|
|
@ -58,8 +58,7 @@ function enableEnterToSubmit(input, form) {
|
|||
button.textContent = button.textContent + ' ✓';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
|
|
@ -343,3 +342,88 @@ function showDraftIndicator(content, timestamp, onRestore, onDiscard) {
|
|||
|
||||
return indicator;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Validation Functions
|
||||
// ============================================
|
||||
|
||||
function validateRequired(value, fieldName) {
|
||||
if (!value || value.trim() === '') {
|
||||
return `${fieldName} is required`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateUsername(username) {
|
||||
if (!username || username.trim() === '') {
|
||||
return 'Username is required';
|
||||
}
|
||||
if (username.length < 3) {
|
||||
return 'Username must be at least 3 characters';
|
||||
}
|
||||
if (username.length > 50) {
|
||||
return 'Username must be less than 50 characters';
|
||||
}
|
||||
if (!/^[a-zA-Z0-9_]+$/.test(username)) {
|
||||
return 'Username can only contain letters, numbers, and underscores';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function validatePassword(password) {
|
||||
if (!password || password.trim() === '') {
|
||||
return 'Password is required';
|
||||
}
|
||||
if (password.length < 6) {
|
||||
return 'Password must be at least 6 characters';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function showFieldError(field, error) {
|
||||
field.classList.add('error');
|
||||
let errorDiv = field.nextElementSibling;
|
||||
if (!errorDiv || !errorDiv.classList.contains('field-error')) {
|
||||
errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'field-error';
|
||||
field.parentNode.insertBefore(errorDiv, field.nextSibling);
|
||||
}
|
||||
errorDiv.textContent = error;
|
||||
}
|
||||
|
||||
function clearFieldError(field) {
|
||||
field.classList.remove('error');
|
||||
const errorDiv = field.nextElementSibling;
|
||||
if (errorDiv && errorDiv.classList.contains('field-error')) {
|
||||
errorDiv.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function autoResizeTextarea(textarea) {
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = textarea.scrollHeight + 'px';
|
||||
}
|
||||
|
||||
function addCharacterCounter(textarea, maxLength) {
|
||||
const counter = document.createElement('div');
|
||||
counter.className = 'char-counter';
|
||||
textarea.parentNode.insertBefore(counter, textarea.nextSibling);
|
||||
|
||||
const updateCounter = () => {
|
||||
const length = textarea.value.length;
|
||||
counter.textContent = `${length}/${maxLength}`;
|
||||
if (length > maxLength * 0.9) {
|
||||
counter.classList.add('warning');
|
||||
} else {
|
||||
counter.classList.remove('warning');
|
||||
}
|
||||
};
|
||||
|
||||
textarea.addEventListener('input', updateCounter);
|
||||
updateCounter();
|
||||
}
|
||||
|
||||
function initRelativeTimestamps() {
|
||||
// This function can be used to show relative timestamps
|
||||
// For now, it's just a placeholder
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,6 +343,13 @@ p.thread-info {
|
|||
background-color: #ffe0f0; /* Light pink background */
|
||||
animation: highlight-fade 2s ease-out;
|
||||
}
|
||||
/* Grouped messages (hide header for consecutive messages from same user) */
|
||||
.chat-message.grouped {
|
||||
margin-top: -4px;
|
||||
}
|
||||
.chat-message.grouped .chat-message-header {
|
||||
display: none;
|
||||
}
|
||||
@keyframes highlight-fade {
|
||||
from {
|
||||
background-color: #f582ae;
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@
|
|||
<span id="typing-users"></span><span class="typing-dots"><span>.</span><span>.</span><span>.</span></span>
|
||||
</div>
|
||||
{{range .Messages}}
|
||||
<div class="chat-message{{if .Mentions}}{{range .Mentions}}{{if eq . $.CurrentUsername}} chat-message-highlighted{{end}}{{end}}{{end}}" id="msg-{{.ID}}">
|
||||
<div class="chat-message{{if .Mentions}}{{range .Mentions}}{{if eq . $.CurrentUsername}} chat-message-highlighted{{end}}{{end}}{{end}}" id="msg-{{.ID}}" data-user="{{.Username}}" data-reply="{{.ReplyTo}}">
|
||||
<div class="chat-message-header">
|
||||
{{if .PfpFileID.Valid}}
|
||||
<img src="{{$.BasePath}}/file?id={{.PfpFileID.Int64}}" alt="PFP" class="chat-message-pfp">
|
||||
|
|
@ -627,6 +627,8 @@
|
|||
}
|
||||
msgDiv.className = 'chat-message' + highlightClass;
|
||||
msgDiv.id = 'msg-' + msg.id;
|
||||
msgDiv.dataset.user = msg.username;
|
||||
msgDiv.dataset.reply = msg.replyTo || 0;
|
||||
let pfpHTML = `<div class="chat-message-pfp" style="background-color: #001858;"></div>`;
|
||||
if (msg.pfpFileId && msg.pfpFileId.Valid) {
|
||||
pfpHTML = `<img src="{{.BasePath}}/file?id=${msg.pfpFileId.Int64}&t=${new Date().getTime()}" alt="PFP" class="chat-message-pfp">`;
|
||||
|
|
@ -647,6 +649,9 @@
|
|||
`;
|
||||
messages.appendChild(msgDiv);
|
||||
|
||||
// Apply grouping
|
||||
applyGrouping();
|
||||
|
||||
// Scroll handling
|
||||
if (wasAtBottom) {
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
|
|
@ -834,6 +839,9 @@
|
|||
const messagesContainer = document.getElementById('chat-messages');
|
||||
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
||||
|
||||
// Apply message grouping on load
|
||||
applyGrouping();
|
||||
|
||||
// Add scroll event listener
|
||||
messagesContainer.addEventListener('scroll', checkScrollPosition);
|
||||
|
||||
|
|
@ -909,6 +917,30 @@
|
|||
// Initial check for scroll position
|
||||
checkScrollPosition();
|
||||
};
|
||||
|
||||
function applyGrouping() {
|
||||
const container = document.getElementById('chat-messages');
|
||||
const msgs = Array.from(container.querySelectorAll('.chat-message')).filter(el => el.id.startsWith('msg-'));
|
||||
|
||||
for (let i = 0; i < msgs.length; i++) {
|
||||
const curr = msgs[i];
|
||||
|
||||
// Remove grouped class first
|
||||
curr.classList.remove('grouped');
|
||||
|
||||
if (i === 0) continue; // First message is never grouped
|
||||
|
||||
const prev = msgs[i - 1];
|
||||
const currUser = curr.dataset.user;
|
||||
const prevUser = prev.dataset.user;
|
||||
const currReply = parseInt(curr.dataset.reply) || -1;
|
||||
|
||||
// Group if same user and not a reply (reply is -1 or 0 when there's no reply)
|
||||
if (currUser === prevUser && (currReply <= 0)) {
|
||||
curr.classList.add('grouped');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Reference in New Issue