// DATACOM-3000 Data Explorer JavaScript Module class DataExplorer { constructor() { this.data = []; this.filteredData = []; this.sortColumn = 'id'; this.sortDirection = 'asc'; this.selectedRow = null; this.columns = ['id', 'name', 'type', 'size', 'modified']; this.init(); } init() { this.bindEvents(); this.generateMockData(); this.updateDisplay(); this.startSystemClock(); this.simulateMemoryUsage(); } bindEvents() { // Search filter const searchInput = document.getElementById('search-filter'); searchInput.addEventListener('input', (e) => this.handleSearch(e.target.value)); // Sort controls const sortSelector = document.getElementById('sort-selector'); sortSelector.addEventListener('change', (e) => this.handleSort(e.target.value)); const sortDirection = document.querySelector('.sort-direction'); sortDirection.addEventListener('click', () => this.toggleSortDirection()); // Action buttons document.querySelectorAll('.action-btn').forEach(btn => { btn.addEventListener('click', (e) => { const action = e.currentTarget.dataset.action; this.handleAction(action); }); }); // Column headers for sorting document.querySelectorAll('.column-header').forEach(header => { header.addEventListener('click', (e) => { if (!e.target.classList.contains('resize-handle')) { const column = header.dataset.column; this.handleSort(column); } }); }); // Column resizing this.initColumnResizing(); // Preview close button const previewClose = document.querySelector('.preview-close'); previewClose.addEventListener('click', () => this.closePreview()); // Command input const commandInput = document.querySelector('.command-input'); commandInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.executeCommand(e.target.value); e.target.value = ''; } }); } generateMockData() { const fileTypes = ['DAT', 'TXT', 'BIN', 'LOG', 'CFG', 'SYS', 'EXE', 'BAT']; const names = [ 'SYSTEM', 'CONFIG', 'DATA', 'BACKUP', 'ARCHIVE', 'TEMP', 'CACHE', 'INDEX', 'DATABASE', 'REPORT', 'LOG', 'USER' ]; for (let i = 1; i <= 50; i++) { const type = fileTypes[Math.floor(Math.random() * fileTypes.length)]; const name = names[Math.floor(Math.random() * names.length)]; const size = Math.floor(Math.random() * 999999) + 1; const date = new Date(Date.now() - Math.floor(Math.random() * 31536000000)); this.data.push({ id: String(i).padStart(4, '0'), name: `${name}_${String(i).padStart(2, '0')}.${type}`, type: type, size: this.formatSize(size), sizeBytes: size, modified: this.formatDate(date), modifiedTimestamp: date.getTime(), rawData: this.generatePreviewData(type) }); } this.filteredData = [...this.data]; } generatePreviewData(type) { const previews = { 'DAT': '00000000 48 45 58 20 44 55 4D 50 20 44 41 54 41 20 46 49 |HEX DUMP DATA FI|\n00000010 4C 45 20 46 4F 52 20 50 52 45 56 49 45 57 20 4F |LE FOR PREVIEW O|\n00000020 4E 4C 59 20 2D 20 4E 4F 54 20 41 43 54 55 41 4C |NLY - NOT ACTUAL|', 'TXT': 'PLAINTEXT DOCUMENT\n==================\nLorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n[END OF FILE]', 'BIN': '01001000 01000101 01001100 01001100 01001111\n01010111 01001111 01010010 01001100 01000100\n00100001 00100000 00110010 00110000 00110010\n00110100 00100000 01000010 01001001 01001110', 'LOG': '[1990-01-01 00:00:00] SYSTEM INITIALIZED\n[1990-01-01 00:00:01] MEMORY CHECK... OK\n[1990-01-01 00:00:02] DISK CHECK... OK\n[1990-01-01 00:00:03] NETWORK CHECK... OK\n[1990-01-01 00:00:04] READY FOR OPERATION', 'CFG': 'SYSTEM.MEMORY=640K\nSYSTEM.DISK=40MB\nSYSTEM.CPU=80486\nSYSTEM.SPEED=33MHZ\nSYSTEM.CACHE=ENABLED\nSYSTEM.SOUND=BEEPER', 'SYS': 'SYSTEM FILE - PROTECTED\n\nACCESS DENIED\n\nAUTHORIZATION REQUIRED', 'EXE': 'EXECUTABLE FILE HEADER\n=====================\nMAGIC NUMBER: 4D5A\nBYTES ON LAST PAGE: 0090\nPAGES IN FILE: 0003\nRELOCATIONS: 0000\nHEADER SIZE: 0004', 'BAT': '@ECHO OFF\nCLS\nECHO BATCH FILE PREVIEW\nECHO ==================\nPAUSE\nEXIT' }; return previews[type] || 'UNKNOWN FILE TYPE'; } formatSize(bytes) { if (bytes < 1024) return `${bytes}B`; if (bytes < 1048576) return `${Math.floor(bytes / 1024)}K`; return `${(bytes / 1048576).toFixed(1)}M`; } formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}`; } handleSearch(query) { if (!query) { this.filteredData = [...this.data]; } else { const searchTerm = query.toLowerCase(); this.filteredData = this.data.filter(item => item.name.toLowerCase().includes(searchTerm) || item.type.toLowerCase().includes(searchTerm) || item.id.includes(searchTerm) ); } this.updateDisplay(); } handleSort(column) { if (this.sortColumn === column) { this.toggleSortDirection(); } else { this.sortColumn = column; this.sortDirection = 'asc'; document.querySelector('.sort-direction').textContent = '▲'; } this.sortData(); this.updateDisplay(); } toggleSortDirection() { this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc'; const directionBtn = document.querySelector('.sort-direction'); directionBtn.textContent = this.sortDirection === 'asc' ? '▲' : '▼'; this.sortData(); this.updateDisplay(); } sortData() { this.filteredData.sort((a, b) => { let valueA, valueB; switch (this.sortColumn) { case 'size': valueA = a.sizeBytes; valueB = b.sizeBytes; break; case 'date': case 'modified': valueA = a.modifiedTimestamp; valueB = b.modifiedTimestamp; break; default: valueA = a[this.sortColumn]; valueB = b[this.sortColumn]; } if (valueA < valueB) return this.sortDirection === 'asc' ? -1 : 1; if (valueA > valueB) return this.sortDirection === 'asc' ? 1 : -1; return 0; }); } handleAction(action) { switch (action) { case 'import': this.showMessage('IMPORT FUNCTION NOT IMPLEMENTED'); this.simulateImport(); break; case 'export': this.exportData(); break; case 'refresh': this.refreshData(); break; } } simulateImport() { // Simulate file import setTimeout(() => { const newItem = { id: String(this.data.length + 1).padStart(4, '0'), name: `IMPORT_${Date.now()}.DAT`, type: 'DAT', size: this.formatSize(Math.floor(Math.random() * 99999) + 1000), sizeBytes: Math.floor(Math.random() * 99999) + 1000, modified: this.formatDate(new Date()), modifiedTimestamp: Date.now(), rawData: 'IMPORTED DATA FILE\n================\n[DATA IMPORTED SUCCESSFULLY]' }; this.data.push(newItem); this.filteredData = [...this.data]; this.updateDisplay(); this.showMessage('IMPORT COMPLETE: 1 FILE ADDED'); }, 1000); } exportData() { const exportText = this.filteredData.map(item => `${item.id},${item.name},${item.type},${item.size},${item.modified}` ).join('\n'); const header = 'ID,NAME,TYPE,SIZE,MODIFIED\n'; const fullExport = header + exportText; // Create download const blob = new Blob([fullExport], { type: 'text/csv' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `DATACOM_EXPORT_${Date.now()}.CSV`; a.click(); URL.revokeObjectURL(url); this.showMessage(`EXPORT COMPLETE: ${this.filteredData.length} RECORDS`); } refreshData() { // Simulate refresh animation const tbody = document.getElementById('data-tbody'); tbody.style.opacity = '0.5'; setTimeout(() => { tbody.style.opacity = '1'; this.updateDisplay(); this.showMessage('DATA REFRESHED'); }, 500); } updateDisplay() { const tbody = document.getElementById('data-tbody'); tbody.innerHTML = ''; this.filteredData.forEach((item, index) => { const row = document.createElement('tr'); row.setAttribute('role', 'row'); row.dataset.index = index; row.innerHTML = `
FILE: ${item.name}
TYPE: ${item.type}
SIZE: ${item.size}
DATE: ${item.modified}
${item.rawData}
`;
// Show preview panel on mobile
const preview = document.querySelector('.data-preview');
preview.classList.add('active');
}
closePreview() {
const preview = document.querySelector('.data-preview');
preview.classList.remove('active');
}
executeCommand(command) {
const cmd = command.toUpperCase().trim();
switch (cmd) {
case 'CLS':
case 'CLEAR':
this.filteredData = [];
this.updateDisplay();
this.showMessage('SCREEN CLEARED');
break;
case 'DIR':
case 'LS':
this.showMessage(`${this.data.length} FILES IN DIRECTORY`);
break;
case 'HELP':
this.showMessage('COMMANDS: CLS, DIR, SORT, FILTER, EXIT');
break;
case 'EXIT':
this.showMessage('CANNOT EXIT - SYSTEM LOCKED');
break;
default:
if (cmd.startsWith('FILTER ')) {
const query = cmd.substring(7);
document.getElementById('search-filter').value = query;
this.handleSearch(query);
} else if (cmd.startsWith('SORT ')) {
const column = cmd.substring(5).toLowerCase();
if (this.columns.includes(column)) {
this.handleSort(column);
}
} else {
this.showMessage('UNKNOWN COMMAND - TYPE HELP');
}
}
}
showMessage(message) {
const commandInput = document.querySelector('.command-input');
const originalPlaceholder = commandInput.placeholder;
commandInput.placeholder = message;
setTimeout(() => {
commandInput.placeholder = originalPlaceholder;
}, 3000);
}
initColumnResizing() {
let isResizing = false;
let currentColumn = null;
let startX = 0;
let startWidth = 0;
document.querySelectorAll('.resize-handle').forEach(handle => {
handle.addEventListener('mousedown', (e) => {
isResizing = true;
currentColumn = handle.parentElement;
startX = e.pageX;
startWidth = currentColumn.offsetWidth;
document.body.style.cursor = 'col-resize';
e.preventDefault();
});
});
document.addEventListener('mousemove', (e) => {
if (!isResizing) return;
const width = startWidth + (e.pageX - startX);
if (width > 50) {
currentColumn.style.width = `${width}px`;
}
});
document.addEventListener('mouseup', () => {
isResizing = false;
currentColumn = null;
document.body.style.cursor = 'default';
});
}
startSystemClock() {
const updateClock = () => {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
document.getElementById('system-time').textContent = `${hours}:${minutes}:${seconds}`;
};
updateClock();
setInterval(updateClock, 1000);
}
simulateMemoryUsage() {
const memoryBar = document.querySelector('.memory-used');
const memoryText = document.querySelector('.memory-text');
setInterval(() => {
const used = 640 + Math.floor(Math.random() * 100);
const percentage = (used / 1024) * 100;
memoryBar.style.width = `${percentage}%`;
memoryText.textContent = `${used}K/1024K`;
if (percentage > 90) {
memoryBar.style.backgroundColor = 'var(--error-red)';
} else if (percentage > 75) {
memoryBar.style.backgroundColor = 'var(--warning-yellow)';
} else {
memoryBar.style.backgroundColor = 'var(--terminal-text)';
}
}, 2000);
}
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', () => {
window.dataExplorer = new DataExplorer();
// Add keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
switch (e.key) {
case 'f':
e.preventDefault();
document.getElementById('search-filter').focus();
break;
case 'e':
e.preventDefault();
window.dataExplorer.handleAction('export');
break;
case 'r':
e.preventDefault();
window.dataExplorer.handleAction('refresh');
break;
}
}
});
});
// Add some retro console messages
console.log('%c╔════════════════════════════╗', 'color: #00ff00');
console.log('%c║ DATACOM-3000 SYSTEM v2.31 ║', 'color: #00ff00');
console.log('%c║ (C) 1990 RETROTECH CORP ║', 'color: #00ff00');
console.log('%c╚════════════════════════════╝', 'color: #00ff00');
console.log('%cSYSTEM INITIALIZED', 'color: #ffb000');
console.log('%cMEMORY: 640K OK', 'color: #00ff00');
console.log('%cREADY.', 'color: #00ff00');