suspiciously working first attempt at batch-rename

This commit is contained in:
ed 2021-08-05 20:49:49 +02:00
parent 051998429c
commit f269a710e2
2 changed files with 243 additions and 52 deletions

View file

@ -1086,14 +1086,24 @@ html.light #rui {
} }
#rui table { #rui table {
width: 100%; width: 100%;
border-collapse: collapse;
} }
#rui td { #rui td+td {
padding: .2em .5em; padding: .2em 0 .2em .5em;
}
#rn_vadv input {
font-family: monospace, monospace;
} }
#rui td+td, #rui td+td,
#rui td input { #rui td input[type="text"] {
width: 100%; width: 100%;
} }
#rn_f.m td:first-child {
white-space: nowrap;
}
#rn_f.m td+td {
width: 50%;
}
#rui input[readonly] { #rui input[readonly] {
color: #fff; color: #fff;
background: #444; background: #444;
@ -1109,6 +1119,7 @@ html.light #rui {
#barbuf, #barbuf,
#barpos, #barpos,
#u2conf label, #u2conf label,
#rui label,
#ops { #ops {
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;

View file

@ -1460,6 +1460,79 @@ function play_linked() {
})(); })();
function fmt_ren(re, md, fmt) {
var ptr = 0;
function dive() {
var ret = '', ng = 0;
while (ptr < fmt.length) {
var ch = fmt[ptr++];
if (ch == '\\') {
ret += fmt[ptr++];
continue;
}
if (ch == ')' || ch == ']')
return [ng, ret];
if (ch == '$') {
ch = fmt[ptr++];
if (ch == '[') {
var r2 = dive();
if (r2[0] == 0)
ret += r2[1];
}
else if (ch == '(') {
var end = fmt.indexOf(')', ptr);
if (end < 0)
throw 'the $( was never closed: ' + fmt.slice(0, ptr);
var arg = fmt.slice(ptr, end), v = null;
ptr = end + 1;
if (arg != parseInt(arg))
v = md[arg];
else {
arg = parseInt(arg);
if (!re)
throw 'regex did not match';
if (arg >= re.length)
throw 'matching group ' + arg + ' exceeds ' + (re.length - 0);
v = re[arg];
}
if (v !== null && v !== undefined)
ret += v;
else
ng++;
}
else {
var end = fmt.indexOf('(', ptr);
if (end < 0)
throw 'no function name after the $ here: ' + fmt.slice(0, ptr);
var fun = fmt.slice(ptr - 1, end);
throw 'function not implemented: [' + fun + ']';
}
continue;
}
ret += ch;
}
return [ng, ret];
}
try {
return [true, dive()[1]];
}
catch (ex) {
return [false, ex];
}
}
var fileman = (function () { var fileman = (function () {
var bren = ebi('fren'), var bren = ebi('fren'),
bdel = ebi('fdel'), bdel = ebi('fdel'),
@ -1493,16 +1566,32 @@ var fileman = (function () {
return toast.err(3, 'cannot rename:\nyou do not have “move” permission in this folder'); return toast.err(3, 'cannot rename:\nyou do not have “move” permission in this folder');
var sel = msel.getsel(); var sel = msel.getsel();
if (sel.length !== 1) if (!sel.length)
return toast.err(3, 'select exactly 1 item to rename'); return toast.err(3, 'select at least one item to rename');
var src = sel[0].vp; var f = [],
if (src.endsWith('/')) base = vsplit(sel[0].vp)[0],
src = src.slice(0, -1); mkeys;
var vsp = vsplit(src), for (var a = 0; a < sel.length; a++) {
base = vsp[0], var vp = sel[a].vp;
ofn = uricom_dec(vsp[1])[0]; if (vp.endsWith('/'))
vp = vp.slice(0, -1);
var vsp = vsplit(vp);
if (base != vsp[0])
return toast.err(0, 'bug:\n' + base + '\n' + vsp[0]);
var vars = ft2dict(ebi(sel[a].id).closest('tr'));
mkeys = vars[1].concat(vars[2]);
f.push({
"src": vp,
"ofn": uricom_dec(vsp[1])[0],
"md": vars[0],
"ok": true
});
}
var rui = ebi('rui'); var rui = ebi('rui');
if (!rui) { if (!rui) {
@ -1510,62 +1599,147 @@ var fileman = (function () {
rui.setAttribute('id', 'rui'); rui.setAttribute('id', 'rui');
document.body.appendChild(rui); document.body.appendChild(rui);
} }
var html = [
'<h1>rename file</h1>', var html = sel.length > 1 ? ['<div>'] : [
'<div><table>',
'<tr><td>old:</td><td><input type="text" id="rn_old" readonly /></td></tr>',
'<tr><td>new:</td><td><input type="text" id="rn_new" /></td></tr>',
'</table></div>',
'<div>', '<div>',
'<button id="rn_dec">url-decode</button>', '<button class="rn_dec" n="0">url-decode</button>',
'|', '//',
'<button id="rn_reset">↺ reset</button>', '<button class="rn_reset" n="0">↺ reset</button>'
'<button id="rn_cancel">❌ cancel</button>',
'<button id="rn_apply">✅ apply rename</button>',
'</div>',
'<div><table>'
]; ];
var vars = ft2dict(ebi(sel[0].id).closest('tr')), html = html.concat([
keys = vars[1].concat(vars[2]); '<button id="rn_cancel">❌ cancel</button>',
'<button id="rn_apply">✅ apply rename</button>',
'<a id="rn_adv" class="tgl btn" href="#" tt="batch / metadata / pattern renaming">advanced</a>',
'<a id="rn_case" class="tgl btn" href="#" tt="case-sensitive regex">case</a>',
'</div>',
'<div id="rn_vadv"><table>',
'<tr><td>regex</td><td><input type="text" id="rn_re" /></td></tr>',
'<tr><td>format</td><td><input type="text" id="rn_fmt" /></td></tr>',
'<tr><td>preset</td><td><select id="rn_pre"></select>',
'<button id="rn_pdel">❌ delete</button>',
'<button id="rn_pnew">💾 save as</button>',
'</td></tr>',
'</table></div>'
]);
vars = vars[0]; if (sel.length == 1)
for (var a = 0; a < keys.length; a++) html.push(
html.push('<tr><td>' + esc(keys[a]) + '</td><td><input type="text" readonly value="' + esc(vars[keys[a]]) + '" /></td></tr>'); '<div><table id="rn_f">\n' +
'<tr><td>old:</td><td><input type="text" id="rn_old" n="0" readonly /></td></tr>\n' +
'<tr><td>new:</td><td><input type="text" id="rn_new" n="0" /></td></tr>');
else {
html.push(
'<div><table id="rn_f" class="m">' +
'<tr><td></td><td>new name</td><td>old name</td></tr>');
for (var a = 0; a < f.length; a++)
html.push(
'<tr><td>' +
'<button class="rn_dec" n="' + a + '">decode</button>',
'<button class="rn_reset" n="' + a + '">↺ reset</button></td>',
'<td><input type="text" id="rn_new" n="' + a + '" /></td>' +
'<td><input type="text" id="rn_old" n="' + a + '" readonly /></td></tr>');
}
html.push('</table></div>');
if (sel.length == 1) {
html.push('<div>tags for the selected file (read-only):<table>');
for (var a = 0; a < mkeys.length; a++)
html.push('<tr><td>' + esc(mkeys[a]) + '</td><td><input type="text" readonly value="' + esc(f[0].md[mkeys[a]]) + '" /></td></tr>');
html.push('</table></div>'); html.push('</table></div>');
}
rui.innerHTML = html.join('\n'); rui.innerHTML = html.join('\n');
var iold = ebi('rn_old'), for (var a = 0; a < f.length; a++) {
inew = ebi('rn_new'); var k = '[n="' + a + '"]';
f[a].iold = QS('#rn_old' + k);
f[a].inew = QS('#rn_new' + k);
f[a].inew.value = f[a].iold.value = f[a].ofn;
function rn_reset() { (function (a) {
inew.value = iold.value; f[a].inew.onkeydown = function (e) {
inew.focus(); f[a].ok = true;
inew.setSelectionRange(0, inew.value.lastIndexOf('.'), "forward");
}
function rn_cancel() {
rui.parentNode.removeChild(rui);
}
inew.onkeydown = function (e) {
if (e.key == 'Escape') if (e.key == 'Escape')
return rn_cancel(); return rn_cancel();
if (e.key == 'Enter') if (e.key == 'Enter')
return rn_apply(); return rn_apply();
}; };
QS('.rn_dec' + k).onclick = function () {
f[a].inew.value = uricom_dec(f[a].inew.value)[0];
};
QS('.rn_reset' + k).onclick = function () {
rn_reset(a);
};
})(a);
}
rn_reset(0);
tt.att(rui);
var adv = bcfg_get('rn_adv', false),
cs = bcfg_get('rn_case', false);
function sadv() {
ebi('rn_vadv').style.display = ebi('rn_case').style.display = adv ? '' : 'none';
}
sadv();
function rn_reset(n) {
f[n].inew.value = f[n].iold.value = f[n].ofn;
f[n].inew.focus();
f[n].inew.setSelectionRange(0, f[n].inew.value.lastIndexOf('.'), "forward");
}
function rn_cancel() {
rui.parentNode.removeChild(rui);
}
ebi('rn_cancel').onclick = rn_cancel; ebi('rn_cancel').onclick = rn_cancel;
ebi('rn_reset').onclick = rn_reset;
ebi('rn_apply').onclick = rn_apply; ebi('rn_apply').onclick = rn_apply;
ebi('rn_dec').onclick = function () { ebi('rn_adv').onclick = function () {
inew.value = uricom_dec(inew.value)[0]; adv = !adv;
bcfg_set('rn_adv', adv);
sadv();
};
ebi('rn_case').onclick = function () {
cs = !cs;
bcfg_set('rn_case', cs);
}; };
iold.value = ofn; var ire = ebi('rn_re'),
rn_reset(); ifmt = ebi('rn_fmt'),
ipre = ebi('rn_pre'),
idel = ebi('rn_pdel'),
inew = ebi('rn_pnew');
ire.oninput = ifmt.oninput = function (e) {
var re = ire.value,
fmt = ifmt.value;
if (!fmt)
return;
try {
re = re ? new RegExp(re, cs ? 'i' : '') : null;
}
catch (ex) {
return toast.err(5, 'invalid regex:\n' + ex);
}
toast.hide();
for (var a = 0; a < f.length; a++) {
var m = re ? re.exec(f[a].ofn) : null,
ret = fmt_ren(m, f[a].md, fmt);
f[a].ok = ret[0];
f[a].inew.value = ret[1];
}
};
function rn_apply() { function rn_apply() {
var dst = base + uricom_enc(inew.value, false); toast.inf(0, 'renaming ' + f.length + ' items\n\n' + f[0].ofn);
var dst = base + uricom_enc(f[0].inew.value, false);
function rename_cb() { function rename_cb() {
if (this.readyState != XMLHttpRequest.DONE) if (this.readyState != XMLHttpRequest.DONE)
@ -1576,15 +1750,21 @@ var fileman = (function () {
toast.err(9, 'rename failed:\n' + msg); toast.err(9, 'rename failed:\n' + msg);
return; return;
} }
f.shift().inew.value = '( OK )';
if (f.length)
return rn_apply();
toast.ok(2, 'rename OK'); toast.ok(2, 'rename OK');
treectl.goto(get_evpath()); treectl.goto(get_evpath());
rn_cancel(); rn_cancel();
} }
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', src + '?move=' + dst, true); xhr.open('GET', f[0].src + '?move=' + dst, true);
xhr.onreadystatechange = rename_cb; xhr.onreadystatechange = rename_cb;
xhr.send(); xhr.send();
}; }
}; };
r.delete = function (e) { r.delete = function (e) {