Change UI ranking
This commit is contained in:
parent
d38342ad43
commit
9b1724cdad
16 changed files with 291 additions and 631 deletions
|
@ -1,4 +1,142 @@
|
|||
<script src="//cdn.jsdelivr.net/npm/featherlight@1.7.14/release/featherlight.min.js" type="text/javascript" charset="utf-8"></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: `{{url('contest_ranking_ajax', contest.key)}}?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');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$('.leaving-forever').click(function () {
|
||||
return confirm('{{ _('Are you sure you want to leave?') }}\n' +
|
||||
|
@ -9,5 +147,68 @@
|
|||
return confirm('{{ _('Are you sure you want to join?') }}\n' +
|
||||
'{{ _('Joining a contest starts your timer, after which it becomes unstoppable.') }}');
|
||||
});
|
||||
|
||||
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 %}
|
||||
|
||||
// $(".problem-score-a").on('click', function(e) {
|
||||
// var href = $(this).attr('href');
|
||||
// if (href !== '#') return;
|
||||
// e.preventDefault();
|
||||
|
||||
|
||||
// })
|
||||
});
|
||||
|
||||
</script>
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
{% block before_point_head %}
|
||||
{% for problem in problems %}
|
||||
<th class="points header problem-score-col"><a href="{{ url('contest_ranked_submissions', contest.key, problem.problem.code) }}">
|
||||
<th class="points header problem-score-col" title="{{ problem.problem.name }}"><a href="{{ url('problem_detail', problem.problem.code) }}">
|
||||
{{- contest.get_label_for_problem(loop.index0) }}
|
||||
<div class="point-denominator">{{ problem.points }}</div>
|
||||
</a></th>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block users_media %}
|
||||
<link href="//cdn.jsdelivr.net/npm/featherlight@1.7.14/release/featherlight.min.css" type="text/css" rel="stylesheet" />
|
||||
|
||||
<style>
|
||||
#content-left {
|
||||
overflow-x: auto;
|
||||
|
@ -130,6 +132,12 @@
|
|||
color: gray !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.featherlight-content {
|
||||
border-radius: 10px;
|
||||
height: 80%;
|
||||
width: 60%;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% if has_rating %}
|
||||
|
@ -227,215 +235,6 @@
|
|||
});
|
||||
</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 %}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue