From 05d82eb12eb26cc5cfefb61accca33d4dd9ec6bc Mon Sep 17 00:00:00 2001 From: joshuaboud Date: Mon, 19 Jul 2021 12:17:11 -0300 Subject: [PATCH] implement more intuitive file renaming --- navigator/components/NavContextMenu.js | 47 ++++---------- navigator/components/NavEntry.js | 90 +++++++++++++++++++++++++- navigator/components/NavFile.js | 5 +- navigator/components/NavWindow.js | 6 +- 4 files changed, 109 insertions(+), 39 deletions(-) diff --git a/navigator/components/NavContextMenu.js b/navigator/components/NavContextMenu.js index a34bdf9..1333cf0 100644 --- a/navigator/components/NavContextMenu.js +++ b/navigator/components/NavContextMenu.js @@ -53,7 +53,7 @@ export class NavContextMenu { var name_list = func[0].split("_"); name_list.forEach((word, index) => {name_list[index] = word.charAt(0).toUpperCase() + word.slice(1)}); elem.innerHTML = func[1] + name_list.join(" "); - elem.addEventListener("click", (e) => {this[func[0]].bind(this).apply()}); + elem.addEventListener("click", (e) => {this[func[0]].bind(this, e).apply()}); elem.classList.add("nav-context-menu-item") elem.id = "nav-context-menu-" + func[0]; this.dom_element.appendChild(elem); @@ -61,58 +61,37 @@ export class NavContextMenu { } } - new_dir() { + new_dir(e) { this.nav_window_ref.mkdir(); } - new_file() { + new_file(e) { this.nav_window_ref.touch(); } - new_link() { + new_link(e) { var default_target = ""; if (this.nav_window_ref.selected_entries.size <= 1 && this.target !== this.nav_window_ref.pwd()) default_target = this.target.filename(); this.nav_window_ref.ln(default_target); } - cut() { + cut(e) { this.nav_window_ref.cut(); } - copy() { + copy(e) { this.nav_window_ref.copy(); } - paste() { + paste(e) { this.nav_window_ref.paste(); } - async rename() { + async rename(e) { this.hide(); - let response = await this.nav_window_ref.modal_prompt.prompt("Renaming " + this.target.filename(), - { - new_name: { - label: "New Name: ", - type: "text", - default: this.target.filename() - } - } - ); - if (response === null) - return; - var new_name = response.new_name; - if (new_name.includes("/")) { - this.nav_window_ref.modal_prompt.alert("File name can't contain `/`."); - return; - } - try { - await this.target.mv(new_name); - } catch(e) { - this.nav_window_ref.modal_prompt.alert(e); - return; - } - this.nav_window_ref.refresh(); + this.target.show_edit(this.target.dom_element.nav_item_title); + e.stopPropagation(); } zip_for_download() { @@ -134,7 +113,7 @@ export class NavContextMenu { }); } - async download() { + async download(e) { var download_target = ""; if (this.nav_window_ref.selected_entries.size === 1 && !(this.nav_window_ref.selected_entry() instanceof NavDir)) { download_target = this.nav_window_ref.selected_entry(); @@ -155,11 +134,11 @@ export class NavContextMenu { download.download(); } - delete() { + delete(e) { this.nav_window_ref.delete_selected(); } - properties() { + properties(e) { this.nav_window_ref.show_edit_selected(); } diff --git a/navigator/components/NavEntry.js b/navigator/components/NavEntry.js index 45eef0e..6ccff18 100644 --- a/navigator/components/NavEntry.js +++ b/navigator/components/NavEntry.js @@ -42,6 +42,19 @@ export class NavEntry { title.innerText = this.filename(); this.dom_element.appendChild(icon); this.dom_element.appendChild(title); + let title_edit = this.dom_element.nav_item_title.editor = document.createElement("input"); + title_edit.type = "text"; + title_edit.style.display = "none"; + title_edit.style.padding = title_edit.style.margin = "0"; + title_edit.style.flexBasis = "0"; + title_edit.style.flexGrow = "2"; + title_edit.classList.add("nav-item-title"); + title_edit.oninput = (e) => { + let elem = e.target; + elem.style.width = elem.value.length + "ch"; + } + title_edit.addEventListener("click", (e) => {e.stopPropagation();}); + this.dom_element.appendChild(title_edit); this.stat = stat; if (stat && stat["inaccessible"]) { this.dom_element.style.cursor = "not-allowed"; @@ -80,9 +93,18 @@ export class NavEntry { handleEvent(e) { switch (e.type) { case "click": + if (this.nav_window_ref.selected_entries.size === 1 && this.nav_window_ref.selected_entries.has(this)) { + switch (e.target) { + case this.dom_element.nav_item_title: + this.show_edit(e.target); + e.stopPropagation(); + break; + default: + break; + } + } this.nav_window_ref.set_selected(this, e.shiftKey, e.ctrlKey); this.context_menu_ref.hide(); - e.stopPropagation(); break; case "contextmenu": this.context_menu_ref.show(e, this); @@ -227,6 +249,72 @@ export class NavEntry { }); } + /** + * + * @param {string} new_path + */ + async rename(new_name) { + if (new_name === this.filename()) + return; + if (new_name.includes("/")) { + this.nav_window_ref.modal_prompt.alert("File name can't contain `/`."); + return; + } else if (new_name === "..") { + this.nav_window_ref.modal_prompt.alert( + "File name can't be `..`.", + "If you want to move the file, right click > cut then right click > paste." + ); + return; + } + try { + await this.mv(new_name); + } catch(e) { + this.nav_window_ref.modal_prompt.alert(e); + return; + } + this.nav_window_ref.refresh(); + } + + /** + * + * @param {HTMLDivElement} element + * @returns + */ + show_edit(element) { + if (!element.editor) + return; + element.hide_func = () => {this.hide_edit(element)}; + element.editor.onchange = element.hide_func; + window.addEventListener("click", element.hide_func); + switch (element) { + case this.dom_element.nav_item_title: + element.editor.value = this.filename(); + break; + default: + element.editor.value = element.innerText; + break; + } + element.editor.style.width = element.editor.value.length + "ch"; + element.editor.style.display = "inline-block"; + element.style.display = "none"; + element.editor.focus(); + } + + hide_edit(element) { + if (!element.editor) + return; + switch (element) { + case this.dom_element.nav_item_title: + this.rename(element.editor.value); + break; + default: + break; + } + element.editor.style.display = "none"; + element.style.display = "inline-block"; + window.removeEventListener("click", element.hide_func); + } + /** * * @param {string} extra_properties diff --git a/navigator/components/NavFile.js b/navigator/components/NavFile.js index 199d6db..e06fd30 100644 --- a/navigator/components/NavFile.js +++ b/navigator/components/NavFile.js @@ -43,9 +43,10 @@ export class NavFile extends NavEntry { handleEvent(e) { switch(e.type){ case "click": - if (this.double_click) + if (this.double_click) { this.open(); - else { // single click + return; + } else { // single click this.double_click = true; if(this.timeout) clearTimeout(this.timeout) diff --git a/navigator/components/NavWindow.js b/navigator/components/NavWindow.js index b7e3955..c97afdb 100644 --- a/navigator/components/NavWindow.js +++ b/navigator/components/NavWindow.js @@ -58,8 +58,10 @@ export class NavWindow { handleEvent(e) { switch (e.type) { case "click": - this.clear_selected(); - this.show_selected_properties(); + if (e.target === this.window) { + this.clear_selected(); + this.show_selected_properties(); + } break; case "contextmenu": this.context_menu.show(e, this.pwd());