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 @@
+