Cloned DMOJ
This commit is contained in:
parent
f623974b58
commit
49dc9ff10c
513 changed files with 132349 additions and 39 deletions
35
templates/contest/access_code.html
Normal file
35
templates/contest/access_code.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block media %}
|
||||
<style>
|
||||
#access-code-form {
|
||||
margin: 50px auto 0;
|
||||
display: block;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
#id_access_code {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button-line {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form id="access-code-form" action="" method="post" class="form-area">
|
||||
{% csrf_token %}
|
||||
{% if form.errors or wrong_code %}
|
||||
<div id="form-errors">
|
||||
<p class="error">{{ _('Invalid access code.') }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<p>{{ _('Please enter your access code:') }}</p>
|
||||
<p>{{ form.access_code }}</p>
|
||||
<p class="button-line">
|
||||
<button type="submit">{{ _('Join Contest') }}</button>
|
||||
</p>
|
||||
</form>
|
||||
{% endblock %}
|
46
templates/contest/calendar.html
Normal file
46
templates/contest/calendar.html
Normal file
|
@ -0,0 +1,46 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title_ruler %}{% endblock %}
|
||||
|
||||
{% block title_row %}
|
||||
{% set tab = 'calendar' %}
|
||||
{% include "contest/contest-list-tabs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<table id="contest-calendar">
|
||||
<tr>
|
||||
<th>{{ _('Sunday') }}</th>
|
||||
<th>{{ _('Monday') }}</th>
|
||||
<th>{{ _('Tuesday') }}</th>
|
||||
<th>{{ _('Wednesday') }}</th>
|
||||
<th>{{ _('Thursday') }}</th>
|
||||
<th>{{ _('Friday') }}</th>
|
||||
<th>{{ _('Saturday') }}</th>
|
||||
</tr>
|
||||
{% for week in calendar %}
|
||||
<tr>{% for day in week %}
|
||||
<td class="{{ day.weekday }}{% if day.is_today %} today{% endif %}{% if day.is_pad %} noday{% endif %}">
|
||||
<span class="num">{{ day.date.day }}</span>
|
||||
<ul class="fa-ul">
|
||||
{% for contest in day.starts %}
|
||||
<li class="start"><i class="fa fa-li fa-lg fa-step-forward"></i>
|
||||
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% for contest in day.oneday %}
|
||||
<li class="oneday">
|
||||
<i class="fa fa-li fa-lg fa-play"></i>
|
||||
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% for contest in day.ends %}
|
||||
<li class="end"><i class="fa fa-li fa-lg fa-step-backward"></i>
|
||||
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
{% endfor %}</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
42
templates/contest/clone.html
Normal file
42
templates/contest/clone.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block media %}
|
||||
<style>
|
||||
#contest-clone-panel {
|
||||
position: relative;
|
||||
margin: 5em auto auto -10em;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
#contest-key-container {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
#id_key {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
ul.errorlist {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form id="contest-clone-panel" action="" method="post" class="form-area">
|
||||
{% csrf_token %}
|
||||
{% if form.errors %}
|
||||
<div id="form-errors">
|
||||
{{ form.key.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div><label class="inline-header grayed">{{ _('Enter a new key for the cloned contest:') }}</label></div>
|
||||
<div id="contest-key-container"><span class="fullwidth">{{ form.key }}</span></div>
|
||||
<hr>
|
||||
<button style="float: right;" type="submit">{{ _('Clone!') }}</button>
|
||||
</form>
|
||||
{% endblock %}
|
26
templates/contest/contest-list-tabs.html
Normal file
26
templates/contest/contest-list-tabs.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% extends "tabs-base.html" %}
|
||||
|
||||
{% block post_tab_spacer %}
|
||||
{% if tab == 'calendar' %}
|
||||
<div style="font-size: 1.6em; margin-top: 0.3em">
|
||||
{% if prev_month %}
|
||||
<a href="{{ url('contest_calendar', prev_month.year, prev_month.month) }}">« {{ _('Prev') }}</a>
|
||||
{% endif %}
|
||||
{% if not (curr_month.year == now.year and curr_month.month == now.month) %}
|
||||
<a href="{{ url('contest_calendar', now.year, now.month) }}"> {{ _('Today') }}</a>
|
||||
{% endif %}
|
||||
{% if next_month %}
|
||||
<a href="{{ url('contest_calendar', next_month.year, next_month.month) }}">{{ _('Next') }} »</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<span class="spacer"></span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block tabs %}
|
||||
{{ make_tab('list', 'fa-list', url('contest_list'), _('List')) }}
|
||||
{{ make_tab('calendar', 'fa-calendar', url('contest_calendar', now.year, now.month), _('Calendar')) }}
|
||||
{% if perms.judge.change_contest %}
|
||||
{{ make_tab('admin', 'fa-edit', url('admin:judge_contest_changelist'), _('Admin')) }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
88
templates/contest/contest-tabs.html
Normal file
88
templates/contest/contest-tabs.html
Normal file
|
@ -0,0 +1,88 @@
|
|||
{% extends "tabs-base.html" %}
|
||||
|
||||
{% block tabs %}
|
||||
{{ make_tab('detail', 'fa-info-circle', url('contest_view', contest.key), _('Info')) }}
|
||||
{% if contest.ended or contest.is_editable_by(request.user) %}
|
||||
{{ make_tab('stats', 'fa-pie-chart', url('contest_stats', contest.key), _('Statistics')) }}
|
||||
{% endif %}
|
||||
|
||||
{% if contest.start_time <= now or perms.judge.see_private_contest %}
|
||||
{% if contest.show_scoreboard or contest.can_see_scoreboard(request.user) %}
|
||||
{{ make_tab('ranking', 'fa-bar-chart', url('contest_ranking', contest.key), _('Rankings')) }}
|
||||
{% else %}
|
||||
{{ make_tab('ranking', 'fa-bar-chart', None, _('Hidden Rankings')) }}
|
||||
{% endif %}
|
||||
{% if contest.show_scoreboard and request.user.is_authenticated %}
|
||||
{{ make_tab('participation', 'fa-users', url('contest_participation_own', contest.key), _('Participation')) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if contest.is_editable_by(request.user) %}
|
||||
{% if perms.judge.moss_contest and has_moss_api_key %}
|
||||
{{ make_tab('moss', 'fa-gavel', url('contest_moss', contest.key), _('MOSS')) }}
|
||||
{% endif %}
|
||||
{{ make_tab('edit', 'fa-edit', url('admin:judge_contest_change', contest.id), _('Edit')) }}
|
||||
{% endif %}
|
||||
{% if perms.judge.clone_contest %}
|
||||
{{ make_tab('clone', 'fa-copy', url('contest_clone', contest.key), _('Clone')) }}
|
||||
{% endif %}
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
{% if contest.can_join or participating or is_organizer %}
|
||||
{% if contest.ended %}
|
||||
{% if in_contest %}
|
||||
{# They're in the contest because they're participating virtually #}
|
||||
<form action="{{ url('contest_leave', contest.key) }}" method="post"
|
||||
class="contest-join-pseudotab unselectable button full">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="leaving-forever" value="{{ _('Leave contest') }}">
|
||||
</form>
|
||||
{% else %}
|
||||
{# They're in the contest because they're participating virtually #}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post"
|
||||
class="contest-join-pseudotab unselectable button full">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="{{ _('Virtual join') }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if in_contest %}
|
||||
{# Allow people with ended participations to continue spectating #}
|
||||
<form action="{{ url('contest_leave', contest.key) }}" method="post"
|
||||
class="contest-join-pseudotab unselectable button full">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="
|
||||
{%- if participating and participation.ended or request.profile in contest.organizers.all() %}
|
||||
{{- _('Stop spectating') -}}
|
||||
{% else %}
|
||||
{{- _('Leave contest') -}}
|
||||
{% endif %}">
|
||||
</form>
|
||||
{% elif participating and participation.ended or is_organizer %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post"
|
||||
class="contest-join-pseudotab unselectable button full">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="{{ _('Spectate contest') }}">
|
||||
</form>
|
||||
{% elif participating %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post"
|
||||
class="contest-join-pseudotab unselectable button full">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="{{ _('Join contest') }}">
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post"
|
||||
class="contest-join-pseudotab unselectable button full">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="first-join" value="{{ _('Join contest') }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% elif contest.can_join %}
|
||||
<form action="{{ url('auth_login') }}" method="get"
|
||||
class="contest-join-pseudotab unselectable button full">
|
||||
<input type="hidden" name="next" value="{{ LOGIN_RETURN_PATH|urlencode }}">
|
||||
<input type="submit" value="{{ _('Login to participate') }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
137
templates/contest/contest.html
Normal file
137
templates/contest/contest.html
Normal file
|
@ -0,0 +1,137 @@
|
|||
{% extends "common-content.html" %}
|
||||
|
||||
{% block title_ruler %}{% endblock %}
|
||||
|
||||
{% block title_row %}
|
||||
{% set tab = 'detail' %}
|
||||
{% set title = contest.name %}
|
||||
{% include "contest/contest-tabs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content_js_media %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('.time-remaining').each(function () {
|
||||
count_down($(this));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% include "contest/media-js.html" %}
|
||||
{% include "comments/media-js.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content_media %}
|
||||
{% include "comments/media-css.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div id="banner">
|
||||
<a href="https://www.timeanddate.com/worldclock/fixedtime.html?msg={{ contest.name|urlquote('') }}&iso=
|
||||
{{- contest.start_time|utc|date('Y-m-d\TH:i:s') }}" class="date">
|
||||
{%- if participating and participation.virtual and not participation.ended -%}
|
||||
{% if participation.spectate %}
|
||||
{{- _('Spectating, contest ends in %(countdown)s.', countdown=contest.time_before_end|as_countdown) -}}
|
||||
{% elif participation.end_time %}
|
||||
{{- _('Participating virtually, %(countdown)s remaining.', countdown=participation.time_remaining|as_countdown) -}}
|
||||
{% else %}
|
||||
{{- _('Participating virtually.') -}}
|
||||
{% endif %}
|
||||
{%- else -%}
|
||||
{% if contest.start_time > now %}
|
||||
{{- _('Starting in %(countdown)s', countdown=contest.time_before_start|as_countdown) -}}
|
||||
{% elif contest.end_time < now %}
|
||||
{{- _('Contest is over.') -}}
|
||||
{% else %}
|
||||
{%- if participating -%}
|
||||
{% if participation.ended %}
|
||||
{{- _('Your time is up! Contest ends in %(countdown)s.', countdown=contest.time_before_end|as_countdown) -}}
|
||||
{% else %}
|
||||
{{- _('You have %(countdown)s remaining.', countdown=participation.time_remaining|as_countdown) -}}
|
||||
{% endif %}
|
||||
{%- else -%}
|
||||
{{ _('Contest ends in %(countdown)s.', countdown=contest.time_before_end|as_countdown) }}
|
||||
{%- endif -%}
|
||||
{% endif %}
|
||||
{%- endif -%}
|
||||
</a>
|
||||
<div id="time">
|
||||
{% if contest.time_limit %}
|
||||
{% trans trimmed start_time=contest.start_time|date(_("F j, Y, G:i T")), end_time=contest.end_time|date(_("F j, Y, G:i T")), time_limit=contest.time_limit|timedelta('localized-no-seconds') %}
|
||||
<b>{{ time_limit }}</b> window between <b>{{ start_time }}</b> and <b>{{ end_time }}</b>
|
||||
{% endtrans %}
|
||||
{% else %}
|
||||
{% trans trimmed length=contest.contest_window_length|timedelta("localized-no-seconds"), start_time=contest.start_time|date(_("F j, Y, G:i T")) %}
|
||||
<b>{{ length }}</b> long starting on <b>{{ start_time }}</b>
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-description">
|
||||
{% cache 3600 'contest_html' contest.id MATH_ENGINE %}
|
||||
{{ contest.description|markdown('contest', MATH_ENGINE)|reference|str|safe }}
|
||||
{% endcache %}
|
||||
</div>
|
||||
|
||||
{% if contest.ended or request.user.is_superuser or is_organizer %}
|
||||
<hr>
|
||||
<div class="contest-problems">
|
||||
<h2 style="margin-bottom: 0.2em"><i class="fa fa-fw fa-question-circle"></i>{{ _('Problems') }} </h2>
|
||||
<table id="contest-problems" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ _('Problem') }}</th>
|
||||
<th>{{ _('Points') }}</th>
|
||||
<th>{{ _('AC Rate') }}</th>
|
||||
<th>{{ _('Users') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for problem in contest_problems %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if problem.is_public %}
|
||||
<a href="{{ url('problem_detail', problem.code) }}">{{ problem.i18n_name }}</a>
|
||||
{% else %}
|
||||
{{ problem.i18n_name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ problem.points|floatformat }}{% if problem.partial %}p{% endif %}</td>
|
||||
<td>{{ problem.ac_rate|floatformat(1) }}%</td>
|
||||
<td>
|
||||
{% if problem.is_public %}
|
||||
<a href="{{ url('ranked_submissions', problem.code) }}">{{ problem.user_count }}</a>
|
||||
{% else %}
|
||||
{{ problem.user_count }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if problem.is_public and problem.has_public_editorial %}
|
||||
<a href="{{ url('problem_editorial', problem.code) }}">{{ _('Editorial') }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
<span class="social">
|
||||
{{ post_to_gplus(request, contest, '<i class="fa fa-google-plus-square"></i>') }}
|
||||
{{ post_to_facebook(request, contest, '<i class="fa fa-facebook-official"></i>') }}
|
||||
{{ post_to_twitter(request, SITE_NAME + ':', contest, '<i class="fa fa-twitter"></i>') }}
|
||||
</span>
|
||||
|
||||
{% include "comments/list.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block description_end %}{% endblock %}
|
||||
|
||||
{% block bodyend %}
|
||||
{{ super() }}
|
||||
{% include "comments/math.html" %}
|
||||
{% endblock %}
|
||||
k
|
307
templates/contest/list.html
Normal file
307
templates/contest/list.html
Normal file
|
@ -0,0 +1,307 @@
|
|||
{% extends "common-content.html" %}
|
||||
{% block meta %}
|
||||
<meta name="description" content="The {{ SITE_NAME }}'s contest list - past, present, and future.">
|
||||
{% endblock %}
|
||||
|
||||
{% block media %}
|
||||
<style>
|
||||
.time-left {
|
||||
text-align: left;
|
||||
color: #777;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
.content-description ul {
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_media %}
|
||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('.time-remaining').each(function () {
|
||||
count_down($(this));
|
||||
});
|
||||
|
||||
$('.contest-tag').find('a[data-featherlight]').featherlight();
|
||||
|
||||
$('.join-warning').click(function () {
|
||||
return confirm('{{ _('Are you sure you want to join?') }}\n' +
|
||||
'{{ _('Joining a contest for the first time starts your timer, after which it becomes unstoppable.') }}');
|
||||
});
|
||||
|
||||
// var tooltip_classes = 'tooltipped tooltipped-e';
|
||||
//
|
||||
// $('.contest-tag').each(function () {
|
||||
// var link = $(this);//
|
||||
// link.mouseenter(function (e) {
|
||||
// link.addClass(tooltip_classes).attr('aria-label', link.attr('data-description'));
|
||||
// }).mouseleave(function (e) {
|
||||
// link.removeClass(tooltip_classes).removeAttr('aria-label');
|
||||
// });
|
||||
// });
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title_ruler %}{% endblock %}
|
||||
|
||||
{% block title_row %}
|
||||
{% set tab = 'list' %}
|
||||
{% set title = 'Contests' %}
|
||||
{% include "contest/contest-list-tabs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% macro contest_head(contest) %}
|
||||
{% spaceless %}
|
||||
<a href="{{ url('contest_view', contest.key) }}" class="contest-list-title">
|
||||
{{- contest.name -}}
|
||||
</a>
|
||||
<span class="contest-tags">
|
||||
{% if not contest.is_visible %}
|
||||
<span style="background-color: #000000; color: #ffffff" class="contest-tag">
|
||||
<i class="fa fa-eye-slash"></i> {{ _('hidden') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if contest.is_private %}
|
||||
<span style="background-color: #666666; color: #ffffff" class="contest-tag">
|
||||
<i class="fa fa-lock"></i> {{ _('private') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if contest.is_organization_private %}
|
||||
{% for org in contest.organizations.all() %}
|
||||
<span style="background-color: #cccccc" class="contest-tag">
|
||||
<a href="{{ org.get_absolute_url() }}" style="color: #000000">
|
||||
<i class="fa fa-lock"></i> {{ org.name }}
|
||||
</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if contest.is_rated %}
|
||||
<span style="background-color: #e54c14; color: #ffffff" class="contest-tag">
|
||||
<i class="fa fa-bar-chart"></i> {{ _('rated') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% for tag in contest.tags.all() %}
|
||||
<span style="background-color: {{ tag.color }}" class="contest-tag">
|
||||
<a href="{{ url('contest_tag', tag.name) }}"
|
||||
style="color: {{ tag.text_color }}"
|
||||
data-featherlight="{{ url('contest_tag_ajax', tag.name) }}">
|
||||
{{- tag.name -}}
|
||||
</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</span>
|
||||
{% endspaceless %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro time_left(contest) %}
|
||||
<div class="time time-left">
|
||||
{% if contest.time_limit %}
|
||||
{{ contest.start_time|date(_("M j, Y, G:i")) }} -
|
||||
{{ contest.end_time|date(_("M j, Y, G:i")) }}
|
||||
{% else %}
|
||||
{{ contest.start_time|date(_("M j, Y, G:i")) }}
|
||||
{% endif %}
|
||||
<br>
|
||||
{% if contest.time_limit %}
|
||||
{{ _('%(time_limit)s window', time_limit=contest.time_limit|timedelta('localized-no-seconds')) }}
|
||||
{% else %}
|
||||
{{ _('%(duration)s long', duration=contest.contest_window_length|timedelta('localized-no-seconds')) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro user_count(contest, user) %}
|
||||
{% if contest.show_scoreboard or contest.can_see_scoreboard(user) %}
|
||||
<a href="{{ url('contest_ranking', contest.key) }}">{{ contest.user_count }}</a>
|
||||
{% else %}
|
||||
{{ contest.user_count }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro contest_join(contest, request) %}
|
||||
{% if not request.in_contest %}
|
||||
<td>
|
||||
{% if request.profile in contest.organizers.all() %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full participate-button"
|
||||
value="{{ _('Spectate') }}">
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full participate-button join-warning"
|
||||
value="{{ _('Join') }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block body %}
|
||||
<div class="content-description">
|
||||
{% if active_participations %}
|
||||
<h4>{{ _('Active Contests') }}</h4>
|
||||
<table class="contest-list table striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:90%">{{ _('Contest') }}</th>
|
||||
<th>{{ _('Users') }}</th>
|
||||
{% if not request.in_contest %}
|
||||
<th style="width:15%"></th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for participation in active_participations %}
|
||||
{% with contest=participation.contest %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="contest-block">
|
||||
{{ contest_head(contest) }}
|
||||
{% if contest.start_time %}
|
||||
<br>
|
||||
{% if contest.time_limit %}
|
||||
<span class="time">{{ _('Window ends in %(countdown)s', countdown=participation.time_remaining|as_countdown)}}
|
||||
{% elif contest.time_before_end %}
|
||||
<span class="time">{{ _('Ends in %(countdown)s', countdown=contest.time_before_end|as_countdown) }}</span>
|
||||
{% endif %}
|
||||
{{ time_left(contest) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ user_count(contest, request.user) }}
|
||||
</td>
|
||||
{{ contest_join(contest, request) }}
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
{% endif %}
|
||||
|
||||
{% if current_contests %}
|
||||
<h4>{{ _('Ongoing Contests') }}</h4>
|
||||
<table class="contest-list table striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:90%">{{ _('Contest') }}</th>
|
||||
<th>{{ _('Users') }}</th>
|
||||
{% if not request.in_contest %}
|
||||
<th style="width:15%"></th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for contest in current_contests %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="contest-block">
|
||||
{{ contest_head(contest) }}
|
||||
{% if contest.start_time %}
|
||||
<br>
|
||||
{% if contest.time_before_end %}
|
||||
<span class="time">{{ _('Ends in %(countdown)s', countdown=contest.time_before_end|as_countdown) }}</span>
|
||||
{% endif %}
|
||||
{{ time_left(contest) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ user_count(contest, request.user) }}
|
||||
</td>
|
||||
{{ contest_join(contest, request) }}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
{% endif %}
|
||||
|
||||
<h4>{{ _('Upcoming Contests') }}</h4>
|
||||
{% if future_contests %}
|
||||
<table class="contest-list table striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ _('Contest') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for contest in future_contests %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="contest-block">
|
||||
{{ contest_head(contest) }}
|
||||
{% if contest.start_time %}
|
||||
<br>
|
||||
{% if contest.time_before_start %}
|
||||
<span class="time">{{ _('Starting in %(countdown)s.', countdown=contest.time_before_start|as_countdown) }}</span>
|
||||
{% endif %}
|
||||
{{ time_left(contest) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<i>{{ _('There are no scheduled contests at this time.') }}</i>
|
||||
<br>
|
||||
{% endif %}
|
||||
<br>
|
||||
|
||||
{% if past_contests %}
|
||||
<h4>{{ _('Past Contests') }}</h4>
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
<div style="margin-bottom: 4px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<table class="contest-list table striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:90%">{{ _('Contest') }}</th>
|
||||
<th>{{ _('Users') }}</th>
|
||||
{% if not request.in_contest %}
|
||||
<th style="width:15%"></th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for contest in past_contests %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="contest-block">
|
||||
{{ contest_head(contest) }}
|
||||
{{ time_left(contest) }}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ user_count(contest, request.user) }}
|
||||
</td>
|
||||
{% if not request.in_contest %}
|
||||
<td><form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full participate-button"
|
||||
value="{{ _('Virtual join') }}">
|
||||
</form></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
<div style="margin-top: 10px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
13
templates/contest/media-js.html
Normal file
13
templates/contest/media-js.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('.leaving-forever').click(function () {
|
||||
return confirm('{{ _('Are you sure you want to leave?') }}\n' +
|
||||
'{{ _('You cannot come back to a virtual participation. You will have to start a new one.') }}');
|
||||
});
|
||||
|
||||
$('.first-join').click(function () {
|
||||
return confirm('{{ _('Are you sure you want to join?') }}\n' +
|
||||
'{{ _('Joining a contest starts your timer, after which it becomes unstoppable.') }}');
|
||||
});
|
||||
});
|
||||
</script>
|
87
templates/contest/moss.html
Normal file
87
templates/contest/moss.html
Normal file
|
@ -0,0 +1,87 @@
|
|||
{% extends "common-content.html" %}
|
||||
|
||||
{% block title_ruler %}{% endblock %}
|
||||
|
||||
{% block title_row %}
|
||||
{% set tab = 'moss' %}
|
||||
{% set title = contest.name %}
|
||||
{% include "contest/contest-tabs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content_media %}
|
||||
<style>
|
||||
.panes {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
.pane {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_js_media %}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('.contest-moss').click(function () {
|
||||
return confirm('{{ _('Are you sure you want MOSS the contest?') }}');
|
||||
});
|
||||
});
|
||||
$(function () {
|
||||
$('.contest-moss-delete').click(function () {
|
||||
return confirm('{{ _('Are you sure you want to delete the MOSS results?') }}');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
{% if has_results %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="header">{{ _('Problem') }}</th>
|
||||
{% for lang in languages %}
|
||||
<th class="header">{{ lang }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for problem, results in moss_results %}
|
||||
<tr id="problem-{{ problem.code }}">
|
||||
<td>
|
||||
<a href="{{ url('problem_detail', problem.code) }}">{{ problem.name }}</a>
|
||||
</td>
|
||||
{% for result in results %}
|
||||
<td>
|
||||
{% if result.submission_count %}
|
||||
<a href="{{ result.url }}">{{ result.submission_count }} {{_('submissions')}}</a>
|
||||
{% else %}
|
||||
{{ _('No submissions') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<div class="panes">
|
||||
<div class="pane">
|
||||
<form method="post" action="{{ url('contest_moss', contest.key) }}">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full contest-moss" style="padding: 10px;"
|
||||
value="{% if has_results %} {{ _('Re-MOSS contest') }} {% else %} {{ _('MOSS contest') }} {% endif %}">
|
||||
</form>
|
||||
</div>
|
||||
{% if has_results %}
|
||||
<div class="pane">
|
||||
<form method="post" action="{{ url('contest_moss_delete', contest.key) }}">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full contest-moss-delete" style="padding: 10px;"
|
||||
value="{{ _('Delete MOSS results') }}">
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
4
templates/contest/preview.html
Normal file
4
templates/contest/preview.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
{{ preview_data|markdown('contest', MATH_ENGINE)|reference|str|safe }}
|
||||
{% if REQUIRE_JAX %}
|
||||
<div data-config="{{ static('mathjax_config.js') }}" class="require-mathjax-support"></div>
|
||||
{% endif %}
|
20
templates/contest/private.html
Normal file
20
templates/contest/private.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
{% if error.is_private %}
|
||||
<p><i>{{ _('This contest is private to specific users.') }}</i></p>
|
||||
{% endif %}
|
||||
|
||||
{% if error.is_organization_private %}
|
||||
{% if error.is_private %}
|
||||
<p>{{ _('Additionally, only the following organizations may access this contest:') }}</p>
|
||||
{% else %}
|
||||
<p>{{ _('Only the following organizations may access this contest:') }}</p>
|
||||
{% endif %}
|
||||
<ul>
|
||||
{% for org in error.orgs %}
|
||||
<li><a href="{{ org.get_absolute_url() }}">{{ org.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
68
templates/contest/ranking-table.html
Normal file
68
templates/contest/ranking-table.html
Normal file
|
@ -0,0 +1,68 @@
|
|||
{% extends "user/base-users-table.html" %}
|
||||
|
||||
{% block after_rank_head %}
|
||||
{% if has_rating %}
|
||||
<th>{{ _('Rating') }}</th>
|
||||
{% endif %}
|
||||
<th class="organization-column">{{ _('Organization') }}</th>
|
||||
{% endblock %}
|
||||
|
||||
{% block after_rank %}
|
||||
{% if has_rating %}
|
||||
<td>{% if user.participation_rating %}{{ rating_number(user.participation_rating) }}{% endif %}</td>
|
||||
{% endif %}
|
||||
<td class="organization-column">
|
||||
{% if user.organization %}
|
||||
<span class="organization"><a href="{{ user.organization.get_absolute_url() }}">
|
||||
{{- user.organization.short_name -}}
|
||||
</a></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endblock %}
|
||||
|
||||
{% block user_data %}
|
||||
{% if is_organizer %}
|
||||
<span class="contest-participation-operation">
|
||||
<form action="{{ url('contest_participation_disqualify', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="participation" value="{{ user.participation.id }}">
|
||||
{% if user.participation.is_disqualified %}
|
||||
<a href="#" title="{{ _('Un-Disqualify') }}"
|
||||
class="un-disqualify-participation"><i class="fa fa-undo fa-fw"></i></a>
|
||||
{% else %}
|
||||
<a href="#" title="{{ _('Disqualify') }}"
|
||||
class="disqualify-participation"><i class="fa fa-trash fa-fw"></i></a>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if perms.judge.change_contestparticipation %}
|
||||
<a href="{{ url('admin:judge_contestparticipation_change', user.participation.id) }}"
|
||||
title="{{ _('Admin') }}" class="edit-participation"><i class="fa fa-cog fa-fw"></i></a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block before_point_head %}
|
||||
{% for problem in problems %}
|
||||
<th class="points header"><a href="{{ url('contest_ranked_submissions', contest.key, problem.problem.code) }}">
|
||||
{{- loop.index }}
|
||||
<div class="point-denominator">{{ problem.points }}</div>
|
||||
</a></th>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block row_extra %}
|
||||
{% if user.participation.is_disqualified %}
|
||||
class="disqualified"
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block before_point %}
|
||||
{% for cell in user.problem_cells %}
|
||||
{{ cell }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block point %}
|
||||
{{ user.result_cell }}
|
||||
{% endblock %}
|
259
templates/contest/ranking.html
Normal file
259
templates/contest/ranking.html
Normal file
|
@ -0,0 +1,259 @@
|
|||
{% 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;
|
||||
}
|
||||
|
||||
.rank {
|
||||
min-width: 2.5em
|
||||
}
|
||||
|
||||
.points {
|
||||
min-width: 4em;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
</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 is_organizer %}
|
||||
<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">
|
||||
$(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();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% include "contest/media-js.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block users_table %}
|
||||
<div style="margin-bottom: 0.5em">
|
||||
{% if tab == 'participation' %}
|
||||
{% if contest.start_time <= now or perms.judge.see_private_contest %}
|
||||
<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">{{ _('Show organizations') }}</label>
|
||||
</div>
|
||||
{% include "contest/ranking-table.html" %}
|
||||
{% endblock %}
|
58
templates/contest/stats.html
Normal file
58
templates/contest/stats.html
Normal file
|
@ -0,0 +1,58 @@
|
|||
{% extends "common-content.html" %}
|
||||
|
||||
{% block title_ruler %}{% endblock %}
|
||||
|
||||
{% block title_row %}
|
||||
{% set tab = 'stats' %}
|
||||
{% set title = contest.name %}
|
||||
{% include "contest/contest-tabs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content_js_media %}
|
||||
<script type="text/javascript">
|
||||
window.stats = {{ stats }};
|
||||
</script>
|
||||
{% compress js %}
|
||||
{% include "stats/media-js.html" %}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
draw_stacked_bar_chart(window.stats.problem_status_count, $('#problem-status-count'));
|
||||
draw_bar_chart(window.stats.problem_ac_rate, $('#problem-ac-rate'));
|
||||
draw_pie_chart(window.stats.language_count, $('#language-count'));
|
||||
draw_bar_chart(window.stats.language_ac_rate, $('#language-ac-rate'));
|
||||
});
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% include "contest/media-js.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content_media %}
|
||||
<style>
|
||||
.chart {
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h3>{{ _('Problem Status Distribution') }}</h3>
|
||||
<div id="problem-status-count" class="chart">
|
||||
<canvas></canvas>
|
||||
</div>
|
||||
|
||||
<h3>{{ _('Problem AC Rate') }}</h3>
|
||||
<div id="problem-ac-rate" class="chart">
|
||||
<canvas></canvas>
|
||||
</div>
|
||||
|
||||
<h3>{{ _('Submissions by Language') }}</h3>
|
||||
<div id="language-count" class="chart">
|
||||
<canvas width="400" height="300"></canvas>
|
||||
<ul class="legend"></ul>
|
||||
</div>
|
||||
|
||||
<h3>{{ _('Language AC Rate') }}</h3>
|
||||
<div id="language-ac-rate" class="chart">
|
||||
<canvas></canvas>
|
||||
</div>
|
||||
{% endblock %}
|
7
templates/contest/tag-ajax.html
Normal file
7
templates/contest/tag-ajax.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
{% if not title %}
|
||||
{% include "contest/tag-title.html" %}
|
||||
<br><br>
|
||||
<hr>
|
||||
{% endif %}
|
||||
|
||||
{{ tag.description|markdown('contest_tag') }}
|
11
templates/contest/tag-title.html
Normal file
11
templates/contest/tag-title.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<h2 style="display:inline">
|
||||
<span style="background-color: {{ tag.color }}; color: {{ tag.text_color }}" class="contest-tag">
|
||||
{{- tag.name -}}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
{% if perms.judge.change_contesttag %}
|
||||
<div class="title-line-action">
|
||||
[<a href="{{ url('admin:judge_contesttag_change', tag.id) }}">{{ _('Edit') }}</a>]
|
||||
</div>
|
||||
{% endif %}
|
9
templates/contest/tag.html
Normal file
9
templates/contest/tag.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content_title %}
|
||||
{% include "contest/tag-title.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{% include "contest/tag-ajax.html" %}
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue