plugins(files): Feature 10 — Navigation history

- History stack with Back/Forward (goBack/goForward)
- historyIndex + navigatingHistory flag for correct stack management
- Toolbar buttons: ← (back) and → (forward) before Up button
- Alt+Left / Alt+Right and Ctrl+[ / Ctrl+] keyboard shortcuts
- Future path trimmed on new navigation (forward state discarded)
- Duplicate paths not pushed to stack
- Refresh and direct loadEntries don't pollute history
This commit is contained in:
mirivlad 2026-06-20 20:01:20 +08:00
parent 4a0656cd09
commit c3a14411ab
1 changed files with 47 additions and 2 deletions

View File

@ -231,6 +231,9 @@
var createMode = '';
var renameTarget = null;
var disposed = false;
var historyStack = [''];
var historyIndex = 0;
var navigatingHistory = false;
function scopedPath(local) {
local = cleanPath(local);
@ -246,6 +249,8 @@
var toolbar = el('div', { className: 'files-toolbar' });
var breadcrumb = el('div', { className: 'files-breadcrumb' });
var backBtn = el('button', { className: 'files-toolbar-btn', 'data-files-action': 'back', title: 'Back (Alt+Left)' }, ['\u2190']);
var forwardBtn = el('button', { className: 'files-toolbar-btn', 'data-files-action': 'forward', title: 'Forward (Alt+Right)' }, ['\u2192']);
var upBtn = el('button', { className: 'files-toolbar-btn', 'data-files-action': 'up', title: 'Up' }, ['Up']);
var refreshBtn = el('button', { className: 'files-toolbar-btn', 'data-files-action': 'refresh', title: 'Refresh' }, ['Refresh']);
var newFolderBtn = el('button', { className: 'files-toolbar-btn', 'data-files-action': 'new-folder' }, ['+ Folder']);
@ -264,7 +269,7 @@
el('option', { value: 'size-desc' }, ['Size'])
]);
toolbar.appendChild(breadcrumb);
[upBtn, refreshBtn, newFolderBtn, newMdBtn, newTextBtn, openBtn, renameBtn, trashBtn, pasteBtn, filterInput, sortSelect].forEach(function (node) { toolbar.appendChild(node); });
[backBtn, forwardBtn, upBtn, refreshBtn, newFolderBtn, newMdBtn, newTextBtn, openBtn, renameBtn, trashBtn, pasteBtn, filterInput, sortSelect].forEach(function (node) { toolbar.appendChild(node); });
containerEl.appendChild(toolbar);
var listContainer = el('div', { className: 'files-list', 'data-files-list': '' });
@ -307,6 +312,11 @@
pasteBtn.disabled = !window.__filesClipboard;
}
function updateHistoryButtons() {
backBtn.disabled = historyIndex <= 0;
forwardBtn.disabled = historyIndex >= historyStack.length - 1;
}
function updateBreadcrumb() {
breadcrumb.innerHTML = '';
var root = el('span', { className: currentPath ? 'files-breadcrumb-item' : 'files-breadcrumb-current', onClick: function () { navigateTo(''); } }, [workspaceName]);
@ -480,12 +490,39 @@
}
function navigateTo(path) {
currentPath = cleanPath(path);
var newPath = cleanPath(path);
if (!navigatingHistory) {
if (historyIndex < historyStack.length - 1) {
historyStack = historyStack.slice(0, historyIndex + 1);
}
if (historyStack[historyStack.length - 1] !== newPath) {
historyStack.push(newPath);
historyIndex = historyStack.length - 1;
}
}
currentPath = newPath;
cancelCreate();
cancelRename();
updateHistoryButtons();
loadEntries();
}
function goBack() {
if (historyIndex <= 0) return;
historyIndex--;
navigatingHistory = true;
navigateTo(historyStack[historyIndex]);
navigatingHistory = false;
}
function goForward() {
if (historyIndex >= historyStack.length - 1) return;
historyIndex++;
navigatingHistory = true;
navigateTo(historyStack[historyIndex]);
navigatingHistory = false;
}
function goUp() {
if (currentPath) navigateTo(parentPath(currentPath));
}
@ -608,6 +645,8 @@
}
}
backBtn.addEventListener('click', goBack);
forwardBtn.addEventListener('click', goForward);
refreshBtn.addEventListener('click', loadEntries);
upBtn.addEventListener('click', goUp);
newFolderBtn.addEventListener('click', function () { startCreate('folder'); });
@ -929,6 +968,11 @@
beginRename();
return;
}
if (key === 'ArrowLeft' && event.altKey) { event.preventDefault(); goBack(); return; }
if (key === 'ArrowRight' && event.altKey) { event.preventDefault(); goForward(); return; }
if (key === '[' && ctrl) { event.preventDefault(); goBack(); return; }
if (key === ']' && ctrl) { event.preventDefault(); goForward(); return; }
if (key === 'a' && (ctrl || event.metaKey)) {
event.preventDefault();
var vis = visibleEntries();
@ -970,6 +1014,7 @@
}
});
updateHistoryButtons();
loadEntries();
containerEl.__filesCleanup = function () {