initial commit , first one was bullshit
This commit is contained in:
267
src/main/resources/HTML/script.js
vendored
Normal file
267
src/main/resources/HTML/script.js
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const fileList = document.getElementById('file-list');
|
||||
const backBtn = document.getElementById('back-btn');
|
||||
const forwardBtn = document.getElementById('forward-btn');
|
||||
const upBtn = document.getElementById('up-btn');
|
||||
const addressInput = document.getElementById('address-input');
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const statusText = document.getElementById('status-text');
|
||||
|
||||
let history = ['/'];
|
||||
let historyIndex = 0;
|
||||
let forwardStack = [];
|
||||
let selectedIndex = -1;
|
||||
let currentItems = [];
|
||||
|
||||
function getCurrentPath() {
|
||||
return history[historyIndex];
|
||||
}
|
||||
|
||||
function setAddressBar() {
|
||||
let p = getCurrentPath();
|
||||
addressInput.value = p === '/' ? 'Computer' : p;
|
||||
}
|
||||
|
||||
function updateSelection() {
|
||||
const items = fileList.querySelectorAll('.file-item');
|
||||
items.forEach((item, index) => {
|
||||
item.classList.toggle('focused', index === selectedIndex);
|
||||
});
|
||||
}
|
||||
|
||||
function selectItem(index) {
|
||||
const items = fileList.querySelectorAll('.file-item');
|
||||
if (index >= 0 && index < items.length) {
|
||||
selectedIndex = index;
|
||||
updateSelection();
|
||||
// Scroll into view
|
||||
items[selectedIndex].scrollIntoView({ block: 'nearest' });
|
||||
|
||||
// Update status
|
||||
if (currentItems[selectedIndex]) {
|
||||
const item = currentItems[selectedIndex];
|
||||
statusText.textContent = `Selected: ${item.name} (${item.isDir ? 'Folder' : 'File'})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openSelectedItem() {
|
||||
if (selectedIndex >= 0 && selectedIndex < currentItems.length) {
|
||||
const item = currentItems[selectedIndex];
|
||||
if (item.isDir) {
|
||||
let cur = getCurrentPath();
|
||||
let next = cur.endsWith('/') ? cur + item.name : cur + '/' + item.name;
|
||||
history = history.slice(0, historyIndex + 1);
|
||||
history.push(next);
|
||||
historyIndex++;
|
||||
forwardStack = [];
|
||||
selectedIndex = -1;
|
||||
fetchFiles();
|
||||
} else {
|
||||
// Download file
|
||||
let cur = getCurrentPath();
|
||||
let filePath = cur.endsWith('/') ? cur + item.name : cur + '/' + item.name;
|
||||
window.location.href = `/api/download?path=${encodeURIComponent(filePath)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fetchFiles(searchTerm = '') {
|
||||
setAddressBar();
|
||||
statusText.textContent = 'Loading...';
|
||||
let path = getCurrentPath();
|
||||
let url = `/api/list-isos?path=${encodeURIComponent(path)}`;
|
||||
if (searchTerm) {
|
||||
url += `&search=${encodeURIComponent(searchTerm)}`;
|
||||
}
|
||||
fetch(url)
|
||||
.then(res => {
|
||||
if (!res.ok) throw new Error('Failed to fetch file list');
|
||||
return res.json();
|
||||
})
|
||||
.then(items => {
|
||||
fileList.innerHTML = '';
|
||||
currentItems = [];
|
||||
selectedIndex = -1;
|
||||
if (!items.length) {
|
||||
fileList.innerHTML = '<div class="file-item" style="grid-column: 1 / -1; text-align: center; color: #888;">No files or folders found.</div>';
|
||||
statusText.textContent = 'No items found';
|
||||
return;
|
||||
}
|
||||
currentItems = items;
|
||||
items.forEach((item, index) => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'file-item';
|
||||
div.dataset.index = index;
|
||||
|
||||
// Icon
|
||||
const icon = document.createElement('img');
|
||||
icon.className = 'icon';
|
||||
icon.src = item.isDir ? 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTIgM0MxLjQ0NzcyIDMgMSAzLjQ0NzcyIDEgNFYxMkMxIDEyLjU1MjMgMS40NDc3MiAxMyAyIDEzSDE0QzE0LjU1MjMgMTMgMTUgMTIuNTUyMyAxNSAxMlY2QzE1IDUuNDQ3NzIgMTQuNTUyMyA1IDE0IDVIOEw2IDNIMloiIGZpbGw9IiNGRkQ3MDAiLz4KPC9zdmc+' : 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTMgM0MyLjQ0NzcyIDMgMiAzLjQ0NzcyIDIgNFYxMkMyIDEyLjU1MjMgMi40NDc3MiAxMyAzIDEzSDEzQzEzLjU1MjMgMTMgMTQgMTIuNTUyMyAxNCAxMlY0QzE0IDMuNDQ3NzIgMTMuNTUyMyAzIDEzIDNIM1oiIGZpbGw9IiM4ODg4ODgiLz4KPC9zdmc+';
|
||||
icon.onerror = () => icon.style.display = 'none';
|
||||
div.appendChild(icon);
|
||||
|
||||
// Name (show relative path if searching)
|
||||
const nameSpan = document.createElement('span');
|
||||
nameSpan.className = 'file-name';
|
||||
if (searchTerm && item.path) {
|
||||
nameSpan.textContent = item.path;
|
||||
} else {
|
||||
nameSpan.textContent = item.name;
|
||||
}
|
||||
div.appendChild(nameSpan);
|
||||
|
||||
// Type
|
||||
const typeSpan = document.createElement('span');
|
||||
typeSpan.className = 'file-type';
|
||||
typeSpan.textContent = item.isDir ? 'Folder' : 'File';
|
||||
div.appendChild(typeSpan);
|
||||
|
||||
// Size
|
||||
const sizeSpan = document.createElement('span');
|
||||
sizeSpan.className = 'file-size';
|
||||
sizeSpan.textContent = item.isDir ? '' : '-';
|
||||
div.appendChild(sizeSpan);
|
||||
|
||||
// Date Modified
|
||||
const dateSpan = document.createElement('span');
|
||||
dateSpan.className = 'file-date';
|
||||
dateSpan.textContent = '';
|
||||
div.appendChild(dateSpan);
|
||||
|
||||
// Action
|
||||
const actionDiv = document.createElement('div');
|
||||
if (!item.isDir) {
|
||||
const dlBtn = document.createElement('button');
|
||||
dlBtn.className = 'download-btn';
|
||||
dlBtn.textContent = 'Download';
|
||||
dlBtn.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
let cur = getCurrentPath();
|
||||
let filePath = cur.endsWith('/') ? cur + item.name : cur + '/' + item.name;
|
||||
window.location.href = `/api/download?path=${encodeURIComponent(filePath)}`;
|
||||
};
|
||||
actionDiv.appendChild(dlBtn);
|
||||
}
|
||||
div.appendChild(actionDiv);
|
||||
|
||||
// Click handlers
|
||||
div.onclick = () => {
|
||||
selectItem(index);
|
||||
if (item.isDir) {
|
||||
setTimeout(() => openSelectedItem(), 200);
|
||||
}
|
||||
};
|
||||
|
||||
fileList.appendChild(div);
|
||||
});
|
||||
|
||||
statusText.textContent = `${items.length} item${items.length !== 1 ? 's' : ''}`;
|
||||
|
||||
// Update button states
|
||||
backBtn.disabled = historyIndex <= 0;
|
||||
forwardBtn.disabled = historyIndex >= history.length - 1;
|
||||
upBtn.disabled = getCurrentPath() === '/';
|
||||
})
|
||||
.catch(err => {
|
||||
fileList.innerHTML = `<div class="file-item" style="grid-column: 1 / -1; text-align: center; color: #d9534f;">${err.message}</div>`;
|
||||
statusText.textContent = 'Error loading files';
|
||||
});
|
||||
}
|
||||
|
||||
// Navigation event handlers
|
||||
backBtn.addEventListener('click', () => {
|
||||
if (historyIndex > 0) {
|
||||
historyIndex--;
|
||||
selectedIndex = -1;
|
||||
fetchFiles();
|
||||
}
|
||||
});
|
||||
|
||||
forwardBtn.addEventListener('click', () => {
|
||||
if (historyIndex < history.length - 1) {
|
||||
historyIndex++;
|
||||
selectedIndex = -1;
|
||||
fetchFiles();
|
||||
}
|
||||
});
|
||||
|
||||
upBtn.addEventListener('click', () => {
|
||||
let cur = getCurrentPath();
|
||||
if (cur === '/' || cur === '') return;
|
||||
let parts = cur.split('/').filter(Boolean);
|
||||
parts.pop();
|
||||
let upPath = '/' + parts.join('/');
|
||||
if (upPath === '') upPath = '/';
|
||||
history = history.slice(0, historyIndex + 1);
|
||||
history.push(upPath);
|
||||
historyIndex++;
|
||||
selectedIndex = -1;
|
||||
fetchFiles();
|
||||
});
|
||||
|
||||
addressInput.addEventListener('click', () => {
|
||||
addressInput.select();
|
||||
});
|
||||
|
||||
searchInput.addEventListener('input', (e) => {
|
||||
selectedIndex = -1;
|
||||
fetchFiles(e.target.value);
|
||||
});
|
||||
|
||||
// Keyboard navigation
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.target.tagName === 'INPUT') return;
|
||||
|
||||
switch(e.key) {
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
if (selectedIndex > 0) {
|
||||
selectItem(selectedIndex - 1);
|
||||
} else if (currentItems.length > 0) {
|
||||
selectItem(currentItems.length - 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
if (selectedIndex < currentItems.length - 1) {
|
||||
selectItem(selectedIndex + 1);
|
||||
} else if (currentItems.length > 0) {
|
||||
selectItem(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Enter':
|
||||
e.preventDefault();
|
||||
openSelectedItem();
|
||||
break;
|
||||
|
||||
case 'Escape':
|
||||
e.preventDefault();
|
||||
selectedIndex = -1;
|
||||
updateSelection();
|
||||
statusText.textContent = `${currentItems.length} item${currentItems.length !== 1 ? 's' : ''}`;
|
||||
break;
|
||||
|
||||
case 'Backspace':
|
||||
e.preventDefault();
|
||||
upBtn.click();
|
||||
break;
|
||||
|
||||
case 'F5':
|
||||
e.preventDefault();
|
||||
selectedIndex = -1;
|
||||
fetchFiles(searchInput.value);
|
||||
break;
|
||||
|
||||
case '/':
|
||||
e.preventDefault();
|
||||
searchInput.focus();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Initial load
|
||||
fetchFiles();
|
||||
});
|
||||
Reference in New Issue
Block a user