Skip to content

Commit 5b3413a

Browse files
committed
Add keyboard shortcuts.
1 parent e3bc681 commit 5b3413a

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

webapp/public/js/domjudge.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,3 +809,112 @@ function setupPreviewClarification($input, $previewDiv, previewInitial) {
809809
$(function () {
810810
$('[data-toggle="tooltip"]').tooltip();
811811
});
812+
813+
function initializeKeyboardShortcuts() {
814+
var $body = $('body');
815+
var ignore = false;
816+
$body.on('keydown', function(e) {
817+
// Check if the user is not typing in an input field.
818+
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
819+
return;
820+
}
821+
var key = e.key.toLowerCase();
822+
if (key === '?') {
823+
var $keyhelp = $('#keyhelp');
824+
if ($keyhelp.length) {
825+
$keyhelp.toggleClass('d-none');
826+
}
827+
return;
828+
}
829+
if (key === 'escape') {
830+
var $keyhelp = $('#keyhelp');
831+
if ($keyhelp.length && !$keyhelp.hasClass('d-none')) {
832+
$keyhelp.addClass('d-none');
833+
}
834+
}
835+
836+
if (!ignore && !e.shiftKey && (key === 'j' || key === 'k')) {
837+
var parts = window.location.href.split('/');
838+
var lastPart = parts[parts.length - 1];
839+
var params = lastPart.split('?');
840+
var currentNumber = parseInt(params[0]);
841+
if (isNaN(currentNumber)) {
842+
return;
843+
}
844+
if (key === 'j') {
845+
parts[parts.length - 1] = currentNumber + 1;
846+
} else if (key === 'k') {
847+
parts[parts.length - 1] = currentNumber - 1;
848+
}
849+
if (params.length > 1) {
850+
parts[parts.length - 1] += '?' + params[1];
851+
}
852+
window.location = parts.join('/');
853+
} else if (!ignore && (key === 's' || key === 't' || key === 'p' || key === 'j' || key === 'c')) {
854+
if (e.shiftKey && key === 's') {
855+
window.location = domjudge_base_url + '/jury/scoreboard';
856+
return;
857+
}
858+
var type = key;
859+
ignore = true;
860+
var oldFunc = null;
861+
var events = $._data($body[0], 'events');
862+
if (events && events.keydown) {
863+
oldFunc = events.keydown[0].handler;
864+
}
865+
var sequence = '';
866+
var box = null;
867+
var $sequenceBox = $('<div class="keybox"></div>');
868+
box = $sequenceBox;
869+
$sequenceBox.text(type + sequence);
870+
$sequenceBox.appendTo($body);
871+
$body.on('keydown', function(e) {
872+
// Check if the user is not typing in an input field.
873+
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
874+
ignore = false;
875+
if (box) {
876+
box.remove();
877+
}
878+
sequence = '';
879+
return;
880+
}
881+
if (e.key >= '0' && e.key <= '9') {
882+
sequence += e.key;
883+
box.text(type + sequence);
884+
} else if (e.key === 'Enter') {
885+
ignore = false;
886+
switch (type) {
887+
case 's':
888+
type = 'submissions';
889+
break;
890+
case 't':
891+
type = 'teams';
892+
break;
893+
case 'p':
894+
type = 'problems';
895+
break;
896+
case 'c':
897+
type = 'clarifications';
898+
break;
899+
case 'j':
900+
window.location = domjudge_base_url + '/jury/submissions/by-judging-id/' + sequence;
901+
return;
902+
}
903+
var redirect_to = domjudge_base_url + '/jury/' + type;
904+
if (sequence) {
905+
redirect_to += '/' + sequence;
906+
}
907+
window.location = redirect_to;
908+
} else {
909+
ignore = false;
910+
if (box) {
911+
box.remove();
912+
}
913+
sequence = '';
914+
$body.off('keydown');
915+
$body.on('keydown', oldFunc);
916+
}
917+
});
918+
}
919+
});
920+
}

webapp/public/style_domjudge.css

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,3 +659,40 @@ blockquote {
659659
.lasttcruns, .lastresult {
660660
opacity: 0.5;
661661
}
662+
663+
.keybox {
664+
position: fixed;
665+
top: 50%;
666+
left: 50%;
667+
transform: translate(-50%, -50%);
668+
background-color: #295D8A;
669+
font-size: 200%;
670+
font-weight: bold;
671+
color: white;
672+
padding: 20px;
673+
border-radius: 5px;
674+
z-index: 1000;
675+
}
676+
677+
#keyhelp {
678+
position: fixed;
679+
height: 90%;
680+
width: 90%;
681+
top: 50%;
682+
left: 50%;
683+
transform: translate(-50%, -50%);
684+
background-color: rgba(41, 93, 138, 0.9);
685+
font-size: 150%;
686+
font-weight: bold;
687+
color: white;
688+
padding: 20px;
689+
border-radius: 5px;
690+
z-index: 1001;
691+
}
692+
693+
#keyhelp code {
694+
color: white;
695+
background-color: black;
696+
padding: 3px;
697+
border-radius: 5px;
698+
}

webapp/templates/jury/base.html.twig

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,40 @@
3939
4040
$('[data-bs-toggle="tooltip"]').tooltip();
4141
});
42+
43+
initializeKeyboardShortcuts();
4244
</script>
45+
46+
<div class="container d-none" id="keyhelp">
47+
<h1>Keyboard shortcuts</h1>
48+
49+
<code>?</code> display this help, <code>Escape</code> to exit <br/>
50+
<br/>
51+
52+
<code>j</code> go to the next item, e.g. next submission <br/>
53+
<code>k</code> go to the previous item, e.g. previous submission <br/>
54+
<br/>
55+
56+
<code>s</code> <code>↵</code> open the list of submissions <br/>
57+
<code>s</code> <code>[0-9]+</code> <code>↵</code> open a specific submission, e.g. <code>s42↵</code> to go to submission 42 <br/>
58+
<br/>
59+
60+
<code>t</code> <code>↵</code> open the list of teams <br/>
61+
<code>t</code> <code>[0-9]+</code> <code>↵</code> open to a specific team <br/>
62+
<br/>
63+
64+
<code>p</code> <code>↵</code> open the list of problems <br/>
65+
<code>p</code> <code>[0-9]+</code> <code>↵</code> open a specific problem <br/>
66+
<br/>
67+
68+
<code>c</code> <code>↵</code> open the list of clarifications <br/>
69+
<code>c</code> <code>[0-9]+</code> <code>↵</code> open a specific clarification <br/>
70+
<br/>
71+
72+
<code>Shift + j</code> <code>[0-9]+</code> <code>↵</code> open a specific judging <br/>
73+
<br/>
74+
75+
<code>Shift + s</code> open the scoreboard<br/>
76+
<br/>
77+
</div>
4378
{% endblock %}

0 commit comments

Comments
 (0)