diff --git a/copyparty/web/browser.css b/copyparty/web/browser.css
index e32c0968..5887c13f 100644
--- a/copyparty/web/browser.css
+++ b/copyparty/web/browser.css
@@ -1068,6 +1068,43 @@ html.light #ggrid a:hover {
margin: 0;
padding: 0;
}
+#rui {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: calc(100% - 2em);
+ height: auto;
+ overflow: auto;
+ max-height: calc(100% - 2em);
+ border-bottom: .5em solid #999;
+ background: #333;
+ padding: 1em;
+ z-index: 765;
+}
+#rui div+div {
+ margin-top: 1em;
+}
+#rui table {
+ width: 100%;
+}
+#rui td {
+ padding: .2em .5em;
+}
+#rui td+td,
+#rui td input {
+ width: 100%;
+}
+#rui input[readonly] {
+ color: #fff;
+ background: #444;
+ border: 1px solid #777;
+ padding: .2em .25em;
+}
+#rui h1 {
+ margin: 0 0 .3em 0;
+ padding: 0;
+ font-size: 1.5em;
+}
#pvol,
#barbuf,
#barpos,
diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js
index a536d8c8..57ce39e3 100644
--- a/copyparty/web/browser.js
+++ b/copyparty/web/browser.js
@@ -522,15 +522,14 @@ var mp = new MPlayer();
makeSortable(ebi('files'), mp.read_order.bind(mp));
-function get_np() {
+function ft2dict(tr) {
var th = ebi('files').tHead.rows[0].cells,
- tr = QS('#files tr.play').cells,
rv = [],
ra = [],
rt = {};
for (var a = 1, aa = th.length; a < aa; a++) {
- var tv = tr[a].textContent,
+ var tv = tr.cells[a].textContent,
tk = a == 1 ? 'file' : th[a].getAttribute('name').split('/').slice(-1)[0],
vis = th[a].className.indexOf('min') === -1;
@@ -541,6 +540,12 @@ function get_np() {
rt[tk] = tv;
}
return [rt, rv, ra];
+}
+
+
+function get_np() {
+ var tr = QS('#files tr.play');
+ return ft2dict(tr);
};
@@ -1499,28 +1504,87 @@ var fileman = (function () {
base = vsp[0],
ofn = uricom_dec(vsp[1])[0];
- var fn = prompt('new filename:', ofn);
- if (!fn || fn == ofn)
- return toast.warn(1, 'rename aborted');
-
- var dst = base + uricom_enc(fn, false);
-
- function rename_cb() {
- if (this.readyState != XMLHttpRequest.DONE)
- return;
-
- if (this.status !== 200) {
- var msg = this.responseText;
- toast.err(9, 'rename failed:\n' + msg);
- return;
- }
- toast.ok(2, 'rename OK');
- treectl.goto(get_evpath());
+ var rui = ebi('rui');
+ if (!rui) {
+ rui = mknod('div');
+ rui.setAttribute('id', 'rui');
+ document.body.appendChild(rui);
}
- var xhr = new XMLHttpRequest();
- xhr.open('GET', src + '?move=' + dst, true);
- xhr.onreadystatechange = rename_cb;
- xhr.send();
+ var html = [
+ '
rename file ',
+ '',
+ '',
+ 'url-decode ',
+ '|',
+ '↺ reset ',
+ '❌ cancel ',
+ '✅ apply rename ',
+ '
',
+ '');
+ rui.innerHTML = html.join('\n');
+ var iold = ebi('rn_old'),
+ inew = ebi('rn_new');
+
+ function rn_reset() {
+ inew.value = iold.value;
+ inew.focus();
+ inew.setSelectionRange(0, inew.value.lastIndexOf('.'), "forward");
+ }
+ function rn_cancel() {
+ rui.parentNode.removeChild(rui);
+ }
+
+ inew.onkeydown = function (e) {
+ if (e.key == 'Escape')
+ return rn_cancel();
+
+ if (e.key == 'Enter')
+ return rn_apply();
+ };
+ ebi('rn_cancel').onclick = rn_cancel;
+ ebi('rn_reset').onclick = rn_reset;
+ ebi('rn_apply').onclick = rn_apply;
+ ebi('rn_dec').onclick = function () {
+ inew.value = uricom_dec(inew.value)[0];
+ };
+
+ iold.value = ofn;
+ rn_reset();
+
+ function rn_apply() {
+ var dst = base + uricom_enc(inew.value, false);
+
+ function rename_cb() {
+ if (this.readyState != XMLHttpRequest.DONE)
+ return;
+
+ if (this.status !== 200) {
+ var msg = this.responseText;
+ toast.err(9, 'rename failed:\n' + msg);
+ return;
+ }
+ toast.ok(2, 'rename OK');
+ treectl.goto(get_evpath());
+ rn_cancel();
+ }
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', src + '?move=' + dst, true);
+ xhr.onreadystatechange = rename_cb;
+ xhr.send();
+ };
};
r.delete = function (e) {