feat: Renamen functionaliteit aangepast
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -38,7 +38,7 @@ class UiSmokeGoldenTest(unittest.TestCase):
|
||||
self.assertIn('id="right-items"', body)
|
||||
self.assertIn('id="function-bar"', body)
|
||||
self.assertIn('id="settings-btn"', body)
|
||||
self.assertIn('id="rename-placeholder-btn"', body)
|
||||
self.assertIn('id="rename-btn"', body)
|
||||
self.assertIn('id="view-btn"', body)
|
||||
self.assertIn('id="edit-btn"', body)
|
||||
self.assertIn("F1", body)
|
||||
@@ -51,6 +51,9 @@ class UiSmokeGoldenTest(unittest.TestCase):
|
||||
self.assertIn("F8", body)
|
||||
self.assertIn('id="viewer-modal"', body)
|
||||
self.assertIn('id="settings-modal"', body)
|
||||
self.assertIn('id="rename-popup"', body)
|
||||
self.assertIn('id="rename-input"', body)
|
||||
self.assertIn('id="rename-apply-btn"', body)
|
||||
self.assertIn('id="settings-general-tab"', body)
|
||||
self.assertIn('id="settings-logs-tab"', body)
|
||||
self.assertIn('id="settings-logs-list"', body)
|
||||
@@ -77,20 +80,16 @@ class UiSmokeGoldenTest(unittest.TestCase):
|
||||
|
||||
ordered_ids = [
|
||||
'id="settings-btn"',
|
||||
'id="rename-placeholder-btn"',
|
||||
'id="rename-btn"',
|
||||
'id="view-btn"',
|
||||
'id="edit-btn"',
|
||||
'id="copy-btn"',
|
||||
'id="move-btn"',
|
||||
'id="rename-btn"',
|
||||
'id="mkdir-btn"',
|
||||
'id="delete-btn"',
|
||||
]
|
||||
positions = [body.index(marker) for marker in ordered_ids]
|
||||
self.assertEqual(positions, sorted(positions))
|
||||
rename_placeholder_index = body.index('id="rename-placeholder-btn"')
|
||||
disabled_index = body.index("disabled", rename_placeholder_index)
|
||||
self.assertLess(rename_placeholder_index, disabled_index)
|
||||
|
||||
def test_ui_static_assets_are_present_and_mapped(self) -> None:
|
||||
mount = self._ui_mount()
|
||||
@@ -106,6 +105,9 @@ class UiSmokeGoldenTest(unittest.TestCase):
|
||||
self.assertIn('if (event.key === "F1") {', app_js)
|
||||
self.assertIn('if (event.key === "F2") {', app_js)
|
||||
self.assertIn('function openSettings(tab = "general")', app_js)
|
||||
self.assertIn('function openRenamePopup()', app_js)
|
||||
self.assertIn('document.getElementById("rename-btn").onclick = openRenamePopup;', app_js)
|
||||
self.assertIn('return triggerActionButton("rename-btn");', app_js)
|
||||
self.assertIn('await apiRequest("GET", "/api/history")', app_js)
|
||||
self.assertIn('Cross-root directory move is not supported in v1', app_js)
|
||||
self.assertIn('Batch directory move is not supported in v1', app_js)
|
||||
|
||||
+126
-2
@@ -34,6 +34,10 @@ let renameMoveState = {
|
||||
source: null,
|
||||
destination: "",
|
||||
};
|
||||
let renameState = {
|
||||
source: null,
|
||||
name: "",
|
||||
};
|
||||
let batchMoveState = {
|
||||
destinationBase: "",
|
||||
count: 0,
|
||||
@@ -147,6 +151,17 @@ function renameMoveElements() {
|
||||
};
|
||||
}
|
||||
|
||||
function renameElements() {
|
||||
return {
|
||||
overlay: document.getElementById("rename-popup"),
|
||||
input: document.getElementById("rename-input"),
|
||||
error: document.getElementById("rename-error"),
|
||||
applyButton: document.getElementById("rename-apply-btn"),
|
||||
cancelButton: document.getElementById("rename-cancel-btn"),
|
||||
closeButton: document.getElementById("rename-close-btn"),
|
||||
};
|
||||
}
|
||||
|
||||
function batchMoveElements() {
|
||||
return {
|
||||
overlay: document.getElementById("batch-move-popup"),
|
||||
@@ -920,7 +935,7 @@ function actionShortcutHandled(event) {
|
||||
return triggerActionButton("settings-btn");
|
||||
}
|
||||
if (event.key === "F2") {
|
||||
return false;
|
||||
return triggerActionButton("rename-btn");
|
||||
}
|
||||
if (event.key === "F3") {
|
||||
return triggerActionButton("view-btn");
|
||||
@@ -991,6 +1006,10 @@ function isRenameMovePopupOpen() {
|
||||
return !renameMoveElements().overlay.classList.contains("hidden");
|
||||
}
|
||||
|
||||
function isRenamePopupOpen() {
|
||||
return !renameElements().overlay.classList.contains("hidden");
|
||||
}
|
||||
|
||||
function isBatchMovePopupOpen() {
|
||||
return !batchMoveElements().overlay.classList.contains("hidden");
|
||||
}
|
||||
@@ -1076,6 +1095,38 @@ function resetRenameMoveState() {
|
||||
};
|
||||
}
|
||||
|
||||
function resetRenameState() {
|
||||
renameState = {
|
||||
source: null,
|
||||
name: "",
|
||||
};
|
||||
}
|
||||
|
||||
function closeRenamePopup() {
|
||||
const elements = renameElements();
|
||||
elements.overlay.classList.add("hidden");
|
||||
elements.error.textContent = "";
|
||||
elements.input.value = "";
|
||||
resetRenameState();
|
||||
}
|
||||
|
||||
function openRenamePopup() {
|
||||
const selectedItems = activePaneState().selectedItems;
|
||||
if (selectedItems.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
const source = selectedItems[0];
|
||||
const elements = renameElements();
|
||||
renameState.source = source;
|
||||
renameState.name = source.name;
|
||||
elements.input.value = source.name;
|
||||
elements.error.textContent = "";
|
||||
elements.overlay.classList.remove("hidden");
|
||||
elements.input.focus();
|
||||
elements.input.select();
|
||||
return true;
|
||||
}
|
||||
|
||||
function resetBatchMoveState() {
|
||||
batchMoveState = {
|
||||
destinationBase: "",
|
||||
@@ -1154,6 +1205,45 @@ function openF6Flow() {
|
||||
return openBatchMovePopup(selectedItems);
|
||||
}
|
||||
|
||||
async function submitRenamePopup() {
|
||||
const elements = renameElements();
|
||||
const source = renameState.source;
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
const newName = elements.input.value.trim();
|
||||
elements.error.textContent = "";
|
||||
if (!newName) {
|
||||
elements.error.textContent = "Name is required";
|
||||
return;
|
||||
}
|
||||
if (newName === source.name) {
|
||||
elements.error.textContent = "Name must differ from current name";
|
||||
return;
|
||||
}
|
||||
if (newName.includes("/")) {
|
||||
elements.error.textContent = "Name cannot contain /";
|
||||
return;
|
||||
}
|
||||
if (newName === "." || newName === "..") {
|
||||
elements.error.textContent = "Invalid name";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await apiRequest("POST", "/api/files/rename", {
|
||||
path: source.path,
|
||||
new_name: newName,
|
||||
});
|
||||
closeRenamePopup();
|
||||
setSelectedItem(state.activePane, null);
|
||||
await loadBrowsePane(state.activePane);
|
||||
setStatus(`Renamed ${source.path}`);
|
||||
} catch (err) {
|
||||
elements.error.textContent = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
async function submitRenameMovePopup() {
|
||||
const elements = renameMoveElements();
|
||||
const source = renameMoveState.source;
|
||||
@@ -1532,6 +1622,19 @@ function clearSelectionForActivePane() {
|
||||
}
|
||||
|
||||
function handleKeyboardShortcuts(event) {
|
||||
if (isRenamePopupOpen()) {
|
||||
if (event.key === "Escape") {
|
||||
event.preventDefault();
|
||||
closeRenamePopup();
|
||||
return;
|
||||
}
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
submitRenamePopup();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isSettingsOpen()) {
|
||||
if (event.key === "Escape") {
|
||||
event.preventDefault();
|
||||
@@ -1679,12 +1782,33 @@ function setupEvents() {
|
||||
document.getElementById("settings-btn").onclick = () => openSettings("general");
|
||||
document.getElementById("view-btn").onclick = openViewer;
|
||||
document.getElementById("edit-btn").onclick = openEditor;
|
||||
document.getElementById("rename-btn").onclick = renameSelected;
|
||||
document.getElementById("rename-btn").onclick = openRenamePopup;
|
||||
document.getElementById("delete-btn").onclick = deleteSelected;
|
||||
document.getElementById("copy-btn").onclick = startCopySelected;
|
||||
document.getElementById("move-btn").onclick = openF6Flow;
|
||||
document.getElementById("mkdir-btn").onclick = createFolderForActivePane;
|
||||
|
||||
const rename = renameElements();
|
||||
rename.closeButton.onclick = closeRenamePopup;
|
||||
rename.cancelButton.onclick = closeRenamePopup;
|
||||
rename.applyButton.onclick = submitRenamePopup;
|
||||
rename.input.onkeydown = (event) => {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
submitRenamePopup();
|
||||
return;
|
||||
}
|
||||
if (event.key === "Escape") {
|
||||
event.preventDefault();
|
||||
closeRenamePopup();
|
||||
}
|
||||
};
|
||||
rename.overlay.onclick = (event) => {
|
||||
if (event.target === rename.overlay) {
|
||||
closeRenamePopup();
|
||||
}
|
||||
};
|
||||
|
||||
const settings = settingsElements();
|
||||
settings.closeButton.onclick = closeSettings;
|
||||
settings.generalTab.onclick = () => setSettingsTab("general");
|
||||
|
||||
+15
-2
@@ -68,12 +68,11 @@
|
||||
<div id="function-bar-meta" class="pathline compact-line">Active:<code id="active-pane-label">left</code></div>
|
||||
<div id="function-bar" class="toolbar compact-toolbar">
|
||||
<button id="settings-btn" type="button"><span class="shortcut-hint">F1</span><span>Settings</span></button>
|
||||
<button id="rename-placeholder-btn" type="button" disabled><span class="shortcut-hint">F2</span><span>Rename</span></button>
|
||||
<button id="rename-btn" type="button" disabled><span class="shortcut-hint">F2</span><span>Rename</span></button>
|
||||
<button id="view-btn" type="button" disabled><span class="shortcut-hint">F3</span><span>View</span></button>
|
||||
<button id="edit-btn" type="button" disabled><span class="shortcut-hint">F4</span><span>Edit</span></button>
|
||||
<button id="copy-btn" type="button" disabled><span class="shortcut-hint">F5</span><span>Copy</span></button>
|
||||
<button id="move-btn" type="button" disabled><span class="shortcut-hint">F6</span><span>Move</span></button>
|
||||
<button id="rename-btn" type="button" disabled><span>Rename</span></button>
|
||||
<button id="mkdir-btn" type="button"><span class="shortcut-hint">F7</span><span>MKdir</span></button>
|
||||
<button id="delete-btn" type="button" disabled><span class="shortcut-hint">F8</span><span>Delete</span></button>
|
||||
</div>
|
||||
@@ -128,6 +127,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rename-popup" class="popup-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="rename-title">
|
||||
<div class="popup-card">
|
||||
<button id="rename-close-btn" class="viewer-close" type="button" aria-label="Close rename">X</button>
|
||||
<h3 id="rename-title">Rename</h3>
|
||||
<label for="rename-input" class="popup-label">Name</label>
|
||||
<input id="rename-input" type="text" autocomplete="off">
|
||||
<div id="rename-error" class="error"></div>
|
||||
<div class="popup-actions">
|
||||
<button id="rename-apply-btn" type="button">Rename</button>
|
||||
<button id="rename-cancel-btn" type="button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="batch-move-popup" class="popup-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="batch-move-title">
|
||||
<div class="popup-card">
|
||||
<h3 id="batch-move-title">Batch Move</h3>
|
||||
|
||||
@@ -490,6 +490,17 @@ button:disabled {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
#rename-popup .popup-card {
|
||||
width: min(520px, calc(100vw - 28px));
|
||||
}
|
||||
|
||||
#rename-input {
|
||||
width: 100%;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.popup-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
Reference in New Issue
Block a user