Skip to content

Commit 83bbfb4

Browse files
committed
Show tabs for deleted files
1 parent 77cb61a commit 83bbfb4

File tree

4 files changed

+128
-50
lines changed

4 files changed

+128
-50
lines changed

webapp/public/js/domjudge.js

Lines changed: 65 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,8 +1297,19 @@ function initScoreboardSubmissions() {
12971297
});
12981298
}
12991299

1300+
const enableButton = (btn, url) => {
1301+
btn.href = url;
1302+
btn.classList.remove('disabled');
1303+
btn.ariaDisabled=false;
1304+
};
1305+
1306+
const disableButton = (btn) => {
1307+
btn.classList.add('disabled');
1308+
btn.ariaDisabled=true;
1309+
}
1310+
13001311
const editors = [];
1301-
function initDiffEditor(editorId) {
1312+
function initDiffEditor(editorId, deletedFiles) {
13021313
const wrapper = $(`#${editorId}-wrapper`);
13031314

13041315
const initialTag = getDiffTag();
@@ -1332,14 +1343,14 @@ function initDiffEditor(editorId) {
13321343
if (rank) {
13331344
let url = new URL(download.href);
13341345
url.searchParams.set("fetch", rank);
1335-
download.href = url;
1346+
enableButton(download, url);
13361347

13371348
url = new URL(edit.href);
13381349
url.searchParams.set("rank", rank);
1339-
edit.href = url;
1350+
enableButton(edit, url);
13401351
} else {
1341-
download.href = "#";
1342-
edit.href = "#";
1352+
disableButton(download);
1353+
disableButton(edit);
13431354
}
13441355
};
13451356
wrapper.find(".nav").on('show.bs.tab', (e) => {
@@ -1358,37 +1369,6 @@ function initDiffEditor(editorId) {
13581369
let s = select[0];
13591370
return s.options[s.selectedIndex].value;
13601371
},
1361-
'updateIcon': (rank, icon) => {
1362-
const element = wrapper.find(".nav-link[data-rank]")[rank].querySelector('.fa-fw');
1363-
element.className = 'fas fa-fw fa-' + icon;
1364-
},
1365-
'renamedFrom': (rank, oldName) => {
1366-
const navItem = wrapper.find(".nav-link[data-rank]")[rank];
1367-
let renamedFromName = navItem.querySelector('.renamed');
1368-
let arrow = navItem.querySelector('.fa-arrow-right');
1369-
if (oldName === undefined) {
1370-
if (renamedFromName) {
1371-
navItem.removeChild(renamedFromName);
1372-
}
1373-
if (arrow) {
1374-
navItem.removeChild(arrow);
1375-
}
1376-
return;
1377-
}
1378-
1379-
if (!renamedFromName) {
1380-
renamedFromName = document.createElement('span');
1381-
renamedFromName.className = 'renamed';
1382-
navItem.insertBefore(renamedFromName, navItem.childNodes[1]);
1383-
}
1384-
renamedFromName.innerText = ` ${oldName} `;
1385-
1386-
if (!arrow) {
1387-
arrow = document.createElement('i');
1388-
arrow.className = 'fas fa-arrow-right';
1389-
navItem.insertBefore(arrow, navItem.childNodes[2]);
1390-
}
1391-
},
13921372
'onDiffModeChange': (f) => {
13931373
radios.change((e) => {
13941374
const diffMode = e.target.value;
@@ -1397,8 +1377,8 @@ function initDiffEditor(editorId) {
13971377
},
13981378
'onDiffSelectChange': (f) => {
13991379
select.change((e) => {
1400-
const submitId = e.target.value;
1401-
const noDiff = submitId === "";
1380+
const noDiff = e.target.value === "";
1381+
const submitId = parseInt(e.target.value);
14021382
f(submitId, noDiff);
14031383
});
14041384
}
@@ -1420,15 +1400,14 @@ function initDiffEditor(editorId) {
14201400
if (selected && selected.dataset.tag) {
14211401
setDiffTag(selected.dataset.tag);
14221402
}
1423-
1424-
// TODO: add tab panes for deleted source files.
14251403
};
1426-
updateSelect(select[0].value, select[0].value === "");
1404+
updateSelect(parseInt(select[0].value), select[0].value === "");
14271405
editor.onDiffSelectChange(updateSelect);
14281406
}
14291407

14301408
function initDiffEditorTab(editorId, diffId, rank, models, modifiedModel) {
14311409
const empty = monaco.editor.getModel(monaco.Uri.file("empty")) ?? monaco.editor.createModel("", undefined, monaco.Uri.file("empty"));
1410+
const navItem = document.getElementById(`${diffId}-link`);
14321411

14331412
const diffEditor = monaco.editor.createDiffEditor(
14341413
document.getElementById(diffId), {
@@ -1450,19 +1429,52 @@ function initDiffEditorTab(editorId, diffId, rank, models, modifiedModel) {
14501429
};
14511430
editors[editorId].onDiffModeChange(updateMode);
14521431

1432+
const renamedFrom = (oldName) => {
1433+
let renamedFromName = navItem.querySelector('.renamed');
1434+
let arrow = navItem.querySelector('.fa-arrow-right');
1435+
if (oldName === undefined) {
1436+
if (renamedFromName) {
1437+
navItem.removeChild(renamedFromName);
1438+
}
1439+
if (arrow) {
1440+
navItem.removeChild(arrow);
1441+
}
1442+
return;
1443+
}
1444+
1445+
if (!renamedFromName) {
1446+
renamedFromName = document.createElement('span');
1447+
renamedFromName.className = 'renamed';
1448+
navItem.insertBefore(renamedFromName, navItem.childNodes[1]);
1449+
}
1450+
renamedFromName.innerText = ` ${oldName} `;
1451+
1452+
if (!arrow) {
1453+
arrow = document.createElement('i');
1454+
arrow.className = 'fas fa-arrow-right';
1455+
navItem.insertBefore(arrow, navItem.childNodes[2]);
1456+
}
1457+
};
1458+
14531459
const updateSelect = (submitId, noDiff) => {
1460+
const exists = submitId in models;
1461+
if (rank === undefined) {
1462+
document.getElementById(diffId).parentElement.style.display = exists ? 'block' : 'none';
1463+
navItem.style.display = exists ? 'block' : 'none';
1464+
if (!exists) return;
1465+
}
1466+
14541467
const model = models[submitId] ??= {'model': empty};
14551468
if (!noDiff) {
14561469
if (!model['model']) {
1457-
// TODO: show source code instead of diff to empty file?
14581470
model['model'] = monaco.editor.createModel(model['source'], undefined, monaco.Uri.file("test/" + submitId + "/" + model['filename']));
14591471
}
14601472
}
14611473

14621474
if (noDiff || !model['renamedFrom']) {
1463-
editors[editorId].renamedFrom(rank, undefined);
1475+
renamedFrom(undefined);
14641476
} else {
1465-
editors[editorId].renamedFrom(rank, model['renamedFrom']);
1477+
renamedFrom(model['renamedFrom']);
14661478
}
14671479

14681480
diffEditor.updateOptions({
@@ -1496,19 +1508,24 @@ function initDiffEditorTab(editorId, diffId, rank, models, modifiedModel) {
14961508
updateSelect(editors[editorId].getDiffSelection(), editors[editorId].getDiffSelection() === "");
14971509

14981510
const updateIcon = () => {
1511+
if (rank === undefined) return;
1512+
const update = (icon) => {
1513+
const element = navItem.querySelector('.fa-fw');
1514+
element.className = 'fas fa-fw fa-' + icon;
1515+
};
14991516
const noDiff = editors[editorId].getDiffSelection() === "";
15001517
if (noDiff) {
1501-
editors[editorId].updateIcon(rank, 'file');
1518+
update('file');
15021519
return;
15031520
}
15041521

15051522
const lineChanges = diffEditor.getLineChanges();
15061523
if (diffEditor.getModel().original == empty) {
1507-
editors[editorId].updateIcon(rank, 'file-circle-plus');
1524+
update('file-circle-plus');
15081525
} else if (lineChanges !== null && lineChanges.length > 0) {
1509-
editors[editorId].updateIcon(rank, 'file-circle-exclamation');
1526+
update('file-circle-exclamation');
15101527
} else {
1511-
editors[editorId].updateIcon(rank, 'file-circle-check');
1528+
update('file-circle-check');
15121529
}
15131530
}
15141531
diffEditor.onDidUpdateDiff(updateIcon);

webapp/src/Controller/Jury/SubmissionController.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ public function sourceAction(
848848
->orderBy('file.ranknumber')
849849
->getQuery()
850850
->getResult();
851+
// TODO: change array to `filename -> file` for efficiency of renaming?
851852
852853
$otherSubmissions = [];
853854
$originalSubmission = $submission->getOriginalSubmission();
@@ -929,6 +930,23 @@ public function sourceAction(
929930
}
930931
}
931932

933+
$deletedFiles = [];
934+
foreach ($otherSubmissions as $s) {
935+
$submitId = $s->getSubmitid();
936+
$sf = $otherFiles[$submitId];
937+
if (count($files) === 1 && count($sf) === 1) {
938+
continue;
939+
}
940+
foreach ($sf as $name => $file) {
941+
if (!array_key_exists($name, $files)) {
942+
// TODO: note to self: rotated the key order s.t. we can iterate over deleted filenames in a.o. twig
943+
$deletedFiles[$name] ??= [];
944+
$deletedFiles[$name][$submitId] = $otherFiles[$submitId][$name];
945+
}
946+
}
947+
}
948+
dump($deletedFiles);
949+
932950
return $this->render('jury/submission_source.html.twig', [
933951
'submission' => $submission,
934952
'files' => $files,
@@ -937,6 +955,7 @@ public function sourceAction(
937955
'allowEdit' => $this->allowEdit(),
938956
'otherSubmissions' => $otherSubmissions,
939957
'otherFiles' => $otherFiles,
958+
'deletedFiles' => $deletedFiles,
940959
]);
941960
}
942961

webapp/src/Twig/TwigExtension.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public function getFunctions(): array
7373
new TwigFunction('globalBannerAssetPath', $this->dj->globalBannerAssetPath(...)),
7474
new TwigFunction('shadowMode', $this->shadowMode(...)),
7575
new TwigFunction('showDiff', $this->showDiff(...), ['is_safe' => ['html']]),
76+
new TwigFunction('showDeleted', $this->showDeleted(...), ['is_safe' => ['html']]),
7677
];
7778
}
7879

@@ -994,6 +995,32 @@ public function showDiff(string $editorId, string $diffId, SubmissionFile $newFi
994995
);
995996
}
996997

998+
/** @param array<int, SubmissionFile[]> $deletedFiles */
999+
public function showDeleted(string $editorId, string $diffId, string $filename, array $deletedFiles): string
1000+
{
1001+
$editor = <<<HTML
1002+
<div class="editor" id="$diffId"></div>
1003+
<script>
1004+
$(function() {
1005+
const editorId = '%s';
1006+
const diffId = '%s';
1007+
const models = %s;
1008+
require(['vs/editor/editor.main'], () => {
1009+
const modifiedModel = monaco.editor.getModel(monaco.Uri.file("empty"));
1010+
initDiffEditorTab(editorId, diffId, undefined, models, modifiedModel);
1011+
});
1012+
});
1013+
</script>
1014+
HTML;
1015+
1016+
return sprintf(
1017+
$editor,
1018+
$editorId,
1019+
$diffId,
1020+
$this->serializer->serialize($deletedFiles, 'json'),
1021+
);
1022+
}
1023+
9971024
public function printContestStart(Contest $contest): string
9981025
{
9991026
$res = "scheduled to start ";

webapp/templates/jury/partials/submission_diff.html.twig

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@
55
{%- for file in files %}
66
{% set diff_id = "diff" ~ file.submitfileid %}
77
<li class="nav-item">
8-
<a class="nav-link {{ extra_css_classes }}" data-bs-toggle="tab" data-rank="{{ file.rank }}" href="#{{ diff_id }}-tab" role="tab"><i class="fas fa-fw fa-file"></i> {{ file.filename }}</a>
8+
<a id="{{ diff_id }}-link" class="nav-link {{ extra_css_classes }}" data-bs-toggle="tab" data-rank="{{ file.rank }}" href="#{{ diff_id }}-tab" role="tab"><i class="fas fa-fw fa-file"></i> {{ file.filename }}</a>
99
</li>
1010
{% set extra_css_classes = "" %}
1111
{%- endfor %}
12+
{%- for deletedName, _ in deletedFiles %}
13+
{% set diff_id = "diff-deleted-" ~ deletedName %}
14+
<li class="nav-item">
15+
<a id="{{ diff_id }}-link" class="nav-link source-deleted" data-bs-toggle="tab" href="#{{ diff_id }}-tab" role="tab"><i class="fas fa-fw fa-file-circle-minus"></i> {{ deletedName }}</a>
16+
</li>
17+
{%- endfor -%}
1218

1319
<li class="nav-item flex-grow-1 text-end mb-1">
1420
<a class="download btn btn-secondary btn-sm"
@@ -50,18 +56,27 @@
5056
<script>
5157
$(() => {
5258
require(['vs/editor/editor.main'], () => {
53-
initDiffEditor('{{ editor_id }}');
59+
const deletedFiles = {{ deletedFiles | json_encode | raw }};
60+
initDiffEditor('{{ editor_id }}', deletedFiles);
5461
});
5562
});
5663
</script>
5764
{% set extra_css_classes = "show active" %}
5865
<div class="tab-content source-tab">
5966
{%- for file in files %}
67+
{# TODO: rewrite s.t. files is also a nice array like otherFiles #}
68+
{# TODO: allow null to showDiff work as deleted file #}
6069
{% set diff_id = "diff" ~ file.submitfileid %}
6170
<div class="tab-pane fade {{ extra_css_classes }}" id="{{ diff_id }}-tab" role="tabpanel">
6271
{{ showDiff(editor_id, diff_id, file, otherFiles) }}
6372
</div>
6473
{% set extra_css_classes = "" %}
6574
{%- endfor %}
75+
{%- for deletedName, deletedF in deletedFiles %}
76+
{% set diff_id = "diff-deleted-" ~ deletedName %}
77+
<div class="tab-pane fade source-deleted" id="{{ diff_id }}-tab" role="tabpanel">
78+
{{ showDeleted(editor_id, diff_id, deletedName, deletedF) }}
79+
</div>
80+
{%- endfor %}
6681
</div>
6782
</div>

0 commit comments

Comments
 (0)