Files
photo-renamer/src/renderer/history.js
T

70 lines
2.1 KiB
JavaScript

// History entries
// reorder: { type:'reorder', files:[...], affectedPaths: Set|null }
// delete: { type:'delete', files:[...] /* filesAfter */,
// deletedEntries:[{name, originalPath, stagingPath}] /* mutable */ }
const MAX = 50;
let _stack = [];
let _cursor = -1;
let _onUpdate = null;
export function setOnUpdate(fn) { _onUpdate = fn; }
// ── Push ─────────────────────────────────────────
export function pushReorder(files, affectedPaths = null) {
_truncate();
_stack.push({
type: 'reorder',
files: [...files],
affectedPaths: affectedPaths ? new Set(affectedPaths) : null,
});
_finalize();
}
export function pushDelete(filesAfter, deletedEntries) {
_truncate();
_stack.push({ type: 'delete', files: [...filesAfter], deletedEntries });
_finalize();
}
function _truncate() { _stack = _stack.slice(0, _cursor + 1); }
function _finalize() {
if (_stack.length > MAX) _stack.shift();
_cursor = _stack.length - 1;
_onUpdate?.();
}
// ── Undo / Redo ───────────────────────────────────
// Returns { entry, targetFiles }
// entry — the entry being undone/redone (for type-specific side-effects)
// targetFiles — the files[] to restore in state
export function undo() {
if (!canUndo()) return null;
const entry = _stack[_cursor]; // operation being undone
--_cursor;
_onUpdate?.();
return { entry, targetFiles: [..._stack[_cursor].files] };
}
export function redo() {
if (!canRedo()) return null;
++_cursor;
_onUpdate?.();
const entry = _stack[_cursor];
return { entry, targetFiles: [...entry.files] };
}
// Peek at the next redo entry without moving cursor (for pre-processing)
export function peekRedo() {
return canRedo() ? _stack[_cursor + 1] : null;
}
export function canUndo() { return _cursor > 0; }
export function canRedo() { return _cursor < _stack.length - 1; }
export function reset() {
_stack = [];
_cursor = -1;
_onUpdate?.();
}