From d98b087de287e1ce60223e9c94d834c346ea1d3a Mon Sep 17 00:00:00 2001 From: Ambrose Chua Date: Tue, 16 Nov 2021 21:17:19 +0800 Subject: [PATCH] feat: File renaming --- README.md | 4 +- assets/common.js | 5 ++ assets/multi.js | 31 ++++-------- assets/rename.js | 62 +++++++++++++++++++++++ index.js | 51 +++++++++++++++++++ rootowned/hi | 0 views/layouts/main.handlebars | 4 ++ views/list.handlebars | 1 + views/partials/dialogue-rename.handlebars | 22 ++++++++ views/partials/toolbar.handlebars | 10 +++- 10 files changed, 166 insertions(+), 24 deletions(-) create mode 100644 assets/common.js create mode 100644 assets/rename.js create mode 100644 rootowned/hi create mode 100644 views/partials/dialogue-rename.handlebars diff --git a/README.md b/README.md index a3a2a92..dd64115 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ A basic node.js file manager. - [x] File uploads - [ ] Bulk file uploads - [ ] Large file uploads (sharded) -- [ ] File/folder renaming +- [x] File/folder renaming - [x] Bulk file/folder selection - [x] Delete - - [ ] Recursive directory delete + - [x] Recursive directory delete - [ ] Move - [ ] Copy - [x] Download archive diff --git a/assets/common.js b/assets/common.js new file mode 100644 index 0000000..d41f70a --- /dev/null +++ b/assets/common.js @@ -0,0 +1,5 @@ +function htmlEscape(text) { + const p = document.createElement("p"); + p.innerText = text; + return p.innerHTML; +} diff --git a/assets/multi.js b/assets/multi.js index 4cd13cc..5d84fa3 100644 --- a/assets/multi.js +++ b/assets/multi.js @@ -1,14 +1,8 @@ /* jshint esversion: 6 */ -function htmlEscape(text) { - const p = document.createElement("p"); - p.innerText = text; - return p.innerHTML; -} - let $select = $(".multi-select"); -let setSelected = (files) => { +$select.on("change-files", (e, files) => { $(".multi-files-value").val(JSON.stringify(files.map((f) => f.name))); if (files.length == 0) { $(".multi-files").html( @@ -19,18 +13,15 @@ let setSelected = (files) => { $(".multi-files").html( files .map((f) => { + const badge = ` + ${filesize(f.size)} + `; return ` -
  • - ${htmlEscape(f.name)} - ${ - f.type == "directory" - ? `` - : `${filesize( - f.size - )}` - } -
  • - `; +
  • + ${htmlEscape(f.name)} + ${f.type == "directory" ? `` : badge} +
  • + `; }) .join("") ); @@ -44,7 +35,7 @@ let setSelected = (files) => { } else { $(".multi-files-total").val(filesize(totalSize)); } -}; +}); const updateSelected = () => { let $selected = $(".multi-select:checked"); @@ -57,7 +48,7 @@ const updateSelected = () => { }); }); - setSelected(files); + $select.trigger("change-files", [files]); }; $select.on("change", updateSelected); diff --git a/assets/rename.js b/assets/rename.js new file mode 100644 index 0000000..8d2f66e --- /dev/null +++ b/assets/rename.js @@ -0,0 +1,62 @@ +/* jshint esversion: 6 */ + +const updateRenameValue = ($inputs, $value) => { + let files = []; + $inputs.each((i, ele) => { + files.push({ + original: $(ele).data("original"), + new: $(ele).val(), + }); + }); + $value.val(JSON.stringify(files)); +}; + +$select.on("change-files", (e, files) => { + if (files.length == 0) { + $(".rename-files").html( + `` + ); + return; + } + $(".rename-files").html( + files + .map((f) => { + return ` +
    + + +
    + `; + }) + .join("") + ); + $(".rename-files-input").on("keydown", (e) => { + if (e.keyCode == 13) { + e.preventDefault(); + const $next = $(e.target).parent().nextAll().find("input")[0]; + if ($next) { + $next.focus(); + if ($next.type == "text") { + $next.select(); + } + } + } + }); + $(".rename-files").each((i, ele) => { + const $value = $(ele).parent().find(".rename-files-value"); + const $inputs = $(ele) + .find(".rename-files-input") + .on("focus blur change", (e) => { + updateRenameValue($inputs, $value); + }); + updateRenameValue($inputs, $value); + }); +}); + +updateSelected(); diff --git a/index.js b/index.js index 50285dd..0a097c0 100755 --- a/index.js +++ b/index.js @@ -453,6 +453,57 @@ app.get("/*@download", (req, res) => { }); }); +app.post("/*@rename", (req, res) => { + res.filename = req.params[0]; + + let files = JSON.parse(req.body.files); + if (!files || !files.map) { + req.flash("error", "No files selected."); + res.redirect("back"); + return; + } + + new Promise((resolve, reject) => { + fs.access(relative(res.filename), fs.constants.W_OK, (err) => { + if (err) { + return reject(err); + } + resolve(); + }); + }) + .then(() => { + let promises = files.map((f) => { + return new Promise((resolve, reject) => { + fs.rename( + relative(res.filename, f.original), + relative(res.filename, f.new), + (err) => { + if (err) { + return reject(err); + } + resolve(); + } + ); + }); + }); + Promise.all(promises) + .then(() => { + req.flash("success", "Files renamed. "); + res.redirect("back"); + }) + .catch((err) => { + console.warn(err); + req.flash("error", "Unable to rename some files: " + err); + res.redirect("back"); + }); + }) + .catch((err) => { + console.warn(err); + req.flash("error", err.toString()); + res.redirect("back"); + }); +}); + const shellable = process.env.SHELL != "false" && process.env.SHELL; const cmdable = process.env.CMD != "false" && process.env.CMD; if (shellable || cmdable) { diff --git a/rootowned/hi b/rootowned/hi new file mode 100644 index 0000000..e69de29 diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index c6f48b3..e6b0d47 100644 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -17,12 +17,16 @@ + + + + diff --git a/views/list.handlebars b/views/list.handlebars index dfa6af6..0d2114a 100644 --- a/views/list.handlebars +++ b/views/list.handlebars @@ -57,4 +57,5 @@ {{> dialogue-cmd}} {{> dialogue-download}} +{{> dialogue-rename}} {{> dialogue-delete}} diff --git a/views/partials/dialogue-rename.handlebars b/views/partials/dialogue-rename.handlebars new file mode 100644 index 0000000..32f8643 --- /dev/null +++ b/views/partials/dialogue-rename.handlebars @@ -0,0 +1,22 @@ +
    + +
    diff --git a/views/partials/toolbar.handlebars b/views/partials/toolbar.handlebars index 6d12dde..d77f65a 100644 --- a/views/partials/toolbar.handlebars +++ b/views/partials/toolbar.handlebars @@ -30,13 +30,19 @@
    {{octicon "file-zip"}} - Download + Download + +
    +
    + + {{octicon "pencil"}} + Rename
    {{octicon "trash"}} - Delete + Delete