mirror of
https://github.com/9001/copyparty.git
synced 2025-11-24 07:23:22 -07:00
Merge 3c042149dd into fb9f0441c9
This commit is contained in:
commit
cc0462b11a
|
|
@ -123,6 +123,7 @@ web/ui.css
|
||||||
web/up2k.js
|
web/up2k.js
|
||||||
web/util.js
|
web/util.js
|
||||||
web/w.hash.js
|
web/w.hash.js
|
||||||
|
web/keybindings.js
|
||||||
"""
|
"""
|
||||||
RES = set(zs.strip().split("\n"))
|
RES = set(zs.strip().split("\n"))
|
||||||
RESM = {
|
RESM = {
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@
|
||||||
<div id="op_up2k" class="opview"></div>
|
<div id="op_up2k" class="opview"></div>
|
||||||
|
|
||||||
<div id="op_cfg" class="opview opbox opwide"></div>
|
<div id="op_cfg" class="opview opbox opwide"></div>
|
||||||
|
<div id="op_hotkey" class="opview opbox opwide"></div>
|
||||||
|
|
||||||
<h1 id="path">
|
<h1 id="path">
|
||||||
<a href="#" id="entree">🌲</a>
|
<a href="#" id="entree">🌲</a>
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,48 @@ if (1)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"hotkeys": {
|
||||||
|
"ESC": "close various things",
|
||||||
|
"ENTER": "open selected file",
|
||||||
|
"HELP": "open help",
|
||||||
|
"PREV_SONG": "prev song",
|
||||||
|
"NEXT_SONG": "next song",
|
||||||
|
"TREE_PREV": "go to the previous dir",
|
||||||
|
"TREE_NEXT": "go to the next dir",
|
||||||
|
"PLAY_PAUSE": "play/pause",
|
||||||
|
"DOWNLOAD": "download selected files",
|
||||||
|
"CUT": "cut selected file(s)",
|
||||||
|
"COPY": "copy selected file(s)",
|
||||||
|
"PASTE": "paste (move/copy) here",
|
||||||
|
"DELETE": "delete selected file(s)",
|
||||||
|
"RENAME": "rename selected file(s)",
|
||||||
|
"TOGGLE_BREADCRUMBS": "toggle breadcrumbs / navpane",
|
||||||
|
"TOGGLE_GRID": "toggle grid / list view",
|
||||||
|
"TOGGLE_THUMBNAILS": "toggle thumbnails / icons",
|
||||||
|
"TOGGLE_FOLDER_TREE": "toggle folders / textfiles in navpane",
|
||||||
|
"FAST_FORWARD": "skip 10sec forward",
|
||||||
|
"REWIND": "skip 10sec back",
|
||||||
|
"NAVPANE_SHRINK": "shrink navpane",
|
||||||
|
"NAVPANE_GROW": "grow navpane",
|
||||||
|
"NAVPANE_SHRINK_DESC": "While in grid mode with nav panel visible",
|
||||||
|
"NAVPANE_GROW_DESC": "While in grid mode with nav panel visible",
|
||||||
|
"SELECT_SONG": "Select playing song",
|
||||||
|
"SELECT_SONG_DESC": "While audio is playing",
|
||||||
|
"SELECT_FILE": "Select file",
|
||||||
|
"SELECT_FILE_DESC": "While in file list",
|
||||||
|
"EDIT_FILE": "Edit file",
|
||||||
|
"EDIT_FILE_DESC": "While in file list",
|
||||||
|
"TOGGLE_GRID_MULTISELECT": "Toggle grid multi select",
|
||||||
|
"TOGGLE_GRID_MULTISELECT_DESC": "While in grid mode",
|
||||||
|
"GRID_SHRINK_THUMBNAILS": "Shrink thumbnails",
|
||||||
|
"GRID_SHRINK_THUMBNAILS_DESC": "While in grid mode",
|
||||||
|
"GRID_GROW_THUMBNAILS": "Grow thumbnails",
|
||||||
|
"GRID_GROW_THUMBNAILS_DESC": "While in grid mode",
|
||||||
|
},
|
||||||
|
"hotkey_binding": "Hotkey keybindings",
|
||||||
|
"hotkey_action": "Hotkey action",
|
||||||
|
"hotkey_context": "Context",
|
||||||
|
|
||||||
"m_ok": "OK",
|
"m_ok": "OK",
|
||||||
"m_ng": "Cancel",
|
"m_ng": "Cancel",
|
||||||
|
|
||||||
|
|
@ -712,6 +754,7 @@ ebi('ops').innerHTML = (
|
||||||
'<a href="#" id="opa_msg" data-dest="msg" tt="' + L.ot_msg + '">📟</a>' +
|
'<a href="#" id="opa_msg" data-dest="msg" tt="' + L.ot_msg + '">📟</a>' +
|
||||||
'<a href="#" id="opa_auc" data-dest="player" tt="' + L.ot_mp + '">🎺</a>' +
|
'<a href="#" id="opa_auc" data-dest="player" tt="' + L.ot_mp + '">🎺</a>' +
|
||||||
'<a href="#" id="opa_cfg" data-dest="cfg" tt="' + L.ot_cfg + '">⚙️</a>' +
|
'<a href="#" id="opa_cfg" data-dest="cfg" tt="' + L.ot_cfg + '">⚙️</a>' +
|
||||||
|
'<a href="#" id="opa_hotkey" data-dest="hotkey" tt="Hotkeys">⚙️</a>' +
|
||||||
(IE ? '<span id="noie">' + L.ot_noie + '</span>' : '') +
|
(IE ? '<span id="noie">' + L.ot_noie + '</span>' : '') +
|
||||||
'<div id="opdesc"></div>'
|
'<div id="opdesc"></div>'
|
||||||
);
|
);
|
||||||
|
|
@ -963,6 +1006,16 @@ ebi('op_cfg').innerHTML = (
|
||||||
'<div><h3>' + L.cl_hiddenc + ' ' + (MOBILE ? '<a href="#" id="hcolsh">' + L.cl_hidec + '</a> / ' : '') + '<a href="#" id="hcolsr">' + L.cl_reset + '</a></h3><div id="hcols"></div></div>'
|
'<div><h3>' + L.cl_hiddenc + ' ' + (MOBILE ? '<a href="#" id="hcolsh">' + L.cl_hidec + '</a> / ' : '') + '<a href="#" id="hcolsr">' + L.cl_reset + '</a></h3><div id="hcols"></div></div>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//DDD kbd
|
||||||
|
lazyLoad('keybindings.js', function () {
|
||||||
|
const rows = [];
|
||||||
|
Object.entries(currentKeybindings).forEach(([key, value]) => {
|
||||||
|
rows.push(`<tr><td>${key}</td><td>${value.tr}</td><td>${value.desc || ''}</td></tr>`);
|
||||||
|
});
|
||||||
|
const table = '<table><thead><tr><th>' + L.hotkey_binding + '</th><th>' + L.hotkey_action + '</th><th>' + L.hotkey_context + '</th></tr></thead><tbody>' + rows.join('') + '</tbody></table>';
|
||||||
|
ebi('op_hotkey').innerHTML = '<div id="hotkey-root">' + table + '</div>';
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// navpane
|
// navpane
|
||||||
ebi('tree').innerHTML = (
|
ebi('tree').innerHTML = (
|
||||||
|
|
@ -1003,6 +1056,7 @@ QS('#op_msg input[type="submit"]').value = L.ab_msg;
|
||||||
|
|
||||||
function opclick(e) {
|
function opclick(e) {
|
||||||
var dest = this.getAttribute('data-dest');
|
var dest = this.getAttribute('data-dest');
|
||||||
|
console.log('Clicked on the top thing with dest', dest);
|
||||||
if (QS('#op_' + dest + '.act'))
|
if (QS('#op_' + dest + '.act'))
|
||||||
dest = '';
|
dest = '';
|
||||||
|
|
||||||
|
|
@ -5880,24 +5934,25 @@ var ahotkeys = function (e) {
|
||||||
if (QS('#bbox-overlay.visible') || modal.busy)
|
if (QS('#bbox-overlay.visible') || modal.busy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var k = (e.key || e.code) + '', pos = -1, n,
|
|
||||||
ae = document.activeElement,
|
|
||||||
aet = ae && ae != document.body ? ae.nodeName.toLowerCase() : '';
|
|
||||||
|
|
||||||
if (k.startsWith('Key'))
|
var kkey = (e.key || e.code) + '', pos = -1, n,
|
||||||
k = k.slice(3);
|
activeElement = document.activeElement,
|
||||||
else if (k.startsWith('Digit'))
|
activeNode = activeElement && activeElement != document.body ? activeElement.nodeName.toLowerCase() : '';
|
||||||
k = k.slice(5);
|
|
||||||
|
|
||||||
var kl = k.toLowerCase();
|
if (kkey.startsWith('Key'))
|
||||||
|
kkey = kkey.slice(3);
|
||||||
|
else if (kkey.startsWith('Digit'))
|
||||||
|
kkey = kkey.slice(5);
|
||||||
|
|
||||||
|
var keyLower = kkey.toLowerCase();
|
||||||
|
|
||||||
if (dbg_kbd)
|
if (dbg_kbd)
|
||||||
console.log('KBD', k, kl, e.key, e.code, e.keyCode, e.which);
|
console.log('KBD', kkey, keyLower, e.key, e.code, e.keyCode, e.which);
|
||||||
|
|
||||||
if (konmai < 0)
|
if (konmai < 0)
|
||||||
noop();
|
noop();
|
||||||
else if (konmak[konmai] != kl)
|
else if (konmak[konmai] != keyLower)
|
||||||
konmai = konmai && kl == konmak[0] ? (konmai<3?konmai:1):0;
|
konmai = konmai && keyLower == konmak[0] ? (konmai<3?konmai:1):0;
|
||||||
else if (++konmai >= konmak.length) {
|
else if (++konmai >= konmak.length) {
|
||||||
konmai = -1;
|
konmai = -1;
|
||||||
document.documentElement.scrollTop = 0;
|
document.documentElement.scrollTop = 0;
|
||||||
|
|
@ -5912,62 +5967,46 @@ var ahotkeys = function (e) {
|
||||||
return ev(e);
|
return ev(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k == 'Escape' || k == 'Esc') {
|
var in_ftab = (activeNode == 'tr' || activeNode == 'td') && activeElement.closest('#files');
|
||||||
ae && ae.blur();
|
|
||||||
tt.hide();
|
|
||||||
|
|
||||||
if (ebi('hkhelp'))
|
//QQQ
|
||||||
return qsr('#hkhelp');
|
const action = getHotkeyEvent(e, {
|
||||||
|
activeElement,
|
||||||
|
activeNode,
|
||||||
|
in_ftab,
|
||||||
|
treectl,
|
||||||
|
gridMode: thegrid.en,
|
||||||
|
mp,
|
||||||
|
showfile
|
||||||
|
});
|
||||||
|
|
||||||
if (toast.visible)
|
if (!action) return;
|
||||||
return toast.hide();
|
|
||||||
|
|
||||||
if (ebi('rn_cancel'))
|
if (action === HOTKEY_ACTIONS.ESCAPE) {
|
||||||
return ebi('rn_cancel').click();
|
return escape();
|
||||||
|
|
||||||
if (ebi('sh_abrt'))
|
|
||||||
return ebi('sh_abrt').click();
|
|
||||||
|
|
||||||
if (QS('.opview.act'))
|
|
||||||
return QS('#ops>a').click();
|
|
||||||
|
|
||||||
if (widget.is_open)
|
|
||||||
return widget.close();
|
|
||||||
|
|
||||||
if (showfile.active())
|
|
||||||
return thegrid.setvis(true);
|
|
||||||
|
|
||||||
if (!treectl.hidden)
|
|
||||||
return treectl.detree();
|
|
||||||
|
|
||||||
if (QS('#unsearch'))
|
|
||||||
return QS('#unsearch').click();
|
|
||||||
|
|
||||||
if (thegrid.en)
|
|
||||||
return ebi('griden').click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var in_ftab = (aet == 'tr' || aet == 'td') && ae.closest('#files');
|
//TODO Ftab in context. can listen for these
|
||||||
if (in_ftab) {
|
if (in_ftab) {
|
||||||
var d = '', rem = 0;
|
var d = '', rem = 0;
|
||||||
if (aet == 'td') ae = ae.closest('tr'); //ie11
|
if (activeNode == 'td') activeElement = activeElement.closest('tr'); //ie11
|
||||||
if (k == 'ArrowUp' || k == 'Up') d = 'previous';
|
if (kkey == 'ArrowUp' || kkey == 'Up') d = 'previous';
|
||||||
if (k == 'ArrowDown' || k == 'Down') d = 'next';
|
if (kkey == 'ArrowDown' || kkey == 'Down') d = 'next';
|
||||||
if (k == 'PageUp') { d = 'previous'; rem = 0.6; }
|
if (kkey == 'PageUp') { d = 'previous'; rem = 0.6; }
|
||||||
if (k == 'PageDown') { d = 'next'; rem = 0.6; }
|
if (kkey == 'PageDown') { d = 'next'; rem = 0.6; }
|
||||||
if (d) {
|
if (d) {
|
||||||
fselfunw(e, ae, d, rem);
|
fselfunw(e, activeElement, d, rem);
|
||||||
return ev(e);
|
return ev(e);
|
||||||
}
|
}
|
||||||
if (k == 'Space' || k == 'Spacebar' || k == ' ') {
|
if (kkey == 'Space' || kkey == 'Spacebar' || kkey == ' ') {
|
||||||
clmod(ae, 'sel', 't');
|
clmod(activeElement, 'sel', 't');
|
||||||
msel.origin_tr(ae);
|
msel.origin_tr(activeElement);
|
||||||
msel.selui();
|
msel.selui();
|
||||||
return ev(e);
|
return ev(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_ftab || !aet || (ae && ae.closest('#ggrid'))) {
|
if (in_ftab || !activeNode || (activeElement && activeElement.closest('#ggrid'))) {
|
||||||
if ((kl == 'a') && ctrl(e)) {
|
if ((keyLower == 'a') && ctrl(e)) {
|
||||||
var ntot = treectl.lsc.files.length + treectl.lsc.dirs.length,
|
var ntot = treectl.lsc.files.length + treectl.lsc.dirs.length,
|
||||||
sel = msel.getsel(),
|
sel = msel.getsel(),
|
||||||
all = msel.getall();
|
all = msel.getall();
|
||||||
|
|
@ -5982,124 +6021,111 @@ var ahotkeys = function (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ae && ae.closest('pre')) {
|
//TODO does not work
|
||||||
if ((kl == 'a') && ctrl(e)) {
|
if (action === HOTKEY_ACTIONS.SELECT_ALL) {
|
||||||
var sel = document.getSelection(),
|
var sel = document.getSelection(),
|
||||||
ran = document.createRange();
|
ran = document.createRange();
|
||||||
|
|
||||||
sel.removeAllRanges();
|
sel.removeAllRanges();
|
||||||
ran.selectNode(ae.closest('pre'));
|
ran.selectNode(activeElement.closest('pre'));
|
||||||
sel.addRange(ran);
|
sel.addRange(ran);
|
||||||
return ev(e);
|
return ev(e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k.endsWith('Enter') && ae && (ae.onclick || ae.hasAttribute('tabIndex')))
|
if (action === HOTKEY_ACTIONS.ENTER && activeElement && (activeElement.onclick || activeElement.hasAttribute('tabIndex')))
|
||||||
return ev(e) && ae.click() || true;
|
return ev(e) && activeElement.click() || true;
|
||||||
|
|
||||||
if (aet && aet != 'a' && aet != 'tr' && aet != 'td' && aet != 'div' && aet != 'pre')
|
if (action === HOTKEY_ACTIONS.HELP)
|
||||||
return;
|
|
||||||
|
|
||||||
if (k == '?')
|
|
||||||
return hkhelp();
|
return hkhelp();
|
||||||
|
|
||||||
if (!e.shiftKey && ctrl(e)) {
|
if (action === HOTKEY_ACTIONS.CUT) {
|
||||||
var sel = window.getSelection && window.getSelection() || {};
|
return fileman.cut(e);
|
||||||
sel = sel && !sel.isCollapsed && sel.direction != 'none';
|
}
|
||||||
|
if (action === HOTKEY_ACTIONS.COPY) {
|
||||||
if (kl == 'x')
|
return fileman.cpy(e);
|
||||||
return fileman.cut(e);
|
}
|
||||||
|
if (action === HOTKEY_ACTIONS.PASTE) {
|
||||||
if (kl == 'c' && !sel)
|
return fileman.d_paste(e);
|
||||||
return fileman.cpy(e);
|
}
|
||||||
|
if (action === HOTKEY_ACTIONS.DELETE) {
|
||||||
if (kl == 'v')
|
return fileman.delete(e);
|
||||||
return fileman.d_paste(e);
|
|
||||||
|
|
||||||
if (kl == 'k')
|
|
||||||
return fileman.delete(e);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.shiftKey && kl != 'a' && kl != 'd')
|
if (action === HOTKEY_ACTIONS.PREV_SONG) {
|
||||||
return;
|
return prev_song() || true;
|
||||||
|
}
|
||||||
|
if (action === HOTKEY_ACTIONS.NEXT_SONG) {
|
||||||
|
return next_song() || true;
|
||||||
|
}
|
||||||
|
if (action === HOTKEY_ACTIONS.TREE_PREV) {
|
||||||
|
return tree_neigh(-1, 1) || true;
|
||||||
|
}
|
||||||
|
if (action === HOTKEY_ACTIONS.TREE_NEXT) {
|
||||||
|
return tree_neigh(1, 1) || true;
|
||||||
|
}
|
||||||
|
|
||||||
if (/^[0-9]$/.test(k))
|
if (action === HOTKEY_ACTIONS.PLAY_PAUSE)
|
||||||
pos = parseInt(k) * 0.1;
|
return playpause() || true;
|
||||||
|
|
||||||
|
//TODO uncovered use case
|
||||||
|
if (/^[0-9]$/.test(kkey))
|
||||||
|
pos = parseInt(kkey) * 0.1;
|
||||||
|
|
||||||
if (pos !== -1)
|
if (pos !== -1)
|
||||||
return seek_au_mul(pos) || true;
|
return seek_au_mul(pos) || true;
|
||||||
|
|
||||||
if (kl == 'j')
|
if (action === HOTKEY_ACTIONS.FAST_FORWARD)
|
||||||
return prev_song() || true;
|
return seek_au_rel(10) || true;
|
||||||
|
if (action === HOTKEY_ACTIONS.REWIND)
|
||||||
|
return seek_au_rel(-10) || true;
|
||||||
|
|
||||||
if (kl == 'l')
|
if (action === HOTKEY_ACTIONS.DOWNLOAD)
|
||||||
return next_song() || true;
|
|
||||||
|
|
||||||
if (kl == 'p')
|
|
||||||
return playpause() || true;
|
|
||||||
|
|
||||||
n = kl == 'u' ? -10 : kl == 'o' ? 10 : 0;
|
|
||||||
if (n !== 0)
|
|
||||||
return seek_au_rel(n) || true;
|
|
||||||
|
|
||||||
if (kl == 'y')
|
|
||||||
return msel.getsel().length ? ebi('seldl').click() :
|
return msel.getsel().length ? ebi('seldl').click() :
|
||||||
showfile.active() ? ebi('dldoc').click() :
|
showfile.active() ? ebi('dldoc').click() :
|
||||||
dl_song();
|
dl_song();
|
||||||
|
|
||||||
n = kl == 'i' ? -1 : kl == 'k' ? 1 : 0;
|
if (action === HOTKEY_ACTIONS.TREE_UP)
|
||||||
if (n !== 0)
|
|
||||||
return tree_neigh(n, 1);
|
|
||||||
|
|
||||||
if (kl == 'm')
|
|
||||||
return tree_up();
|
return tree_up();
|
||||||
|
|
||||||
if (kl == 'b')
|
if (action === HOTKEY_ACTIONS.TOGGLE_BREADCRUMBS)
|
||||||
return treectl.hidden ? treectl.entree() : treectl.detree();
|
return treectl.hidden ? treectl.entree() : treectl.detree();
|
||||||
|
|
||||||
if (kl == 'g')
|
if (action === HOTKEY_ACTIONS.TOGGLE_GRID)
|
||||||
return ebi('griden').click();
|
return ebi('griden').click();
|
||||||
|
|
||||||
if (kl == 't')
|
if (action === HOTKEY_ACTIONS.TOGGLE_THUMBNAILS)
|
||||||
return ebi('thumbs').click();
|
return ebi('thumbs').click();
|
||||||
|
|
||||||
if (kl == 'v')
|
if (action === HOTKEY_ACTIONS.TOGGLE_FOLDER_TREE)
|
||||||
return ebi('filetree').click();
|
return ebi('filetree').click();
|
||||||
|
|
||||||
if (k == 'F2')
|
if (action === HOTKEY_ACTIONS.RENAME)
|
||||||
return fileman.rename();
|
return fileman.rename();
|
||||||
|
|
||||||
if (!treectl.hidden && (!e.shiftKey || !thegrid.en)) {
|
if (action === HOTKEY_ACTIONS.NAVPANE_SHRINK)
|
||||||
if (kl == 'a')
|
return QS('#twig').click();
|
||||||
return QS('#twig').click();
|
if (action === HOTKEY_ACTIONS.NAVPANE_GROW)
|
||||||
|
return QS('#twobytwo').click();
|
||||||
|
|
||||||
|
if (action === HOTKEY_ACTIONS.SELECT_FILE)
|
||||||
|
showfile.tglsel();
|
||||||
|
if (action === HOTKEY_ACTIONS.EDIT_FILE && ebi('editdoc').style.display != 'none')
|
||||||
|
ebi('editdoc').click();
|
||||||
|
|
||||||
if (kl == 'd')
|
if (action === HOTKEY_ACTIONS.SELECT_SONG) {
|
||||||
return QS('#twobytwo').click();
|
return sel_song();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showfile.active()) {
|
if (action === HOTKEY_ACTIONS.TOGGLE_GRID_MULTISELECT) {
|
||||||
if (kl == 's')
|
return ebi('gridsel').click();
|
||||||
showfile.tglsel();
|
|
||||||
if (kl == 'e' && ebi('editdoc').style.display != 'none')
|
|
||||||
ebi('editdoc').click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mp && mp.au && !mp.au.paused) {
|
if (action === HOTKEY_ACTIONS.GRID_SHRINK_THUMBNAILS) {
|
||||||
if (kl == 's')
|
return QSA('#ghead a[z]')[0].click();
|
||||||
return sel_song();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thegrid.en) {
|
if (action === HOTKEY_ACTIONS.GRID_GROW_THUMBNAILS) {
|
||||||
if (kl == 's')
|
return QSA('#ghead a[z]')[1].click();
|
||||||
return ebi('gridsel').click();
|
|
||||||
|
|
||||||
if (kl == 'a')
|
|
||||||
return QSA('#ghead a[z]')[0].click();
|
|
||||||
|
|
||||||
if (kl == 'd')
|
|
||||||
return QSA('#ghead a[z]')[1].click();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -9380,6 +9406,42 @@ function reload_browser() {
|
||||||
thegrid.setdirty();
|
thegrid.setdirty();
|
||||||
msel.render();
|
msel.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escape() {
|
||||||
|
window.activeElement && window.activeElement.blur();
|
||||||
|
tt.hide();
|
||||||
|
|
||||||
|
if (ebi('hkhelp'))
|
||||||
|
return qsr('#hkhelp');
|
||||||
|
|
||||||
|
if (toast.visible)
|
||||||
|
return toast.hide();
|
||||||
|
|
||||||
|
if (ebi('rn_cancel'))
|
||||||
|
return ebi('rn_cancel').click();
|
||||||
|
|
||||||
|
if (ebi('sh_abrt'))
|
||||||
|
return ebi('sh_abrt').click();
|
||||||
|
|
||||||
|
if (QS('.opview.act'))
|
||||||
|
return QS('#ops>a').click();
|
||||||
|
|
||||||
|
if (widget.is_open)
|
||||||
|
return widget.close();
|
||||||
|
|
||||||
|
if (showfile.active())
|
||||||
|
return thegrid.setvis(true);
|
||||||
|
|
||||||
|
if (!treectl.hidden)
|
||||||
|
return treectl.detree();
|
||||||
|
|
||||||
|
if (QS('#unsearch'))
|
||||||
|
return QS('#unsearch').click();
|
||||||
|
|
||||||
|
if (thegrid.en)
|
||||||
|
return ebi('griden').click();
|
||||||
|
}
|
||||||
|
|
||||||
treectl.hydrate();
|
treectl.hydrate();
|
||||||
|
|
||||||
if (!fullui && (window.ui_nombar || /[?&]nombar\b/.exec(sloc0))) ebi('ops').style.display = 'none';
|
if (!fullui && (window.ui_nombar || /[?&]nombar\b/.exec(sloc0))) ebi('ops').style.display = 'none';
|
||||||
|
|
|
||||||
291
copyparty/web/keybindings.js
Normal file
291
copyparty/web/keybindings.js
Normal file
|
|
@ -0,0 +1,291 @@
|
||||||
|
const HOTKEY_ACTIONS = {
|
||||||
|
ESCAPE: {
|
||||||
|
code: "escape",
|
||||||
|
tr: L.hotkeys.ESC,
|
||||||
|
},
|
||||||
|
ENTER: {
|
||||||
|
code: "enter",
|
||||||
|
tr: L.hotkeys.ENTER,
|
||||||
|
},
|
||||||
|
HELP: {
|
||||||
|
code: "?",
|
||||||
|
tr: L.hotkeys.HELP,
|
||||||
|
},
|
||||||
|
PREV_SONG: {
|
||||||
|
code: "prevSong",
|
||||||
|
tr: L.hotkeys.PREV_SONG,
|
||||||
|
},
|
||||||
|
NEXT_SONG: {
|
||||||
|
code: "nextSong",
|
||||||
|
tr: L.hotkeys.NEXT_SONG,
|
||||||
|
},
|
||||||
|
TREE_PREV: {
|
||||||
|
code: "treePrev",
|
||||||
|
tr: L.hotkeys.TREE_PREV,
|
||||||
|
},
|
||||||
|
TREE_NEXT: {
|
||||||
|
code: "treeNext",
|
||||||
|
tr: L.hotkeys.TREE_NEXT,
|
||||||
|
},
|
||||||
|
TREE_UP: {
|
||||||
|
code: "treeUp",
|
||||||
|
tr: L.hotkeys.TREE_UP,
|
||||||
|
},
|
||||||
|
PLAY_PAUSE: {
|
||||||
|
code: "playPause",
|
||||||
|
tr: L.hotkeys.PLAY_PAUSE,
|
||||||
|
},
|
||||||
|
DOWNLOAD: {
|
||||||
|
code: "download",
|
||||||
|
tr: L.hotkeys.DOWNLOAD,
|
||||||
|
},
|
||||||
|
CUT: {
|
||||||
|
code: "cut",
|
||||||
|
tr: L.hotkeys.CUT,
|
||||||
|
},
|
||||||
|
COPY: {
|
||||||
|
code: "copy",
|
||||||
|
tr: L.hotkeys.COPY,
|
||||||
|
context: (ctx) => {
|
||||||
|
var sel = window.getSelection && window.getSelection() || {};
|
||||||
|
sel = sel && !sel.isCollapsed && sel.direction != 'none';
|
||||||
|
return !sel;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PASTE: {
|
||||||
|
code: "paste",
|
||||||
|
tr: L.hotkeys.PASTE,
|
||||||
|
},
|
||||||
|
DELETE: {
|
||||||
|
code: "delete",
|
||||||
|
tr: L.hotkeys.DELETE,
|
||||||
|
},
|
||||||
|
FAST_FORWARD: {
|
||||||
|
code: "fastForward",
|
||||||
|
tr: L.hotkeys.FAST_FORWARD,
|
||||||
|
},
|
||||||
|
REWIND: {
|
||||||
|
code: "rewind",
|
||||||
|
tr: L.hotkeys.REWIND,
|
||||||
|
},
|
||||||
|
TOGGLE_BREADCRUMBS: {
|
||||||
|
code: "toggleBreadcrumbs",
|
||||||
|
tr: L.hotkeys.TOGGLE_BREADCRUMBS,
|
||||||
|
},
|
||||||
|
TOGGLE_GRID: {
|
||||||
|
code: "toggleGrid",
|
||||||
|
tr: L.hotkeys.TOGGLE_GRID,
|
||||||
|
},
|
||||||
|
TOGGLE_THUMBNAILS: {
|
||||||
|
code: "toggleThumbnails",
|
||||||
|
tr: L.hotkeys.TOGGLE_THUMBNAILS,
|
||||||
|
},
|
||||||
|
TOGGLE_FOLDER_TREE: {
|
||||||
|
code: "toggleFolderTree",
|
||||||
|
tr: L.hotkeys.TOGGLE_FOLDER_TREE,
|
||||||
|
},
|
||||||
|
RENAME: {
|
||||||
|
code: "rename",
|
||||||
|
tr: L.hotkeys.RENAME,
|
||||||
|
},
|
||||||
|
NAVPANE_SHRINK: {
|
||||||
|
code: "navpaneShrink",
|
||||||
|
tr: L.hotkeys.NAVPANE_SHRINK,
|
||||||
|
context: (ctx) => {
|
||||||
|
return !ctx.treectl.hidden && ctx.gridMode;
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.NAVPANE_SHRINK_DESC
|
||||||
|
},
|
||||||
|
NAVPANE_GROW: {
|
||||||
|
code: "navpaneGrow",
|
||||||
|
tr: L.hotkeys.NAVPANE_GROW,
|
||||||
|
context: (ctx) => {
|
||||||
|
return !ctx.treectl.hidden && ctx.gridMode;
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.NAVPANE_GROW_DESC
|
||||||
|
},
|
||||||
|
SELECT_ALL: {
|
||||||
|
code: "selectAll",
|
||||||
|
tr: L.hotkeys.SELECT_ALL,
|
||||||
|
context: (ctx) => {
|
||||||
|
return ctx.activeElement && ctx.activeElement.closest('pre')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SELECT_SONG: {
|
||||||
|
code: "selectSong",
|
||||||
|
tr: L.hotkeys.SELECT_SONG,
|
||||||
|
context: (ctx) => {
|
||||||
|
return ctx.mp && ctx.mp.au && !ctx.mp.au.paused;
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.SELECT_SONG_DESC
|
||||||
|
},
|
||||||
|
SELECT_FILE: {
|
||||||
|
code: "selectFile",
|
||||||
|
tr: L.hotkeys.SELECT_FILE,
|
||||||
|
context: (ctx) => {
|
||||||
|
return ctx.showfile.active();
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.SELECT_FILE_DESC
|
||||||
|
},
|
||||||
|
EDIT_FILE: {
|
||||||
|
code: "editFile",
|
||||||
|
tr: L.hotkeys.EDIT_FILE,
|
||||||
|
context: (ctx) => {
|
||||||
|
return ctx.showfile.active();
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.EDIT_FILE_DESC
|
||||||
|
},
|
||||||
|
|
||||||
|
TOGGLE_GRID_MULTISELECT: {
|
||||||
|
code: "toggleGridMultiSelect",
|
||||||
|
tr: L.hotkeys.TOGGLE_GRID_MULTISELECT,
|
||||||
|
context: (ctx) => {
|
||||||
|
return ctx.gridMode;
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.TOGGLE_GRID_MULTISELECT_DESC
|
||||||
|
},
|
||||||
|
GRID_SHRINK_THUMBNAILS: {
|
||||||
|
code: "gridShrinkThumbnails",
|
||||||
|
tr: L.hotkeys.GRID_SHRINK_THUMBNAILS,
|
||||||
|
context: (ctx) => {
|
||||||
|
return ctx.gridMode;
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.GRID_SHRINK_THUMBNAILS_DESC
|
||||||
|
},
|
||||||
|
GRID_GROW_THUMBNAILS: {
|
||||||
|
code: "gridGrowThumbnails",
|
||||||
|
tr: L.hotkeys.GRID_GROW_THUMBNAILS,
|
||||||
|
context: (ctx) => {
|
||||||
|
return ctx.gridMode;
|
||||||
|
},
|
||||||
|
desc: L.hotkeys.GRID_GROW_THUMBNAILS_DESC
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultKeybindings = {
|
||||||
|
"escape": HOTKEY_ACTIONS.ESCAPE,
|
||||||
|
"enter": HOTKEY_ACTIONS.ENTER,
|
||||||
|
"shift+?": HOTKEY_ACTIONS.HELP,
|
||||||
|
"?": HOTKEY_ACTIONS.HELP,
|
||||||
|
"J": HOTKEY_ACTIONS.PREV_SONG,
|
||||||
|
"L": HOTKEY_ACTIONS.NEXT_SONG,
|
||||||
|
"K": HOTKEY_ACTIONS.TREE_NEXT,
|
||||||
|
"I": HOTKEY_ACTIONS.TREE_PREV,
|
||||||
|
"P": HOTKEY_ACTIONS.PLAY_PAUSE,
|
||||||
|
"Y": HOTKEY_ACTIONS.DOWNLOAD,
|
||||||
|
"ctrl+X": HOTKEY_ACTIONS.CUT,
|
||||||
|
"ctrl+C": HOTKEY_ACTIONS.COPY,
|
||||||
|
"ctrl+V": HOTKEY_ACTIONS.PASTE,
|
||||||
|
"ctrl+K": HOTKEY_ACTIONS.DELETE,
|
||||||
|
"meta+X": HOTKEY_ACTIONS.CUT,
|
||||||
|
"meta+C": HOTKEY_ACTIONS.COPY,
|
||||||
|
"meta+V": HOTKEY_ACTIONS.PASTE,
|
||||||
|
"meta+K": HOTKEY_ACTIONS.DELETE,
|
||||||
|
"O": HOTKEY_ACTIONS.FAST_FORWARD,
|
||||||
|
"U": HOTKEY_ACTIONS.REWIND,
|
||||||
|
"M": HOTKEY_ACTIONS.TREE_UP,
|
||||||
|
"B": HOTKEY_ACTIONS.TOGGLE_BREADCRUMBS,
|
||||||
|
"G": HOTKEY_ACTIONS.TOGGLE_GRID,
|
||||||
|
"T": HOTKEY_ACTIONS.TOGGLE_THUMBNAILS,
|
||||||
|
"V": HOTKEY_ACTIONS.TOGGLE_FOLDER_TREE,
|
||||||
|
"F2": HOTKEY_ACTIONS.RENAME,
|
||||||
|
"A": HOTKEY_ACTIONS.NAVPANE_SHRINK,
|
||||||
|
"D": HOTKEY_ACTIONS.NAVPANE_GROW,
|
||||||
|
"ctrl+A": HOTKEY_ACTIONS.SELECT_ALL,
|
||||||
|
"S": HOTKEY_ACTIONS.SELECT_SONG,
|
||||||
|
"E": HOTKEY_ACTIONS.EDIT_FILE,
|
||||||
|
"S": HOTKEY_ACTIONS.SELECT_FILE,
|
||||||
|
"shift+S": HOTKEY_ACTIONS.TOGGLE_GRID_MULTISELECT,
|
||||||
|
"shift+A": HOTKEY_ACTIONS.GRID_SHRINK_THUMBNAILS,
|
||||||
|
"shift+D": HOTKEY_ACTIONS.GRID_GROW_THUMBNAILS,
|
||||||
|
};
|
||||||
|
//TODO bit of a mess
|
||||||
|
const currentKeybindings = readKeybindings();
|
||||||
|
const keybindingTree = toTree(currentKeybindings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the keybindings from localStorage
|
||||||
|
* @returns {object} Current user Keybidnds
|
||||||
|
*/
|
||||||
|
function readKeybindings() {
|
||||||
|
const s = sread("keybindings");
|
||||||
|
if (!s) {
|
||||||
|
return defaultKeybindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the keybindings to default
|
||||||
|
* @returns {object} Default keybindings
|
||||||
|
*/
|
||||||
|
function resetKeybindings() {
|
||||||
|
srem("keybindings");
|
||||||
|
return defaultKeybindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a keybinding for a specific action
|
||||||
|
* @param {string} combo Key combination
|
||||||
|
* @param {function} callback Callback function
|
||||||
|
*/
|
||||||
|
function setKeybinding(event) {
|
||||||
|
console.log('Not implemented setKeybinding', event);
|
||||||
|
// sset("keybindings", JSON.stringify(keybindings));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHotkeyEvent(event, context = {}) {
|
||||||
|
const hash = event.ctrlKey << 2 | event.metaKey << 1 | event.shiftKey;
|
||||||
|
let kkey = (event.key || event.code) + '';
|
||||||
|
const matchingHotkeys = keybindingTree[hash][kkey.toLowerCase()] || [];
|
||||||
|
console.log('getHotkeyEvent', event, context, hash, matchingHotkeys);
|
||||||
|
if (matchingHotkeys.length < 2) {
|
||||||
|
return matchingHotkeys[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var validIndex = -1;
|
||||||
|
for (var i = 0; i < matchingHotkeys.length; i++) {
|
||||||
|
var hotkey = matchingHotkeys[i];
|
||||||
|
if (hotkey.context) {
|
||||||
|
if (hotkey.context(context)) return hotkey;
|
||||||
|
} else {
|
||||||
|
validIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('More than 1 matching hotkey without sufficient context check found', event, context, hash, matchingHotkeys);
|
||||||
|
return matchingHotkeys[validIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convers human readable keybindings into a tree structure for fast lookup
|
||||||
|
* @param {object} keybindings
|
||||||
|
* @see getHotkeyEvent for usage
|
||||||
|
* @returns {object[]} tree of keybindings for fast lookup
|
||||||
|
*/
|
||||||
|
function toTree(keybindings) {
|
||||||
|
var tree = [...Array(8)].map(() => ({}));
|
||||||
|
|
||||||
|
for (var combo in keybindings) {
|
||||||
|
var action = keybindings[combo];
|
||||||
|
|
||||||
|
var parts = combo.split("+").map(function (p) {
|
||||||
|
return p.trim().toLowerCase();
|
||||||
|
});
|
||||||
|
|
||||||
|
var hash = 0;
|
||||||
|
hash += parts.indexOf("shift") !== -1 ? 1 : 0;
|
||||||
|
hash += parts.indexOf("ctrl") !== -1 ? 2 : 0;
|
||||||
|
hash += parts.indexOf("meta") !== -1 ? 4 : 0;
|
||||||
|
var key = parts[parts.length - 1]; // last part is the key
|
||||||
|
|
||||||
|
console.log('binding', combo, action, hash, key);
|
||||||
|
if (!tree[hash][key]) tree[hash][key] = [];
|
||||||
|
tree[hash][key].push(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Tree', keybindings, '=>', tree);
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
@ -2330,3 +2330,26 @@ function xhrchk(xhr, prefix, e404, lvl, tag) {
|
||||||
|
|
||||||
return fun(0, prefix + xhr.status + ": " + errtxt, tag);
|
return fun(0, prefix + xhr.status + ": " + errtxt, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazy load a script from the server
|
||||||
|
* @param {string} scriptName name of the script you want to load
|
||||||
|
* @param {function|undefined} callback callback to run when the script is loaded
|
||||||
|
*/
|
||||||
|
function lazyLoad(scriptName, callback) {
|
||||||
|
const scripts = Array.from(QSA('script'));
|
||||||
|
if (scripts.some(s => s.src.endsWith(scriptName))) {
|
||||||
|
callback && callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var s = document.createElement('script');
|
||||||
|
s.src = '/.cpr/' + scriptName;
|
||||||
|
s.onload = function () {
|
||||||
|
callback && callback();
|
||||||
|
};
|
||||||
|
s.onerror = function (e) {
|
||||||
|
console.log('failed loading ' + scriptName, e);
|
||||||
|
};
|
||||||
|
document.head.appendChild(s);
|
||||||
|
}
|
||||||
|
|
@ -137,3 +137,4 @@ copyparty/web/ui.css,
|
||||||
copyparty/web/up2k.js,
|
copyparty/web/up2k.js,
|
||||||
copyparty/web/util.js,
|
copyparty/web/util.js,
|
||||||
copyparty/web/w.hash.js,
|
copyparty/web/w.hash.js,
|
||||||
|
copyparty/web/keybindings.js,
|
||||||
Loading…
Reference in a new issue