876 lines
32 KiB
HTML
876 lines
32 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>DATATERM v16.0 - Retro Computing Data Explorer</title>
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');
|
|
|
|
:root {
|
|
--terminal-green: #00ff00;
|
|
--terminal-amber: #ffb000;
|
|
--terminal-dark-green: #00aa00;
|
|
--terminal-dark-amber: #cc8800;
|
|
--terminal-bg: #000000;
|
|
--terminal-bg-light: #111111;
|
|
--scan-line: rgba(0, 255, 0, 0.1);
|
|
}
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: 'VT323', monospace;
|
|
background: var(--terminal-bg);
|
|
color: var(--terminal-green);
|
|
font-size: 18px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
/* CRT Effect */
|
|
body::before {
|
|
content: '';
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(
|
|
transparent 50%,
|
|
var(--scan-line) 50%
|
|
);
|
|
background-size: 100% 4px;
|
|
animation: scan-lines 8s linear infinite;
|
|
pointer-events: none;
|
|
z-index: 1000;
|
|
}
|
|
|
|
@keyframes scan-lines {
|
|
0% { transform: translateY(0); }
|
|
100% { transform: translateY(4px); }
|
|
}
|
|
|
|
/* Phosphor Glow */
|
|
.glow {
|
|
text-shadow:
|
|
0 0 2px currentColor,
|
|
0 0 4px currentColor,
|
|
0 0 8px currentColor;
|
|
}
|
|
|
|
/* Main Container */
|
|
.terminal-container {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
padding: 20px;
|
|
background: radial-gradient(ellipse at center, #001100, #000000);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* Terminal Header */
|
|
.terminal-header {
|
|
border: 2px solid var(--terminal-green);
|
|
padding: 10px;
|
|
margin-bottom: 10px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.terminal-header::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: -100%;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(90deg, transparent, var(--terminal-green), transparent);
|
|
animation: terminal-scan 4s linear infinite;
|
|
opacity: 0.3;
|
|
}
|
|
|
|
@keyframes terminal-scan {
|
|
0% { left: -100%; }
|
|
100% { left: 100%; }
|
|
}
|
|
|
|
.terminal-title {
|
|
font-size: 24px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.blink {
|
|
animation: blink-animation 1s step-start infinite;
|
|
}
|
|
|
|
@keyframes blink-animation {
|
|
50% { opacity: 0; }
|
|
}
|
|
|
|
/* Command Line Interface */
|
|
.command-line {
|
|
border: 1px solid var(--terminal-green);
|
|
padding: 10px;
|
|
margin-bottom: 10px;
|
|
background: var(--terminal-bg-light);
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.prompt {
|
|
color: var(--terminal-amber);
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.command-input {
|
|
flex: 1;
|
|
background: none;
|
|
border: none;
|
|
color: var(--terminal-green);
|
|
font-family: 'VT323', monospace;
|
|
font-size: 16px;
|
|
outline: none;
|
|
}
|
|
|
|
/* Control Panel */
|
|
.control-panel {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 10px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.control-group {
|
|
border: 1px solid var(--terminal-dark-green);
|
|
padding: 10px;
|
|
background: var(--terminal-bg-light);
|
|
}
|
|
|
|
.control-label {
|
|
color: var(--terminal-amber);
|
|
font-size: 14px;
|
|
margin-bottom: 5px;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.control-input {
|
|
width: 100%;
|
|
background: var(--terminal-bg);
|
|
border: 1px solid var(--terminal-green);
|
|
color: var(--terminal-green);
|
|
padding: 5px;
|
|
font-family: 'VT323', monospace;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.control-button {
|
|
background: var(--terminal-bg);
|
|
border: 1px solid var(--terminal-green);
|
|
color: var(--terminal-green);
|
|
padding: 5px 10px;
|
|
cursor: pointer;
|
|
font-family: 'VT323', monospace;
|
|
font-size: 16px;
|
|
text-transform: uppercase;
|
|
transition: all 0.3s;
|
|
margin-right: 5px;
|
|
}
|
|
|
|
.control-button:hover {
|
|
background: var(--terminal-green);
|
|
color: var(--terminal-bg);
|
|
box-shadow: 0 0 10px var(--terminal-green);
|
|
}
|
|
|
|
/* Data Table */
|
|
.data-viewport {
|
|
flex: 1;
|
|
border: 2px solid var(--terminal-green);
|
|
overflow: auto;
|
|
background: var(--terminal-bg-light);
|
|
position: relative;
|
|
}
|
|
|
|
.data-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.data-table th, .data-table td {
|
|
border: 1px solid var(--terminal-dark-green);
|
|
padding: 8px;
|
|
text-align: left;
|
|
}
|
|
|
|
.data-table th {
|
|
background: var(--terminal-bg);
|
|
color: var(--terminal-amber);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 10;
|
|
}
|
|
|
|
.data-table th:hover {
|
|
background: var(--terminal-dark-green);
|
|
color: var(--terminal-bg);
|
|
}
|
|
|
|
.data-table tr:hover {
|
|
background: rgba(0, 255, 0, 0.1);
|
|
}
|
|
|
|
.data-table tr.selected {
|
|
background: rgba(255, 176, 0, 0.2);
|
|
color: var(--terminal-amber);
|
|
}
|
|
|
|
.checkbox-cell {
|
|
width: 30px;
|
|
text-align: center;
|
|
}
|
|
|
|
.data-checkbox {
|
|
width: 15px;
|
|
height: 15px;
|
|
appearance: none;
|
|
border: 1px solid var(--terminal-green);
|
|
background: var(--terminal-bg);
|
|
cursor: pointer;
|
|
position: relative;
|
|
}
|
|
|
|
.data-checkbox:checked::after {
|
|
content: 'X';
|
|
position: absolute;
|
|
color: var(--terminal-green);
|
|
font-size: 12px;
|
|
left: 1px;
|
|
top: -3px;
|
|
}
|
|
|
|
/* Status Bar */
|
|
.status-bar {
|
|
border: 1px solid var(--terminal-green);
|
|
padding: 10px;
|
|
margin-top: 10px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
background: var(--terminal-bg-light);
|
|
font-size: 14px;
|
|
}
|
|
|
|
.status-info {
|
|
color: var(--terminal-amber);
|
|
}
|
|
|
|
/* Pagination */
|
|
.pagination {
|
|
display: flex;
|
|
gap: 10px;
|
|
align-items: center;
|
|
}
|
|
|
|
.page-button {
|
|
background: var(--terminal-bg);
|
|
border: 1px solid var(--terminal-green);
|
|
color: var(--terminal-green);
|
|
padding: 5px 10px;
|
|
cursor: pointer;
|
|
font-family: 'VT323', monospace;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.page-button:hover:not(:disabled) {
|
|
background: var(--terminal-green);
|
|
color: var(--terminal-bg);
|
|
}
|
|
|
|
.page-button:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.page-info {
|
|
color: var(--terminal-amber);
|
|
}
|
|
|
|
/* Loading Effect */
|
|
.loading {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
font-size: 24px;
|
|
color: var(--terminal-green);
|
|
}
|
|
|
|
.loading::after {
|
|
content: '';
|
|
animation: loading-dots 1.5s infinite;
|
|
}
|
|
|
|
@keyframes loading-dots {
|
|
0% { content: ''; }
|
|
25% { content: '.'; }
|
|
50% { content: '..'; }
|
|
75% { content: '...'; }
|
|
}
|
|
|
|
/* Export Modal */
|
|
.export-modal {
|
|
position: fixed;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: var(--terminal-bg);
|
|
border: 2px solid var(--terminal-green);
|
|
padding: 20px;
|
|
z-index: 2000;
|
|
display: none;
|
|
min-width: 400px;
|
|
}
|
|
|
|
.export-modal.show {
|
|
display: block;
|
|
}
|
|
|
|
.export-content {
|
|
margin: 20px 0;
|
|
padding: 10px;
|
|
background: var(--terminal-bg-light);
|
|
border: 1px solid var(--terminal-dark-green);
|
|
max-height: 300px;
|
|
overflow: auto;
|
|
white-space: pre-wrap;
|
|
font-size: 12px;
|
|
color: var(--terminal-amber);
|
|
}
|
|
|
|
/* Typing Effect */
|
|
.typing {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
animation: typing 3s steps(40, end);
|
|
}
|
|
|
|
@keyframes typing {
|
|
from { width: 0 }
|
|
to { width: 100% }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="terminal-container">
|
|
<div class="terminal-header">
|
|
<div class="terminal-title glow">
|
|
<span>DATATERM v16.0 - RETRO COMPUTING DATA EXPLORER</span>
|
|
<span>[SYSTEM: ONLINE]<span class="blink">█</span></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="command-line">
|
|
<span class="prompt">DATATERM://></span>
|
|
<input type="text" class="command-input" id="commandInput" placeholder="Type 'help' for commands...">
|
|
</div>
|
|
|
|
<div class="control-panel">
|
|
<div class="control-group">
|
|
<div class="control-label">Search Query</div>
|
|
<input type="text" class="control-input" id="searchInput" placeholder="ENTER SEARCH TERM...">
|
|
</div>
|
|
|
|
<div class="control-group">
|
|
<div class="control-label">Filter By Status</div>
|
|
<select class="control-input" id="statusFilter">
|
|
<option value="">ALL RECORDS</option>
|
|
<option value="ACTIVE">ACTIVE</option>
|
|
<option value="INACTIVE">INACTIVE</option>
|
|
<option value="PENDING">PENDING</option>
|
|
<option value="ARCHIVED">ARCHIVED</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="control-group">
|
|
<div class="control-label">Filter By Department</div>
|
|
<select class="control-input" id="deptFilter">
|
|
<option value="">ALL DEPARTMENTS</option>
|
|
<option value="ENGR">ENGINEERING</option>
|
|
<option value="MRKT">MARKETING</option>
|
|
<option value="FNCE">FINANCE</option>
|
|
<option value="OPRS">OPERATIONS</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="control-group">
|
|
<div class="control-label">Records Per Page</div>
|
|
<select class="control-input" id="pageSizeSelect">
|
|
<option value="10">10 RECORDS</option>
|
|
<option value="25">25 RECORDS</option>
|
|
<option value="50">50 RECORDS</option>
|
|
<option value="100">100 RECORDS</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="control-panel">
|
|
<div class="control-group">
|
|
<div class="control-label">Actions</div>
|
|
<button class="control-button" id="selectAllBtn">[SELECT ALL]</button>
|
|
<button class="control-button" id="clearAllBtn">[CLEAR ALL]</button>
|
|
<button class="control-button" id="exportBtn">[EXPORT DATA]</button>
|
|
<button class="control-button" id="refreshBtn">[REFRESH]</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="data-viewport">
|
|
<div class="loading glow" id="loadingIndicator">LOADING DATA</div>
|
|
<table class="data-table" id="dataTable" style="display: none;">
|
|
<thead>
|
|
<tr>
|
|
<th class="checkbox-cell">
|
|
<input type="checkbox" class="data-checkbox" id="selectAllCheckbox">
|
|
</th>
|
|
<th data-sort="id">ID ↕</th>
|
|
<th data-sort="timestamp">TIMESTAMP ↕</th>
|
|
<th data-sort="user">USER ↕</th>
|
|
<th data-sort="department">DEPT ↕</th>
|
|
<th data-sort="operation">OPERATION ↕</th>
|
|
<th data-sort="status">STATUS ↕</th>
|
|
<th data-sort="size">SIZE (KB) ↕</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="dataTableBody">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="status-bar">
|
|
<div class="status-info">
|
|
<span id="recordCount">0 RECORDS</span> |
|
|
<span id="selectedCount">0 SELECTED</span> |
|
|
<span id="filterStatus">NO FILTERS</span>
|
|
</div>
|
|
<div class="pagination">
|
|
<button class="page-button" id="firstPageBtn">[<<]</button>
|
|
<button class="page-button" id="prevPageBtn">[<]</button>
|
|
<span class="page-info" id="pageInfo">PAGE 1/1</span>
|
|
<button class="page-button" id="nextPageBtn">[>]</button>
|
|
<button class="page-button" id="lastPageBtn">[>>]</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="export-modal" id="exportModal">
|
|
<div class="terminal-header">
|
|
<div class="terminal-title glow">
|
|
<span>EXPORT DATA</span>
|
|
<button class="control-button" id="closeExportBtn">[X]</button>
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<div class="control-label">Export Format</div>
|
|
<select class="control-input" id="exportFormat">
|
|
<option value="csv">CSV FORMAT</option>
|
|
<option value="json">JSON FORMAT</option>
|
|
<option value="txt">TEXT FORMAT</option>
|
|
</select>
|
|
</div>
|
|
<div class="export-content" id="exportContent"></div>
|
|
<button class="control-button" id="downloadBtn">[DOWNLOAD FILE]</button>
|
|
<button class="control-button" id="copyBtn">[COPY TO CLIPBOARD]</button>
|
|
</div>
|
|
|
|
<script>
|
|
// Generate sample data
|
|
const departments = ['ENGR', 'MRKT', 'FNCE', 'OPRS'];
|
|
const operations = ['CREATE', 'UPDATE', 'DELETE', 'READ', 'BACKUP', 'RESTORE', 'SYNC', 'VERIFY'];
|
|
const statuses = ['ACTIVE', 'INACTIVE', 'PENDING', 'ARCHIVED'];
|
|
const users = ['USER_001', 'USER_002', 'USER_003', 'USER_004', 'USER_005', 'ADMIN_01', 'ADMIN_02', 'SYS_USER'];
|
|
|
|
let allData = [];
|
|
let filteredData = [];
|
|
let currentPage = 1;
|
|
let pageSize = 10;
|
|
let sortColumn = 'id';
|
|
let sortDirection = 'asc';
|
|
let selectedRows = new Set();
|
|
|
|
// Generate data
|
|
function generateData() {
|
|
allData = [];
|
|
for (let i = 1; i <= 500; i++) {
|
|
const timestamp = new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000);
|
|
allData.push({
|
|
id: `REC_${String(i).padStart(5, '0')}`,
|
|
timestamp: timestamp.toISOString().replace('T', ' ').substr(0, 19),
|
|
user: users[Math.floor(Math.random() * users.length)],
|
|
department: departments[Math.floor(Math.random() * departments.length)],
|
|
operation: operations[Math.floor(Math.random() * operations.length)],
|
|
status: statuses[Math.floor(Math.random() * statuses.length)],
|
|
size: Math.floor(Math.random() * 1000) + 1
|
|
});
|
|
}
|
|
filteredData = [...allData];
|
|
}
|
|
|
|
// Initialize
|
|
function init() {
|
|
generateData();
|
|
setTimeout(() => {
|
|
document.getElementById('loadingIndicator').style.display = 'none';
|
|
document.getElementById('dataTable').style.display = 'table';
|
|
renderTable();
|
|
updateStatus();
|
|
}, 1500);
|
|
|
|
// Event listeners
|
|
document.getElementById('searchInput').addEventListener('input', applyFilters);
|
|
document.getElementById('statusFilter').addEventListener('change', applyFilters);
|
|
document.getElementById('deptFilter').addEventListener('change', applyFilters);
|
|
document.getElementById('pageSizeSelect').addEventListener('change', (e) => {
|
|
pageSize = parseInt(e.target.value);
|
|
currentPage = 1;
|
|
renderTable();
|
|
});
|
|
|
|
// Command input
|
|
document.getElementById('commandInput').addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') {
|
|
processCommand(e.target.value);
|
|
e.target.value = '';
|
|
}
|
|
});
|
|
|
|
// Sorting
|
|
document.querySelectorAll('[data-sort]').forEach(th => {
|
|
th.addEventListener('click', () => {
|
|
const column = th.dataset.sort;
|
|
if (sortColumn === column) {
|
|
sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
|
|
} else {
|
|
sortColumn = column;
|
|
sortDirection = 'asc';
|
|
}
|
|
sortData();
|
|
renderTable();
|
|
});
|
|
});
|
|
|
|
// Selection
|
|
document.getElementById('selectAllCheckbox').addEventListener('change', (e) => {
|
|
const checkboxes = document.querySelectorAll('.row-checkbox');
|
|
checkboxes.forEach(cb => {
|
|
cb.checked = e.target.checked;
|
|
const row = cb.closest('tr');
|
|
const id = row.dataset.id;
|
|
if (e.target.checked) {
|
|
selectedRows.add(id);
|
|
row.classList.add('selected');
|
|
} else {
|
|
selectedRows.delete(id);
|
|
row.classList.remove('selected');
|
|
}
|
|
});
|
|
updateStatus();
|
|
});
|
|
|
|
// Buttons
|
|
document.getElementById('selectAllBtn').addEventListener('click', () => {
|
|
filteredData.forEach(item => selectedRows.add(item.id));
|
|
renderTable();
|
|
updateStatus();
|
|
});
|
|
|
|
document.getElementById('clearAllBtn').addEventListener('click', () => {
|
|
selectedRows.clear();
|
|
document.getElementById('selectAllCheckbox').checked = false;
|
|
renderTable();
|
|
updateStatus();
|
|
});
|
|
|
|
document.getElementById('exportBtn').addEventListener('click', showExportModal);
|
|
document.getElementById('refreshBtn').addEventListener('click', () => {
|
|
generateData();
|
|
applyFilters();
|
|
});
|
|
|
|
// Pagination
|
|
document.getElementById('firstPageBtn').addEventListener('click', () => {
|
|
currentPage = 1;
|
|
renderTable();
|
|
});
|
|
|
|
document.getElementById('prevPageBtn').addEventListener('click', () => {
|
|
if (currentPage > 1) {
|
|
currentPage--;
|
|
renderTable();
|
|
}
|
|
});
|
|
|
|
document.getElementById('nextPageBtn').addEventListener('click', () => {
|
|
if (currentPage < getTotalPages()) {
|
|
currentPage++;
|
|
renderTable();
|
|
}
|
|
});
|
|
|
|
document.getElementById('lastPageBtn').addEventListener('click', () => {
|
|
currentPage = getTotalPages();
|
|
renderTable();
|
|
});
|
|
|
|
// Export modal
|
|
document.getElementById('closeExportBtn').addEventListener('click', hideExportModal);
|
|
document.getElementById('exportFormat').addEventListener('change', updateExportPreview);
|
|
document.getElementById('downloadBtn').addEventListener('click', downloadExport);
|
|
document.getElementById('copyBtn').addEventListener('click', copyToClipboard);
|
|
}
|
|
|
|
// Process commands
|
|
function processCommand(command) {
|
|
const cmd = command.toLowerCase().trim();
|
|
|
|
switch (cmd) {
|
|
case 'help':
|
|
alert('AVAILABLE COMMANDS:\n\n' +
|
|
'HELP - Show this menu\n' +
|
|
'CLEAR - Clear all filters\n' +
|
|
'SELECT ALL - Select all records\n' +
|
|
'EXPORT - Export selected data\n' +
|
|
'REFRESH - Reload data\n' +
|
|
'SORT [COLUMN] - Sort by column\n' +
|
|
'FILTER [COLUMN] [VALUE] - Apply filter');
|
|
break;
|
|
case 'clear':
|
|
document.getElementById('searchInput').value = '';
|
|
document.getElementById('statusFilter').value = '';
|
|
document.getElementById('deptFilter').value = '';
|
|
applyFilters();
|
|
break;
|
|
case 'select all':
|
|
document.getElementById('selectAllBtn').click();
|
|
break;
|
|
case 'export':
|
|
document.getElementById('exportBtn').click();
|
|
break;
|
|
case 'refresh':
|
|
document.getElementById('refreshBtn').click();
|
|
break;
|
|
default:
|
|
if (cmd.startsWith('sort ')) {
|
|
const column = cmd.substr(5);
|
|
const th = document.querySelector(`[data-sort="${column}"]`);
|
|
if (th) th.click();
|
|
} else if (cmd.startsWith('filter ')) {
|
|
const parts = cmd.substr(7).split(' ');
|
|
if (parts.length >= 2) {
|
|
const [column, ...valueParts] = parts;
|
|
const value = valueParts.join(' ');
|
|
|
|
if (column === 'status') {
|
|
document.getElementById('statusFilter').value = value.toUpperCase();
|
|
} else if (column === 'department' || column === 'dept') {
|
|
document.getElementById('deptFilter').value = value.toUpperCase();
|
|
} else {
|
|
document.getElementById('searchInput').value = value;
|
|
}
|
|
applyFilters();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply filters
|
|
function applyFilters() {
|
|
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
|
|
const statusFilter = document.getElementById('statusFilter').value;
|
|
const deptFilter = document.getElementById('deptFilter').value;
|
|
|
|
filteredData = allData.filter(item => {
|
|
const matchesSearch = !searchTerm ||
|
|
Object.values(item).some(val =>
|
|
String(val).toLowerCase().includes(searchTerm)
|
|
);
|
|
const matchesStatus = !statusFilter || item.status === statusFilter;
|
|
const matchesDept = !deptFilter || item.department === deptFilter;
|
|
|
|
return matchesSearch && matchesStatus && matchesDept;
|
|
});
|
|
|
|
currentPage = 1;
|
|
sortData();
|
|
renderTable();
|
|
updateStatus();
|
|
}
|
|
|
|
// Sort data
|
|
function sortData() {
|
|
filteredData.sort((a, b) => {
|
|
let aVal = a[sortColumn];
|
|
let bVal = b[sortColumn];
|
|
|
|
if (sortColumn === 'size') {
|
|
aVal = parseInt(aVal);
|
|
bVal = parseInt(bVal);
|
|
}
|
|
|
|
if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1;
|
|
if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1;
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
// Get total pages
|
|
function getTotalPages() {
|
|
return Math.ceil(filteredData.length / pageSize);
|
|
}
|
|
|
|
// Render table
|
|
function renderTable() {
|
|
const tbody = document.getElementById('dataTableBody');
|
|
tbody.innerHTML = '';
|
|
|
|
const start = (currentPage - 1) * pageSize;
|
|
const end = start + pageSize;
|
|
const pageData = filteredData.slice(start, end);
|
|
|
|
pageData.forEach(item => {
|
|
const row = document.createElement('tr');
|
|
row.dataset.id = item.id;
|
|
if (selectedRows.has(item.id)) {
|
|
row.classList.add('selected');
|
|
}
|
|
|
|
row.innerHTML = `
|
|
<td class="checkbox-cell">
|
|
<input type="checkbox" class="data-checkbox row-checkbox"
|
|
${selectedRows.has(item.id) ? 'checked' : ''}>
|
|
</td>
|
|
<td>${item.id}</td>
|
|
<td>${item.timestamp}</td>
|
|
<td>${item.user}</td>
|
|
<td>${item.department}</td>
|
|
<td>${item.operation}</td>
|
|
<td>${item.status}</td>
|
|
<td>${item.size}</td>
|
|
`;
|
|
|
|
const checkbox = row.querySelector('.row-checkbox');
|
|
checkbox.addEventListener('change', (e) => {
|
|
if (e.target.checked) {
|
|
selectedRows.add(item.id);
|
|
row.classList.add('selected');
|
|
} else {
|
|
selectedRows.delete(item.id);
|
|
row.classList.remove('selected');
|
|
}
|
|
updateStatus();
|
|
});
|
|
|
|
tbody.appendChild(row);
|
|
});
|
|
|
|
// Update pagination
|
|
document.getElementById('pageInfo').textContent = `PAGE ${currentPage}/${getTotalPages() || 1}`;
|
|
document.getElementById('firstPageBtn').disabled = currentPage === 1;
|
|
document.getElementById('prevPageBtn').disabled = currentPage === 1;
|
|
document.getElementById('nextPageBtn').disabled = currentPage >= getTotalPages();
|
|
document.getElementById('lastPageBtn').disabled = currentPage >= getTotalPages();
|
|
}
|
|
|
|
// Update status
|
|
function updateStatus() {
|
|
document.getElementById('recordCount').textContent = `${filteredData.length} RECORDS`;
|
|
document.getElementById('selectedCount').textContent = `${selectedRows.size} SELECTED`;
|
|
|
|
const filters = [];
|
|
if (document.getElementById('searchInput').value) filters.push('SEARCH');
|
|
if (document.getElementById('statusFilter').value) filters.push('STATUS');
|
|
if (document.getElementById('deptFilter').value) filters.push('DEPT');
|
|
|
|
document.getElementById('filterStatus').textContent =
|
|
filters.length ? `FILTERS: ${filters.join(', ')}` : 'NO FILTERS';
|
|
}
|
|
|
|
// Export functions
|
|
function showExportModal() {
|
|
document.getElementById('exportModal').classList.add('show');
|
|
updateExportPreview();
|
|
}
|
|
|
|
function hideExportModal() {
|
|
document.getElementById('exportModal').classList.remove('show');
|
|
}
|
|
|
|
function updateExportPreview() {
|
|
const format = document.getElementById('exportFormat').value;
|
|
const dataToExport = selectedRows.size > 0
|
|
? filteredData.filter(item => selectedRows.has(item.id))
|
|
: filteredData;
|
|
|
|
let content = '';
|
|
|
|
if (format === 'csv') {
|
|
content = 'ID,TIMESTAMP,USER,DEPARTMENT,OPERATION,STATUS,SIZE_KB\n';
|
|
dataToExport.forEach(item => {
|
|
content += `${item.id},${item.timestamp},${item.user},${item.department},${item.operation},${item.status},${item.size}\n`;
|
|
});
|
|
} else if (format === 'json') {
|
|
content = JSON.stringify(dataToExport, null, 2);
|
|
} else if (format === 'txt') {
|
|
dataToExport.forEach(item => {
|
|
content += `========================================\n`;
|
|
content += `ID: ${item.id}\n`;
|
|
content += `TIMESTAMP: ${item.timestamp}\n`;
|
|
content += `USER: ${item.user}\n`;
|
|
content += `DEPARTMENT: ${item.department}\n`;
|
|
content += `OPERATION: ${item.operation}\n`;
|
|
content += `STATUS: ${item.status}\n`;
|
|
content += `SIZE: ${item.size} KB\n`;
|
|
});
|
|
}
|
|
|
|
document.getElementById('exportContent').textContent = content;
|
|
}
|
|
|
|
function downloadExport() {
|
|
const format = document.getElementById('exportFormat').value;
|
|
const content = document.getElementById('exportContent').textContent;
|
|
|
|
const blob = new Blob([content], { type: 'text/plain' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `dataterm_export_${Date.now()}.${format}`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
function copyToClipboard() {
|
|
const content = document.getElementById('exportContent').textContent;
|
|
navigator.clipboard.writeText(content).then(() => {
|
|
const btn = document.getElementById('copyBtn');
|
|
const originalText = btn.textContent;
|
|
btn.textContent = '[COPIED!]';
|
|
setTimeout(() => {
|
|
btn.textContent = originalText;
|
|
}, 2000);
|
|
});
|
|
}
|
|
|
|
// Initialize on load
|
|
window.addEventListener('load', init);
|
|
</script>
|
|
</body>
|
|
</html> |