rag-data-platform / static /js /raw-data.js
Vipooshanb's picture
Deploy Mozhii RAG Data Platform
af25178 verified
Raw
History Blame Contribute Delete
9.68 kB
/**
* =============================================================================
* Mozhii RAG Data Platform - Raw Data Tab JavaScript
* =============================================================================
* Handles all functionality for the RAW DATA tab where collectors
* submit raw Tamil content for processing.
*
* Features:
* - Form validation
* - Character counting
* - Content submission
* - Form clearing
* =============================================================================
*/
// =============================================================================
// DOM ELEMENTS
// =============================================================================
/**
* Cache DOM elements for the raw data tab
* This improves performance by avoiding repeated DOM queries
*/
const RawDataElements = {
// Form inputs
filename: null,
language: null,
source: null,
content: null,
// Buttons
submitBtn: null,
clearBtn: null,
// Display elements
charCount: null,
// Initialize element references
init() {
this.filename = document.getElementById('raw-filename');
this.language = document.getElementById('raw-language');
this.source = document.getElementById('raw-source');
this.content = document.getElementById('raw-content');
this.submitBtn = document.getElementById('raw-submit');
this.clearBtn = document.getElementById('raw-clear');
this.charCount = document.getElementById('raw-char-count');
}
};
// =============================================================================
// VALIDATION
// =============================================================================
/**
* Validate the filename input
* Only allows letters, numbers, underscores, and hyphens
*
* @param {string} filename - The filename to validate
* @returns {Object} - Validation result {valid: boolean, error: string}
*/
function validateFilename(filename) {
// Check if empty
if (!filename || filename.trim() === '') {
return { valid: false, error: 'Filename is required' };
}
// Check format (alphanumeric with underscores and hyphens)
const pattern = /^[a-zA-Z0-9_-]+$/;
if (!pattern.test(filename)) {
return {
valid: false,
error: 'Filename can only contain letters, numbers, underscores, and hyphens'
};
}
// Check length
if (filename.length < 3) {
return { valid: false, error: 'Filename must be at least 3 characters' };
}
if (filename.length > 50) {
return { valid: false, error: 'Filename cannot exceed 50 characters' };
}
return { valid: true };
}
/**
* Validate the content textarea
*
* @param {string} content - The content to validate
* @returns {Object} - Validation result {valid: boolean, error: string}
*/
function validateContent(content) {
// Check if empty
if (!content || content.trim() === '') {
return { valid: false, error: 'Content is required' };
}
// Check minimum length (at least 50 characters for meaningful content)
if (content.trim().length < 50) {
return {
valid: false,
error: 'Content must be at least 50 characters'
};
}
return { valid: true };
}
/**
* Validate the entire form
*
* @returns {Object} - Validation result {valid: boolean, errors: Array}
*/
function validateRawDataForm() {
const errors = [];
// Validate filename
const filenameResult = validateFilename(RawDataElements.filename.value);
if (!filenameResult.valid) {
errors.push(filenameResult.error);
}
// Validate content
const contentResult = validateContent(RawDataElements.content.value);
if (!contentResult.valid) {
errors.push(contentResult.error);
}
return {
valid: errors.length === 0,
errors
};
}
// =============================================================================
// FORM HANDLERS
// =============================================================================
/**
* Handle character count update
* Called whenever the content textarea changes
*/
function updateCharCount() {
const content = RawDataElements.content.value;
const count = content.length;
// Update the character count display
RawDataElements.charCount.textContent = `${count.toLocaleString()} characters`;
// Add warning color if content is too short
if (count > 0 && count < 50) {
RawDataElements.charCount.style.color = 'var(--warning)';
} else {
RawDataElements.charCount.style.color = 'var(--text-muted)';
}
}
/**
* Handle form submission
* Validates the form and sends data to the API
*/
async function handleRawDataSubmit() {
// Validate form
const validation = validateRawDataForm();
if (!validation.valid) {
// Show first error as toast
showToast('Validation Error', validation.errors[0], 'error');
return;
}
// Disable submit button to prevent double submission
RawDataElements.submitBtn.disabled = true;
RawDataElements.submitBtn.innerHTML = '<span class="btn-icon">⏳</span> Submitting...';
try {
// Prepare data
const formData = {
filename: RawDataElements.filename.value.trim(),
language: RawDataElements.language.value,
source: RawDataElements.source.value,
content: RawDataElements.content.value
};
// Submit to API
const response = await api('/api/raw/submit', {
method: 'POST',
body: JSON.stringify(formData)
});
if (response.success) {
// Show success message
showToast(
'Submitted Successfully!',
`"${formData.filename}" is now pending admin approval.`,
'success'
);
// Clear the form
clearRawDataForm();
// Refresh admin badge
refreshAdminData();
} else {
throw new Error(response.error || 'Submission failed');
}
} catch (error) {
// Show error message
showToast('Submission Failed', error.message, 'error');
} finally {
// Re-enable submit button
RawDataElements.submitBtn.disabled = false;
RawDataElements.submitBtn.innerHTML = '<span class="btn-icon">📤</span> Submit for Review';
}
}
/**
* Clear the raw data form
* Resets all fields to their default values
*/
function clearRawDataForm() {
RawDataElements.filename.value = '';
RawDataElements.language.value = 'ta';
RawDataElements.source.value = 'gov_textbook';
RawDataElements.content.value = '';
// Reset character count
updateCharCount();
// Focus on filename field
RawDataElements.filename.focus();
}
// =============================================================================
// EVENT LISTENERS
// =============================================================================
/**
* Initialize event listeners for the raw data tab
*/
function initRawDataEventListeners() {
// Content textarea - update character count on input
RawDataElements.content.addEventListener('input', updateCharCount);
// Submit button click
RawDataElements.submitBtn.addEventListener('click', handleRawDataSubmit);
// Clear button click
RawDataElements.clearBtn.addEventListener('click', () => {
// Confirm before clearing if there's content
if (RawDataElements.content.value.trim().length > 0) {
showModal('Clear Form?',
'<p>Are you sure you want to clear all fields?</p>',
[
{ text: 'Cancel', class: 'btn-secondary', onClick: hideModal },
{ text: 'Clear', class: 'btn-primary', onClick: () => {
clearRawDataForm();
hideModal();
}}
]
);
} else {
clearRawDataForm();
}
});
// Filename validation on blur
RawDataElements.filename.addEventListener('blur', () => {
const result = validateFilename(RawDataElements.filename.value);
if (!result.valid && RawDataElements.filename.value.length > 0) {
// Visual feedback - could add error border
RawDataElements.filename.style.borderColor = 'var(--error)';
} else {
RawDataElements.filename.style.borderColor = '';
}
});
// Clear error style on focus
RawDataElements.filename.addEventListener('focus', () => {
RawDataElements.filename.style.borderColor = '';
});
// Submit on Ctrl+Enter
RawDataElements.content.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'Enter') {
handleRawDataSubmit();
}
});
}
// =============================================================================
// INITIALIZATION
// =============================================================================
/**
* Initialize the raw data tab
* Called when DOM is ready
*/
document.addEventListener('DOMContentLoaded', () => {
// Initialize element references
RawDataElements.init();
// Set up event listeners
initRawDataEventListeners();
// Initialize character count
updateCharCount();
console.log('📥 Raw Data tab initialized');
});