466 lines
15 KiB
HTML
466 lines
15 KiB
HTML
{% extends "user/base-users.html" %}
|
|
|
|
{% block title_ruler %}{% endblock %}
|
|
|
|
{% block title_row %}
|
|
{% set title = contest.name %}
|
|
{% include "contest/contest-tabs.html" %}
|
|
{% endblock %}
|
|
|
|
{% block users_media %}
|
|
<style>
|
|
#content-left {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
#users-table .username {
|
|
min-width: 20em;
|
|
}
|
|
|
|
#users-table td {
|
|
height: 2.5em;
|
|
}
|
|
|
|
#users-table a {
|
|
display: block;
|
|
}
|
|
|
|
.userinfo a, .user-name a, .user-name form {
|
|
display: inline !important;
|
|
}
|
|
|
|
#users-table th a, #users-table th a:link, #users-table th a:visited {
|
|
color: white;
|
|
}
|
|
|
|
#users-table th a:hover {
|
|
color: #0F0;
|
|
}
|
|
|
|
#users-table td a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.first-solve {
|
|
background: #00f9a1;
|
|
}
|
|
|
|
.rank {
|
|
min-width: 2.5em
|
|
}
|
|
|
|
.points {
|
|
min-width: 2.5em;
|
|
}
|
|
|
|
.disqualified {
|
|
background-color: #ffa8a8 !important;
|
|
}
|
|
|
|
.full-score, .full-score a {
|
|
font-weight: bold;
|
|
color: green;
|
|
}
|
|
|
|
.partial-score, .partial-score a {
|
|
color: green;
|
|
}
|
|
|
|
.failed-score, .failed-score a {
|
|
font-weight: bold;
|
|
color: red;
|
|
}
|
|
|
|
.pretest-full-score, .pretest-full-score a {
|
|
font-weight: bold;
|
|
color: #2980b9;
|
|
}
|
|
|
|
.pretest-partial-score, .pretest-partial-score a {
|
|
color: #2980b9;
|
|
}
|
|
|
|
.pretest-failed-score, .pretest-failed-score a {
|
|
font-weight: bold;
|
|
color: red;
|
|
}
|
|
|
|
.user-points {
|
|
font-weight: bold;
|
|
color: black;
|
|
}
|
|
|
|
.solving-time {
|
|
color: gray;
|
|
font-weight: normal;
|
|
font-size: 0.75em;
|
|
padding-bottom: -0.75em;
|
|
}
|
|
|
|
.point-denominator {
|
|
border-top: 1px solid gray;
|
|
font-size: 0.7em;
|
|
}
|
|
|
|
.start-time {
|
|
display: none;
|
|
}
|
|
|
|
.user-name {
|
|
position: relative;
|
|
}
|
|
|
|
.organization-column {
|
|
display: none;
|
|
text-align: left !important;
|
|
border-right: none !important;
|
|
}
|
|
|
|
.organization-column a {
|
|
color: gray !important;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.fullname-column {
|
|
text-align: right !important;
|
|
border-right: none !important;
|
|
}
|
|
|
|
.fullname-column span {
|
|
color: gray !important;
|
|
font-weight: 600;
|
|
}
|
|
</style>
|
|
|
|
{% if has_rating %}
|
|
<style>#users-table .rate-box {
|
|
font-size: 0.85em;
|
|
float: left;
|
|
}
|
|
|
|
#users-table td:nth-child(1) .rating {
|
|
margin-left: 1.25em;
|
|
display: block;
|
|
}
|
|
|
|
#users-table td:nth-child(2) a {
|
|
display: block;
|
|
}
|
|
</style>
|
|
{% endif %}
|
|
|
|
<style>
|
|
.select2-selection__arrow {
|
|
display: none;
|
|
}
|
|
|
|
.select2-selection__rendered {
|
|
cursor: text;
|
|
overflow: initial !important
|
|
}
|
|
|
|
.select2-results__option--highlighted {
|
|
background-color: #DEDEDE !important;
|
|
}
|
|
|
|
.select2-results__option {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
#search-contest, #search-contest + .select2 {
|
|
margin-top: 0.5em;
|
|
}
|
|
|
|
#search-contest {
|
|
width: 200px;
|
|
height: 2.3em;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block users_js_media %}
|
|
{% if can_edit %}
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
$('a.disqualify-participation').click(function (e) {
|
|
e.preventDefault();
|
|
if (e.ctrlKey || e.metaKey || confirm("{{ _('Are you sure you want to disqualify this participation?') }}"))
|
|
$(this).closest('form').submit();
|
|
})
|
|
$('a.un-disqualify-participation').click(function (e) {
|
|
e.preventDefault();
|
|
if (e.ctrlKey || e.metaKey || confirm("{{ _('Are you sure you want to un-disqualify this participation?') }}"))
|
|
$(this).closest('form').submit();
|
|
})
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
{% if perms.judge.change_contestparticipation %}
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
$('td.user').find('a.user-name').click(function (e) {
|
|
var data = $(this).siblings('.edit-participation');
|
|
if (e.altKey && data.length) {
|
|
window.open(data.attr('data-link'), '_blank');
|
|
return false;
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
{% if not contest.ended %}
|
|
<script type="text/javascript">
|
|
$(function () {
|
|
window.install_tooltips = function () {
|
|
$('td.user').find('a.user-name').each(function () {
|
|
var link = $(this);
|
|
link.mouseenter(function (e) {
|
|
var start_time = link.siblings('.start-time').text();
|
|
link.addClass('tooltipped tooltipped-e').attr('aria-label', start_time);
|
|
}).mouseleave(function (e) {
|
|
link.removeClass('tooltipped tooltipped-e').removeAttr('aria-label');
|
|
});
|
|
});
|
|
};
|
|
|
|
install_tooltips();
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
<script type="text/javascript" src="{{ static('event.js') }}"></script>
|
|
<script type="text/javascript">
|
|
|
|
function isFaster(time1, time2) {
|
|
let arr1 = time1.split(':');
|
|
let arr2 = time2.split(':');
|
|
|
|
for (let i in arr1) {
|
|
let val1 = parseInt(arr1[i]);
|
|
let val2 = parseInt(arr2[i]);
|
|
if (val1 < val2) return true;
|
|
if (val1 > val2) return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function scoretimeComparison(sub1, sub2) {
|
|
if (!sub2) return true;
|
|
return sub1['score'] > sub2['score'] || (sub1['score'] === sub2['score'] && isFaster(sub1['time'], sub2['time']));
|
|
}
|
|
|
|
function highlightFirstSolve() {
|
|
// bucket to store submissions by problems
|
|
let bestSubmissions = {};
|
|
|
|
// get information
|
|
$('td a').each(function() {
|
|
let td = $(this)[0]
|
|
let link = td['attributes']['href']['value']
|
|
if (link.includes('submissions')) {
|
|
let scoreAndTime = (td.innerText.split('\n'))
|
|
let linkElements = link.split('/')
|
|
|
|
// get information
|
|
let problem = linkElements[linkElements.length - 2];
|
|
let score = parseFloat(scoreAndTime[0]);
|
|
let time = scoreAndTime[1];
|
|
|
|
if (time) {
|
|
let curSubmission = {
|
|
'td': $(this).parent(),
|
|
'score': score,
|
|
'time': time
|
|
}
|
|
|
|
// update best submissions
|
|
let curBest = bestSubmissions[problem]
|
|
|
|
if (scoretimeComparison(curSubmission, curBest) && score) {
|
|
bestSubmissions[problem] = curSubmission;
|
|
}
|
|
}
|
|
}
|
|
})
|
|
for (let problem in bestSubmissions) {
|
|
bestSubmissions[problem]['td'].addClass('first-solve')
|
|
}
|
|
}
|
|
|
|
function renew_filter() {
|
|
var checkboxes = [
|
|
'#show-organizations-checkbox',
|
|
'#show-fullnames-checkbox',
|
|
'#show-total-score-checkbox',
|
|
];
|
|
|
|
var checkboxes2 = [
|
|
'#show-friends-checkbox',
|
|
'#show-virtual-checkbox'
|
|
]
|
|
|
|
for (var i of checkboxes) {
|
|
var $box = $(i);
|
|
if ($box.is(':checked')) {
|
|
$box.prop('checked', false);
|
|
$box.click();
|
|
$box.prop('checked', true);
|
|
}
|
|
}
|
|
|
|
var to_update = false;
|
|
for (var i of checkboxes2) {
|
|
var $box = $(i);
|
|
if ($box.is(':checked')) {
|
|
to_update = true;
|
|
}
|
|
}
|
|
if (to_update) {
|
|
update_ranking();
|
|
}
|
|
}
|
|
|
|
function get_initial_rank() {
|
|
var ranks = $('.rank-td').map(function() {return this.innerHTML}).get();
|
|
var usernames = $('.user-name .rating a').map(function() {return this.text}).get();
|
|
window.user_rank = new Map();
|
|
for (var i = 0; i < ranks.length; i++) {
|
|
window.user_rank[usernames[i]] = ranks[i];
|
|
}
|
|
}
|
|
|
|
function add_initial_friend_rank() {
|
|
var usernames = $('.user-name .rating a').map(function() {return this.text}).get();
|
|
|
|
var is_virtual = [];
|
|
$('.user-name').each(function() {
|
|
if($(this).children('sup').length) {
|
|
is_virtual.push(1);
|
|
}
|
|
else is_virtual.push(0);
|
|
});
|
|
|
|
$('.rank-td').each(function(i) {
|
|
if (!is_virtual[i]) this.innerHTML += ' (' + window.user_rank[usernames[i]] + ')';
|
|
});
|
|
}
|
|
|
|
function update_ranking() {
|
|
var friend = $('#show-friends-checkbox').is(':checked');
|
|
var virtual = $('#show-virtual-checkbox').is(':checked');
|
|
$('#loading-gif').show();
|
|
$.get({
|
|
url: `/contest/{{contest.key}}/ranking/ajax?friend=${friend}&virtual=${virtual}`,
|
|
success: function(HTML) {
|
|
$('#users-table').html(HTML);
|
|
highlightFirstSolve();
|
|
$('#loading-gif').hide();
|
|
if (!virtual && !friend) {
|
|
get_initial_rank();
|
|
}
|
|
if (friend) {
|
|
add_initial_friend_rank();
|
|
}
|
|
},
|
|
fail: function() {
|
|
console.log('Fail to update ranking');
|
|
}
|
|
});
|
|
}
|
|
|
|
// window.load_dynamic_update = function (last_msg) {
|
|
// return new EventReceiver(
|
|
// "{{ EVENT_DAEMON_LOCATION }}", "{{ EVENT_DAEMON_POLL_LOCATION }}",
|
|
// ['contest_{{contest.id}}'], last_msg, function (message) {
|
|
// switch (message.type) {
|
|
// case 'update':
|
|
// update_ranking();
|
|
// break;
|
|
// }
|
|
// }
|
|
// );
|
|
// }
|
|
|
|
$(function () {
|
|
var url = '{{ url('contest_participation', contest.key, '__username__') }}';
|
|
var placeholder = $('#search-contest').replaceWith($('<select>').attr({
|
|
id: 'search-contest'
|
|
})).attr('placeholder');
|
|
|
|
$('#search-contest').select2({
|
|
placeholder: placeholder,
|
|
ajax: {
|
|
url: '{{ url('contest_user_search_select2_ajax', contest.key) }}'
|
|
},
|
|
minimumInputLength: 1,
|
|
escapeMarkup: function (markup) {
|
|
return markup;
|
|
},
|
|
templateResult: function (data, container) {
|
|
return ('<img class="user-search-image" src="' + data.gravatar_url + '" width="24" height="24">' +
|
|
'<span class="' + data.display_rank + ' user-search-name">' + data.text + '</span>');
|
|
}
|
|
}).on('change', function () {
|
|
window.location.href = url.replace('__username__', $(this).val());
|
|
});
|
|
|
|
$('#show-organizations-checkbox').click(function () {
|
|
$('.organization-column').toggle();
|
|
});
|
|
$('#show-fullnames-checkbox').click(function () {
|
|
$('.fullname-column').toggle();
|
|
});
|
|
|
|
{% if request.user.is_authenticated %}
|
|
$('#show-friends-checkbox').click(function() {
|
|
update_ranking();
|
|
})
|
|
{% endif %}
|
|
$('#show-virtual-checkbox').click(function() {
|
|
update_ranking();
|
|
})
|
|
$('#show-total-score-checkbox').click(function() {
|
|
$('.problem-score-col').toggle();
|
|
})
|
|
|
|
highlightFirstSolve();
|
|
renew_filter();
|
|
get_initial_rank();
|
|
{% if participation_tab %}
|
|
$('#show-virtual-checkbox').hide();
|
|
$('#show-virtual-label').hide();
|
|
{% else %}
|
|
{% if request.in_contest %}
|
|
setInterval(update_ranking, 60 * 1000);
|
|
{% endif %}
|
|
{% endif %}
|
|
|
|
});
|
|
</script>
|
|
{% include "contest/media-js.html" %}
|
|
{% endblock %}
|
|
|
|
{% block users_table %}
|
|
<div style="margin-bottom: 0.5em">
|
|
{% if tab == 'participation' %}
|
|
{% if contest.can_see_full_scoreboard(request.user) %}
|
|
<input id="search-contest" type="text" placeholder="{{ _('View user participation') }}">
|
|
{% endif %}
|
|
{% endif %}
|
|
<input id="show-organizations-checkbox" type="checkbox" style="vertical-align: bottom">
|
|
<label for="show-organizations-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Show organizations') }}</label>
|
|
|
|
<input id="show-fullnames-checkbox" type="checkbox" style="vertical-align: bottom">
|
|
|
|
<label for="show-fullnames-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Show full name') }}</label>
|
|
{% if request.user.is_authenticated %}
|
|
<input id="show-friends-checkbox" type="checkbox" style="vertical-align: bottom;">
|
|
<label for="show-friends-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Show friends only') }}</label>
|
|
{% endif %}
|
|
<input id="show-total-score-checkbox" type="checkbox" style="vertical-align: bottom; ">
|
|
<label for="show-total-score-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Total score only') }}</label>
|
|
<input id="show-virtual-checkbox" type="checkbox" style="vertical-align: bottom;">
|
|
<label id="show-virtual-label" for="show-virtual-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Show virtual participation') }}</label>
|
|
<img src="{{static('loading.gif')}}" style="height: 1em; display:none;" id="loading-gif"></img>
|
|
</div>
|
|
{% include "contest/ranking-table.html" %}
|
|
{% endblock %}
|