Cloned DMOJ

This commit is contained in:
thanhluong 2020-01-21 15:35:58 +09:00
parent f623974b58
commit 49dc9ff10c
513 changed files with 132349 additions and 39 deletions

View file

@ -0,0 +1,20 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block extrahead %}{{ block.super }}
<script>
django.jQuery(function ($) {
$('.profilelink').appendTo('div#bottombar').show();
});
</script>
{% endblock extrahead %}
{% block after_field_sets %}{{ block.super }}
{% if original %}
<a style="display: none" title="{% trans "Edit profile" %}" href="{% url 'admin:judge_profile_change' original.profile.pk %}"
class="button profilelink">
<i class="fa fa-lg fa-user-plus"></i>
<span class="text">{% trans "Edit profile" %}</span>
</a>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,23 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block extrahead %}{{ block.super }}
<script>
django.jQuery(function ($) {
$('.rerate-link').appendTo('div#bottombar').show();
$('.rejudge-link').click(function () {
return confirm('{{ _('Are you sure you want to rejudge ALL the submissions?') }}');
});
});
</script>
{% endblock extrahead %}
{% block after_field_sets %}{{ block.super }}
{% if original and original.is_rated and perms.judge.contest_rating %}
<a style="display: none" title="{% trans "Rate" %}" href="{% url 'admin:judge_contest_rate' original.pk %}"
class="button rerate-link">
<i class="fa fa-lg fa-signal"></i>
<span class="text">{% trans "Rate" %}</span>
</a>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends "reversion/change_list.html" %}
{% load i18n %}
{% block object-tools-items %}
{{ block.super }}
{% if not is_popup and perms.judge.contest_rating %}
<li>
<a href="{% url 'admin:judge_contest_rate_all' %}" class="ratealllink">
<i class="fa fa-signal"></i> {% trans "Rate all ratable contests" %}
</a>
</li>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,26 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block extrahead %}{{ block.super }}
<script>
django.jQuery(function ($) {
$('.disconnect-link').appendTo('div#bottombar').show();
$('.terminate-link').appendTo('div#bottombar').show();
});
</script>
{% endblock extrahead %}
{% block after_field_sets %}{{ block.super }}
{% if original %}
<a style="display: none" title="{% trans "Disconnect" %}" href="{% url 'admin:judge_judge_disconnect' original.pk %}"
class="button disconnect-link">
<i class="fa fa-lg fa-power-off"></i>
<span class="text">{% trans "Disconnect" %}</span>
</a>
<a style="display: none" title="{% trans "Terminate" %}" href="{% url 'admin:judge_judge_terminate' original.pk %}"
class="button terminate-link">
<i class="fa fa-lg fa-plug"></i>
<span class="text">{% trans "Terminate" %}</span>
</a>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,20 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block extrahead %}{{ block.super }}
<script>
django.jQuery(function ($) {
$('.submissions-link').appendTo('div#bottombar').show();
});
</script>
{% endblock extrahead %}
{% block after_field_sets %}{{ block.super }}
{% if original %}
<a style="display: none" title="{% trans "View Submissions" %}" class="button submissions-link"
href="{% url 'admin:judge_submission_changelist' %}?problem__code={{ original.code }}">
<i class="fa fa-lg fa-search-plus"></i>
<span class="text">{% trans "View submissions" %}</span>
</a>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,20 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block extrahead %}{{ block.super }}
<script>
django.jQuery(function ($) {
$('.userlink').appendTo('div#bottombar').show();
});
</script>
{% endblock extrahead %}
{% block after_field_sets %}{{ block.super }}
{% if original %}
<a style="display: none" title="{% trans "Edit user" %}" href="{% url 'admin:auth_user_change' original.user.pk %}"
class="button userlink">
<i class="fa fa-lg fa-user"></i>
<span class="text">{% trans "Edit user" %}</span>
</a>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,20 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block extrahead %}{{ block.super }}
<script>
django.jQuery(function ($) {
$('.rejudgelink').appendTo('div#bottombar').show();
});
</script>
{% endblock extrahead %}
{% block after_field_sets %}{{ block.super }}
{% if original %}
<a style="display: none" title="{% trans "Rejudge" %}" href="{% url 'admin:judge_submission_rejudge' original.pk %}"
class="button rejudgelink">
<i class="fa fa-lg fa-refresh"></i>
<span class="text">{% trans "Rejudge" %}</span>
</a>
{% endif %}
{% endblock %}

313
templates/base.html Normal file
View file

@ -0,0 +1,313 @@
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE }}">
<head>
<title>{% block title %}{{ title }} - {{ SITE_LONG_NAME }}{% endblock %}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
{% if misc_config.meta_keywords %}
<meta name="keywords" content="{{ misc_config.meta_keywords }}">
{% endif %}
{% if meta_description %}
<meta name="description" content="{{ meta_description }}">
{% endif %}
<meta id="viewport" name="viewport" content="width=device-width, initial-scale=1">
<!-- Favicons-->
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#FFBB33">
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
{# Chrome 39 for Android colour #}
<meta name="theme-color" content="#FFBB33">
{% if og_image %}
<meta property="og:image" content="{{ request.build_absolute_uri(og_image) }}">
{% endif %}
{% block og_title %}{% endblock %}
<meta property="og:site_name" content="{{ SITE_LONG_NAME }}">
<meta property="og:url"
content="{{ DMOJ_SCHEME }}://{{ DMOJ_CANONICAL|default(site.domain) }}{{ request.get_full_path() }}">
{% if meta_description %}
<meta property="og:description" content="{{ meta_description }}">
{% endif %}
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script>window.bad_browser = true</script>
<![endif]-->
{% block meta %}{% endblock %}
{% if not INLINE_FONTAWESOME %}
<link rel="stylesheet" href="{{ FONTAWESOME_CSS }}">
{% endif %}
{% compress css %}
<link rel="stylesheet" href="{{ static('style.css') }}">
{% if PYGMENT_THEME %}
<link rel="stylesheet" href="{{ static(PYGMENT_THEME) }}">
{% endif %}{% if INLINE_FONTAWESOME %}
<link rel="stylesheet" href="{{ static('libs/fontawesome/font-awesome.css') }}">{% endif %}
<link rel="stylesheet" type="text/css" href="{{ static('libs/featherlight/featherlight.min.css') }}">
<link rel="stylesheet" type="text/css" href="{{ static('libs/clipboard/tooltip.css') }}">
<link rel="stylesheet" type="text/css" href="{{ static('libs/select2/select2.css') }}">
{% endcompress %}
<link rel="canonical"
href="{{ DMOJ_SCHEME }}://{{ DMOJ_CANONICAL|default(site.domain) }}{{ request.get_full_path() }}">
{% if request.user.is_impersonate %}
<style>
#nav-container {
background: #893e89 !important;
}
</style>
{% endif %}
{% block media %}{% endblock %}
{% if not INLINE_JQUERY %}
<script src="{{ JQUERY_JS }}"></script>
{% endif %}
{% compress js %}
<script>{{ inlinei18n(LANGUAGE_CODE)|safe }}</script>
{% if INLINE_JQUERY %}
<script src="{{ static('libs/jquery-3.4.1.min.js') }}"></script>
{% endif %}
<script src="{{ static('libs/jquery-cookie.js') }}"></script>
<script src="{{ static('libs/jquery-taphold.js') }}"></script>
<script src="{{ static('libs/jquery.unveil.js') }}"></script>
<script src="{{ static('libs/moment.js') }}"></script>
<script src="{{ static('libs/select2/select2.js') }}"></script>
{% include "extra_js.html" %}
<script src="{{ static('common.js') }}"></script>
<script>
moment.locale('{{ LANGUAGE_CODE }}');
$(function () {
$('img.unveil').unveil(200);
});
</script>
{% endcompress %}
{% block js_media %}{% endblock %}
{% if request.in_contest %}
<script>$(function () {
count_down($("#contest-time-remaining"));
var selected = null,
x_pos = 0, y_pos = 0,
x_elem = 0, y_elem = 0;
$('#contest-info').mousedown(function () {
selected = $(this);
x_elem = x_pos - selected.offset().left;
y_elem = y_pos - (selected.offset().top - $(window).scrollTop());
return false;
});
if (localStorage.getItem("contest_timer_pos")) {
data = localStorage.getItem("contest_timer_pos").split(":");
$("#contest-info").css({
left: data[0],
top: data[1]
});
}
$("#contest-info").show();
$(document).mousemove(function (e) {
x_pos = e.screenX;
y_pos = e.screenY;
x_pos = Math.max(Math.min(x_pos, window.innerWidth), 0);
y_pos = Math.max(Math.min(y_pos, window.innerHeight), 0);
if (selected !== null) {
left_px = (x_pos - x_elem) + 'px';
top_px = (y_pos - y_elem) + 'px';
localStorage.setItem("contest_timer_pos", left_px + ":" + top_px);
selected.css({
left: left_px,
top: top_px
});
}
});
$(document).mouseup(function () {
selected = null;
})
});
</script>
{% endif %}
{% if request.user.is_authenticated %}
<script>
window.user = {
email: '{{ request.user.email|escapejs }}',
id: '{{ request.user.id|escapejs }}',
name: '{{ request.user.username|escapejs }}'
};
</script>
{% else %}
<script>window.user = {};</script>
{% endif %}
{% if misc_config.analytics %}
{{ misc_config.analytics|safe }}
{% endif %}
{# Don't run userscript since it may be malicious #}
{% if request.user.is_authenticated and request.profile.user_script and not request.user.is_impersonate %}
<script type="text/javascript">{{ request.profile.user_script|safe }}</script>
{% endif %}
<noscript>
<style>
#content {
margin: 80px auto auto;
}
#navigation {
top: 27px;
}
</style>
</noscript>
</head>
<body>
<svg width="0" height="0" style="display: block">
<defs>
<clipPath id="rating-clip"><circle cx="8" cy="8" r="7"/></clipPath>
</defs>
</svg>
<nav id="navigation" class="unselectable">
<div id="nav-container">
<a id="navicon" href="javascript:void(0)"><i class="fa fa-bars"></i></a>
<ul id="nav-list">
<li class="home-nav-element"><a href="{{ url('home') }}">{% include "site-logo-fragment.html" %}</a></li>
<li class="home-nav-element"><span class="nav-divider"></span></li>
<li class="home-menu-item"><a href="{{ url('home') }}" class="nav-home">{{ _('Home') }}</a></li>
{% for node in mptt_tree(nav_bar) recursive %}
<li>
<a href="{{ node.path }}" class="nav-{{ node.key }}{% if node.key in nav_tab %} active{% endif %}">
{{ user_trans(node.label) }}
{% if not node.is_leaf_node %}
<div href="javascript:void(0)" class="nav-expand">></div>
{% endif %}
</a>
{% with children=node.get_children() %}
{% if children %}<ul>{{ loop(children) }}</ul>{% endif %}
{% endwith %}
</li>
{% endfor %}
</ul>
<span id="user-links">
{% if request.user.is_authenticated %}
<ul>
<li>
<a href="{{ url('user_page') }}">
<span>
<img src="{{ gravatar(request.user, 32) }}" height="24" width="24">{# -#}
<span>
{%- trans username=request.user.username -%}
Hello, <b>{{ username }}</b>.
{%- endtrans %}
</span>
</span>
</a>
<ul style="width: 150px">
{% if request.user.is_staff or request.user.is_superuser %}
<li><a href="{{ url('admin:index') }}">{{ _('Admin') }}</a></li>
{% endif %}
<li><a href="{{ url('user_edit_profile') }}">{{ _('Edit profile') }}</a></li>
{% if request.user.is_impersonate %}
<li><a href="{{ url('impersonate-stop') }}">Stop impersonating</a></li>
{% else %}
<li>
<form action="{{ url('auth_logout') }}" method="POST">
{% csrf_token %}
<button type="submit">{{ _('Log out') }}</button>
</form>
</li>
{% endif %}
</ul>
</li>
</ul>
{% else %}
<span class="anon">
<a href="{{ url('auth_login') }}?next={{ LOGIN_RETURN_PATH|urlencode }}"><b>{{ _('Log in') }}</b></a>
&nbsp;{{ _('or') }}&nbsp;
<a href="{{ url('registration_register') }}"><b>{{ _('Sign up') }}</b></a>
</span>
{% endif %}
</span>
</div>
<div id="nav-shadow"></div>
</nav>
{% if request.in_contest %}
<div id="contest-info">
<a href="{{ url('contest_view', request.participation.contest.key) }}" style="vertical-align: middle">
{{ request.participation.contest.name }} -
{% if request.participation.spectate %}
{{ _('spectating') }}
{% elif request.participation.end_time %}
<div id="contest-time-remaining" data-secs="{{ request.participation.time_remaining|seconds }}">
{{ request.participation.time_remaining|timedelta("localized") }}
</div>
{% else %}
{{ _('virtual') }}
{% endif %}
</a>
</div>
{% endif %}
<div id="page-container">
<noscript>
<div id="noscript">{{ _('This site works best with JavaScript enabled.') }}</div>
</noscript>
<br>
<main id="content">
{% block title_row %}
<h2 style="color:#393630; display:inline">
{% block content_title %}
{% if content_title %}{{ content_title }}{% else %}{{ title }}{% endif %}
{% endblock %}
</h2>
{% endblock %}
{% block header %}{% endblock %}
{% block title_ruler %}
<hr>
{% endblock %}
<div id="content-body">{% block body %}{% endblock %}</div>
</main>
{% if i18n_config.announcement %}
<div id="announcement">{{ i18n_config.announcement|safe }}</div>
{% endif %}
{% block bodyend %}{% endblock %}
<footer>
<span id="footer-content">
<br>
<a style="color: #808080" href="https://dmoj.ca">proudly powered by <b>DMOJ</b></a> |
{% if i18n_config.footer %}
{{ i18n_config.footer|safe }} |
{% endif %}
<form action="{{ url('set_language') }}" method="post" style="display: inline">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path() }}">
<select name="language" onchange="form.submit()" style="height: 1.5em">
{% for language in language_info_list(LANGUAGES) %}
<option value="{{ language.code }}" {% if language.code == LANGUAGE_CODE %}selected{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
</form>
</span>
</footer>
</div>
</body>
</html>

View file

@ -0,0 +1,53 @@
{% extends "base.html" %}
{% block js_media %}
{% include "comments/media-js.html" %}
{% endblock %}
{% block media %}
{% include "comments/media-css.html" %}
{% endblock %}
{% block header %}
{% if perms.judge.change_blogpost %}
<div class="title-line-action">[<a href="{{ url('admin:judge_blogpost_change', post.id) }}">{{ _('Edit') }}</a>]
</div>
{% endif %}
{% endblock %}
{% block body %}
<div class="post-full">
<div class="time">
{% with authors=post.authors.all() %}
{% if authors %}
<span class="post-authors">{{ link_users(authors) }}</span>
{% endif %}
{% endwith %}
<span class="post-time">
{% trans time=post.publish_on|date(_("N j, Y, g:i a")) %}
posted on {{ time }}
{% endtrans %}
</span>
</div>
<div class="body content-description">
{% cache 86400 'post_content' post.id MATH_ENGINE %}
{{ post.content|markdown('blog', MATH_ENGINE)|reference|str|safe}}
{% endcache %}
</div>
</div>
<hr>
<span class="social">
{{ post_to_gplus(request, post, '<i class="fa fa-google-plus-square"></i>') }}
{{ post_to_facebook(request, post, '<i class="fa fa-facebook-official"></i>') }}
{{ post_to_twitter(request, SITE_NAME + ':', post, '<i class="fa fa-twitter"></i>') }}
</span>
{% include "comments/list.html" %}
{% endblock %}
{% block bodyend %}
{{ super() }}
{% if REQUIRE_JAX %}
{% include "mathjax-load.html" %}
{% endif %}
{% include "comments/math.html" %}
{% endblock %}

View file

@ -0,0 +1,34 @@
<div class="sidebox dashboard">
<h3>Dashboard <i class="fa fa-dashboard"></i>
</h3>
<div class="sidebox-content">
<div class="user-gravatar">
<img src="{{ gravatar(request.user, 135) }}"
alt="gravatar" width="135px" height="135px">
</div>
<div class="recently-attempted">
<h4>Recently attempted problems</h4>
<ul>
{% for code, name, problem_points, user_points, s_date in recently_attempted_problems %}
<li>
<a href="{{ url('problem_detail', code) }}">{{ name }}</a>
[<a href="{{ url('user_submissions', code, request.user.username }}">
{{- user_points }}/{{ problem_points|floatformat }}</a>]
<span class="time">
<span data-unix="{{ submission.date|utc|date("c") }}"
class="recent-time moment-time-toggle">
{% trans time=submission.date|date(_("N j, Y, g:i a")) %}
on {{ time }}
{% endtrans %}
</span>
</span>
</li>
{% endfor %}
</ul>
</div>
<div class="recommended-problems">
<h4>Recommended problems</h4><i>Coming soon.</i>
</div>
</div>
</div>

268
templates/blog/list.html Normal file
View file

@ -0,0 +1,268 @@
{% extends "base.html" %}
{% block title_row %}{% endblock %}
{% block title_ruler %}{% endblock %}
{% block media %}
<link rel="alternate" type="application/atom+xml" href="{{ url('blog_atom') }}" title="Atom Blog Feed">
<link rel="alternate" type="application/rss+xml" href="{{ url('blog_rss') }}" title="RSS Blog Feed">
<link rel="alternate" type="application/atom+xml" href="{{ url('comment_atom') }}" title="Atom Comment Feed">
<link rel="alternate" type="application/rss+xml" href="{{ url('comment_rss') }}" title="RSS Comment Feed">
<link rel="alternate" type="application/atom+xml" href="{{ url('problem_atom') }}" title="Atom Problem Feed">
<link rel="alternate" type="application/rss+xml" href="{{ url('problem_rss') }}" title="RSS Problem Feed">
{% include "blog/media-css.html" %}
<style>
.post {
margin: 0 1.4em;
}
.post:first-child {
margin-top: 0.6em;
}
.comment-count {
font-size: 12px;
}
.comment-icon {
padding: 0.1em 0.2em 0 0.5em;
}
.comment-count-link {
color: #555;
}
.own-open-tickets .title a, .open-tickets .title a {
display: block;
}
.own-open-tickets .object, .open-tickets .object {
margin-left: 1em;
font-style: italic;
}
.open-tickets .user {
margin-left: 1em;
}
.no-clarifications-message {
font-style: italic;
text-align: center;
}
</style>
{% endblock %}
{% block js_media %}
<script type="text/javascript">
$(document).ready(function () {
$('.time-remaining').each(function () {
count_down($(this));
});
$('.blog-sidebar').hide();
$('#blog-tab').find('a').click(function (e) {
e.preventDefault();
$('#blog-tab').addClass('active');
$('#event-tab').removeClass('active');
$('.blog-content').show();
$('.blog-sidebar').hide();
});
$('#event-tab').find('a').click(function (e) {
e.preventDefault();
$('#event-tab').addClass('active');
$('#blog-tab').removeClass('active');
$('.blog-content').hide();
$('.blog-sidebar').show();
});
});
</script>
{% endblock %}
{% block body %}
{% block before_posts %}{% endblock %}
<div id="mobile" class="tabs">
<ul>
<li id="blog-tab" class="tab active"><a href="#">
<i class="tab-icon fa fa-info-circle"></i> {{ _('Blog') }}
</a></li>
<li id="event-tab" class="tab"><a href="#"><i class="tab-icon fa fa-rss"></i> {{ _('Events') }}</a></li>
</ul>
</div>
<div id="blog-container">
<div class="blog-content sidebox">
<h3>{{ _('News') }} <i class="fa fa-terminal"></i></h3>
<div class="sidebox-content">
{% for post in posts %}
<section class="{% if post.sticky %}sticky {% endif %}post">
<h2 class="title">
<a href="{{ url('blog_post', post.id, post.slug) }}">{{ post.title }}</a>
</h2>
<span class="time">
{%- if post.sticky %}<i title="Sticky" class="fa fa-star fa-fw"></i>{% endif -%}
{% with authors=post.authors.all() %}
{%- if authors -%}
<span class="post-authors">{{ link_users(authors) }}</span>
{%- endif -%}
{% endwith %}
{{ relative_time(post.publish_on, abs=_('posted on {time}'), rel=_('posted {time}')) -}}
</span><span class="comment-data">
<a href="{{ url('blog_post', post.id, post.slug) }}#comments" class="comment-count-link">
<i class="fa fa-comments comment-icon"></i><span class="comment-count">
{{- post_comment_counts[post.id] or 0 -}}
</span>
</a>
</span>
<div class="summary content-description">
{% cache 86400 'post_summary' post.id %}
{{ post.summary|default(post.content, true)|markdown('blog', 'svg', lazy_load=True)|reference|str|safe }}
{% endcache %}
</div>
</section>
{% endfor %}
</div>
{% if page_obj.num_pages > 1 %}
<div style="margin-bottom:10px;margin-top:10px">{% include "list-pages.html" %}</div>
{% endif %}
</div>
<div class="blog-sidebar">
{% if request.in_contest and request.participation.contest.use_clarifications %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Clarifications') }} <i class="fa fa-question-circle"></i></h3>
<div class="sidebox-content">
{% if has_clarifications %}
<ul>
{% for clarification in clarifications %}
<li class="clarification">
<a href="{{ url('problem_detail', clarification.problem.code) }}"
class="problem">
{{ clarification.problem.name }}
</a>
<span class="time">{{ relative_time(clarification.date) }}</span>
</li>
{% endfor %}
</ul>
{% else %}
<p class="no-clarifications-message">
{{ _('No clarifications have been made at this time.') }}
</p>
{% endif %}
</div>
</div>
{% endif %}
{% if current_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Ongoing contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in current_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Ends in %(countdown)s.', countdown=contest.time_before_end|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if future_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Upcoming contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in future_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Starting in %(countdown)s.', countdown=contest.time_before_start|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Comment stream') }} <i class="fa fa-comments"></i></h3>
<div class="sidebox-content">
<ul>
{% for comment in comments %}
<li>
<span style="padding-left:0.25em" class="poster">
{{ link_user(comment.author) }}
</span> &rarr;
<a href="{{ comment.link }}#comment-{{ comment.id }}">{{ page_titles[comment.page] }}</a>
</li>{% endfor %}
</ul>
<span class="rssatom">
<a href="{{ url('comment_rss') }}"><span><i class="fa fa-rss"></i></span> RSS</a>
/
<a href="{{ url('comment_atom') }}">Atom</a>
</span>
</div>
</div>
<div class="blog-sidebox sidebox">
<h3>{{ _('New problems') }} <i class="fa fa-puzzle-piece"></i>
</h3>
<div class="sidebox-content">
<ul class="problem-list">
{% for problem in new_problems %}
<li><a href="{{ url('problem_detail', problem.code) }}">{{ problem.name }}</a></li>
{% endfor %}
</ul>
<span class="rssatom">
<a href="{{ url('problem_rss') }}"><span><i class="fa fa-rss"></i></span> RSS</a>
/
<a href="{{ url('problem_atom') }}">Atom</a>
</span>
</div>
</div>
{% if perms.judge.test_site and own_open_tickets %}
<div class="blog-sidebox sidebox">
<h3>{{ _('My open tickets') }} <i class="fa fa-question-circle"></i></h3>
<div class="sidebox-content">
<ul class="own-open-tickets">
{% for ticket in own_open_tickets %}
<li>
<div class="title">
<a href="{{ url('ticket', ticket.id) }}">{{ ticket.title }}</a>
</div>
<div class="object">
<a href="{{ ticket.linked_item.get_absolute_url() }}">
{{ ticket.linked_item|item_title }}</a>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% if perms.judge.test_site and open_tickets %}
<div class="blog-sidebox sidebox">
<h3>{{ _('New tickets') }} <i class="fa fa-exclamation-circle"></i></h3>
<div class="sidebox-content">
<ul class="open-tickets">
{% for ticket in open_tickets %}
<li>
<div class="title">
<a href="{{ url('ticket', ticket.id) }}">{{ ticket.title }}</a>
</div>
<div class="object">
<a href="{{ ticket.linked_item.get_absolute_url() }}">
{{ ticket.linked_item|item_title }}</a>
</div>
<div>{{ link_user(ticket.user) }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
</div>
</div>
{% block after_posts %}{% endblock %}
{% endblock %}

View file

@ -0,0 +1,30 @@
<style>
.user-gravatar {
display: inline-block;
padding-right: 15px;
padding-top: 8px;
width: 135px;
}
.user-gravatar img {
width: 135px;
height: 135px;
display: block;
border-radius: 6px;
}
.recently-attempted, .recommended-problems {
display: inline-block;
}
.recently-attempted ul {
list-style: none;
padding-left: 1em;
padding-right: .5em;
margin: 0.2em;
}
.recently-attempted h4, .recommended-problems h4 {
font-weight: 500;
}
</style>

View file

@ -0,0 +1 @@
{{ preview_data|markdown('blog', MATH_ENGINE)|reference|str|safe }}

View file

@ -0,0 +1 @@
{{ comment.body|markdown('comment', MATH_ENGINE)|reference|str|safe }}

View file

@ -0,0 +1,17 @@
<div class="comment-submit">
<form id="comment-edit" action="{{ request.get_full_path() }}" method="post">
<span style="display: none" class="comment-id">{{ comment.id }}</span>
<span style="display: none" class="read-back">{{ url('comment_content', comment.id) }}</span>
{% csrf_token %}
<div class="form-errors">
{{ form.non_field_errors() }}
{{ form.body.errors }}
</div>
<div class="comment-post-wrapper">
<div id="comment-form-body">{{ form.body }}</div>
</div>
<hr>
<input style="float: right" type="submit" value="Post!" class="button">
</form>
</div>

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block media %}
{% compress css %}
{{ form.media.css }}
{% endcompress %}
{% endblock %}
{% block js_media %}
{{ form.media.js }}
{% endblock %}
{% block body %}
<div class="form-area">{% include "comments/edit-ajax.html" %}</div>
{% endblock %}

View file

@ -0,0 +1,159 @@
<div id="comments" class="comment-area">
<h2><i style="padding-right: 0.3em" class="fa fa-comments"></i>{{ _('Comments') }}</h2>
{% if has_comments %}
<ul class="comments top-level-comments new-comments">
{% set logged_in = request.user.is_authenticated %}
{% set profile = request.profile if logged_in else None %}
{% for node in mptt_tree(comment_list) recursive %}
<li id="comment-{{ node.id }}" data-revision="{{ node.revisions - 1 }}"
data-max-revision="{{ node.revisions - 1 }}"
data-revision-ajax="{{ url('comment_revision_ajax', node.id) }}" class="comment">
<div class="comment-display{% if node.score <= vote_hide_threshold %} bad-comment{% endif %}">
<div class="info">
<div class="vote">
{% if logged_in %}
<a href="javascript:comment_upvote({{ node.id }})"
class="upvote-link fa fa-chevron-up fa-fw{% if node.vote_score == 1 %} voted{% endif %}"></a>
{% else %}
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')" title="{{ _('Please login to vote') }}"
class="upvote-link fa fa-chevron-up fa-fw"></a>
{% endif %}
<br>
<div class="comment-score">{{ node.score }}</div>
{% if logged_in %}
<a href="javascript:comment_downvote({{ node.id }})"
class="downvote-link fa fa-chevron-down fa-fw{% if node.vote_score == -1 %} voted{% endif %}"></a>
{% else %}
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')" title="{{ _('Please login to vote') }}"
class="downvote-link fa fa-chevron-down fa-fw"></a>
{% endif %}
</div>
{% with author=node.author, user=node.author.user %}
<a href="{{ url('user_page', user.username) }}" class="user">
<img src="{{ gravatar(author, 135) }}" class="gravatar">
</a>
{% endwith %}
</div>
<div class="detail">
<div class="header">
{{ link_user(node.author) }}&nbsp;
{{ relative_time(node.time, abs=_('commented on {time}'), rel=_('commented {time}')) }}
<span class="comment-spacer"></span>
<span class="comment-operation">
{% if node.revisions > 1 %}
<span class="comment-edits">
<a href="javascript:show_revision({{ node.id }}, -1)"
class="previous-revision">&larr;</a>
<span class="comment-edit-text">
{% if node.revisions > 2 %}
{% trans edits=node.revisions - 1 %}edit {{ edits }}{% endtrans %}
{% else %}
{{ _('edited') }}
{% endif %}
</span>
<a href="javascript:show_revision({{ node.id }}, 1)" style="visibility: hidden"
class="next-revision">&rarr;</a>
</span>
{% else %}
<span class="comment-edits"></span>
{% endif %}
<a href="#comment-{{ node.id }}" title="{{ _('Link') }}" class="comment-link">
<i class="fa fa-link fa-fw"></i>
</a>
{% if logged_in and not comment_lock %}
{% set can_edit = node.author.id == profile.id and not profile.mute %}
{% if can_edit %}
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
href="{{ url('comment_edit', node.id) }}"
title="{{ _('Edit') }}" class="edit-link">
<i class="fa fa-pencil fa-fw"></i>
</a>
{% else %}
<a href="javascript:comment_set_parent({{ node.id }})"
title="{{ _('Reply') }}">
<i class="fa fa-reply fa-fw"></i>
</a>
{% endif %}
{% if perms.judge.change_comment %}
{% if can_edit %}
<a href="javascript:comment_set_parent({{ node.id }})"
title="{{ _('Reply') }}"><i class="fa fa-reply fa-fw"></i></a>
{% else %}
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
href="{{ url('comment_edit', node.id) }}" title="{{ _('Edit') }}"
class="edit-link"><i class="fa fa-pencil fa-fw"></i></a>
{% endif %}
<a href="javascript:" title="{{ _('Hide') }}" data-id="{{ node.id }}"
class="hide-comment"><i class="fa fa-trash fa-fw"></i></a>
<a href="{{ url('admin:judge_comment_change', node.id) }}"
title="{{ _('Admin') }}"><i class="fa fa-cog fa-fw"></i></a>
{% endif %}
{% endif %}
</span>
</div>
<div class="content content-description">
<div class="comment-body"{% if node.score <= vote_hide_threshold %} style="display:none"{% endif %}>
{{ node.body|markdown('comment', MATH_ENGINE, True)|reference|str|safe }}
</div>
{% if node.score <= vote_hide_threshold %}
<div class="comment-body bad-comment-body">
<p>
{% trans id=node.id %}
This comment is hidden due to too much negative feedback.
Click <a href="javascript:comment_show_content({{ id }})">here</a> to view it.
{% endtrans %}
</p>
</div>
{% endif %}
</div>
</div>
</div>
</li>
{% with children=node.get_children() %}
{% if children %}
<ul id="comment-{{ node.id }}-children" class="comments">{{ loop(children) }}</ul>
{% endif %}
{% endwith %}
{% endfor %}
</ul>
{% elif not comment_lock %}
<p class="no-comments-message">{{ _('There are no comments at the moment.') }}</p>
{% endif %}
{% if request.user.is_authenticated and comment_form and not comment_lock %}
<div class="form-area comment-submit">
{% block comment_submit_title %}
<h3>{{ _('New comment') }}</h3>
<hr>
{% endblock %}
{% if is_new_user %}
<div style="margin-bottom: 0" class="alert alert-info">
{{ _('You need to have solved at least one problem before your voice can be heard.') }}
</div>
{% else %}
<form id="comment-submit" action="" method="post">
{% csrf_token %}
{% if comment_form.errors %}
<div id="form-errors">
{{ comment_form.non_field_errors() }}
{{ comment_form.parent.errors }}
{% if comment_form.body.errors %}{{ _('Invalid comment body.') }}{% endif %}
</div>
{% endif %}
{{ comment_form.parent }}
<div class="comment-post-wrapper">
<div id="comment-form-body">{{ comment_form.body }}</div>
</div>
<hr>
<input style="float:right" type="submit" value="{{ _('Post!') }}" class="button">
</form>
{% endif %}
</div>
{% endif %}
{% if comment_lock %}
<div class="alert alert-warning comment-lock">
{{ _('Comments are disabled on this page.') }}
</div>
{% endif %}
</div>

View file

@ -0,0 +1,3 @@
{% compress js, inline %}
<script src="{{ static('pagedown_math.js') }}"></script>
{% endcompress %}

View file

@ -0,0 +1,103 @@
{% compress css %}
{{ comment_form.media.css }}
<style media="all">
.featherlight {
z-index: 1000;
}
.revision-text p:first-child {
margin-top: 0;
}
.revision-text p:last-child {
margin-bottom: 0;
}
.featherlight-edit .featherlight-content {
background: #FAFAFA;
padding: 10px 15px 10px 10px;
border-radius: 10px;
border: 1px solid #CCC;
}
.new-comments .comment-display {
display: flex;
margin-top: -0.25em !important;
padding-left: 1em;
padding-top: 0.5em !important;
border: 1px solid #ccc;
background: #fafafa;
}
.new-comments .comment .detail {
margin: 0px 15px 0px;
width: 100%;
max-width: calc(100% - 134px);
}
.new-comments .comment-edits {
padding-right: 0.75em;
}
.new-comments .comment .detail .header {
display: flex;
padding: 2px 0px;
font-weight: normal;
border-bottom: 1px #888 solid;
color: #888;
text-align: right;
}
.previous-revision, .next-revision {
color: #444;
}
.new-comments .header i {
color: #888 !important;
}
.new-comments .info {
padding-top: 0.4em;
display: flex;
}
.new-comments .gravatar {
width: 75px;
max-width: 75px;
}
.new-comments .vote {
margin-right: 1em;
height: 75px;
padding-top: 0.4em;
}
.new-comments .comment-display {
border-radius: 4px;
}
.new-comments .comment:target > .comment-display {
border: 1px solid #2980b9;
border-left: 10px solid #2980b9;
padding-left: 5px;
}
.comments.top-level-comments {
margin-bottom: -3px;
}
.bad-comment {
opacity: 0.3;
}
.bad-comment:hover {
opacity: 1;
/* This is necessary to prevent random flickering */
-webkit-transform: translatez(0)
-moz-transform: translatez(0);
-ms-transform: translatez(0);
-o-transform: translatez(0);
transform: translatez(0);
}
</style>
{% endcompress %}

View file

@ -0,0 +1,206 @@
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
{% compress js %}
{{ comment_form.media.js }}
{% if not REQUIRE_JAX %}
<script type="text/javascript">
$(function () {
$('#id_body').keypress(function () {
if (!("MathJax" in window)) {
$.ajax({
type: "GET",
url: '{{ static('mathjax_config.js') }}',
dataType: "script",
cache: true,
success: function () {
$.ajax({
type: "GET",
url: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/config=TeX-AMS_HTML',
dataType: "script",
cache: true,
success: function () {
mathjax_pagedown($);
}
});
}
});
}
});
});
</script>
{% endif %}
<script type="text/javascript">
$(document).ready(function () {
window.comment_set_parent = function (parent) {
$('form#comment-submit input#id_parent').val(parent);
$('html, body').animate({
scrollTop: $('.form-area.comment-submit').offset().top - $('#navigation').height() - 4
}, 500);
};
function update_math($comment) {
if ('MathJax' in window) {
var $body = $comment.find('.comment-body');
MathJax.Hub.Queue(['Typeset', MathJax.Hub, $body[0]], function () {
$body.find('.tex-image').hide();
$body.find('.tex-text').show();
});
}
}
window.show_revision = function (comment_id, offset) {
var $comment = $("#comment-" + comment_id);
// If .comment-body is hidden, then this is a bad comment that the user has not clicked
// Thus the revision retrieval should do nothing
if (!$comment.find('.comment-body').is(':visible'))
return;
var cur_revision = parseInt($comment.attr("data-revision"));
var max_revision = parseInt($comment.attr("data-max-revision"));
var revision_ajax = $comment.attr("data-revision-ajax");
var show_revision = cur_revision + offset;
$comment.attr("data-revision", show_revision);
$.get(revision_ajax, {
revision: show_revision
}).done(function (body) {
$comment.find('.previous-revision').css({visibility: show_revision == 0 ? 'hidden' : ''});
$comment.find('.next-revision').css({visibility: show_revision == max_revision ? 'hidden' : ''});
$comment.find('.content').html(body);
var edit_text = '{{ _('edit {edits}') }}'.replace("{edits}", show_revision);
if (show_revision == 0) {
edit_text = '{{ _('original') }}';
} else if (show_revision == max_revision && max_revision == 1) {
edit_text = '{{ _('edited') }}';
}
$comment.find('.comment-edit-text').text(' ' + edit_text + ' ');
update_math($comment);
});
};
function ajax_vote(url, id, delta, on_success) {
return $.ajax({
url: url,
type: 'POST',
data: {
id: id
},
success: function (data, textStatus, jqXHR) {
var score = $('#comment-' + id + ' .comment-score').first();
score.text(parseInt(score.text()) + delta);
if (typeof on_success !== 'undefined')
on_success();
},
error: function (data, textStatus, jqXHR) {
alert('Could not vote: ' + data.responseText);
}
});
}
var get_$votes = function (id) {
var $comment = $('#comment-' + id);
return {
upvote: $comment.find('.upvote-link').first(),
downvote: $comment.find('.downvote-link').first()
};
};
window.comment_upvote = function (id) {
ajax_vote('{{ url('comment_upvote') }}', id, 1, function () {
var $votes = get_$votes(id);
if ($votes.downvote.hasClass('voted'))
$votes.downvote.removeClass('voted');
else
$votes.upvote.addClass('voted');
});
};
window.comment_downvote = function (id) {
ajax_vote('{{ url('comment_downvote') }}', id, -1, function () {
var $votes = get_$votes(id);
if ($votes.upvote.hasClass('voted'))
$votes.upvote.removeClass('voted');
else
$votes.downvote.addClass('voted');
});
};
var $comments = $('.comments');
$comments.find('a.hide-comment').click(function (e) {
e.preventDefault();
if (!(e.ctrlKey || e.metaKey || confirm('Are you sure you want to hide this comment?')))
return;
var id = $(this).attr('data-id');
$.post('{{ url('comment_hide') }}', {id: id}).then(function () {
$('#comment-' + id).remove();
$('#comment-' + id + '-children').remove();
}).catch(function () {
alert('Failed.');
});
});
$comments.find('a.edit-link').featherlight({
afterOpen: function () {
if ('DjangoPagedown' in window) {
var $wmd = $('.featherlight .wmd-input');
if ($wmd.length) {
window.DjangoPagedown.createEditor($wmd.get(0));
if ('MathJax' in window) {
var preview = $('.featherlight div.wmd-preview')[0];
window.editors[$wmd.attr('id')].hooks.chain('onPreviewRefresh', function () {
MathJax.Hub.Queue(['Typeset', MathJax.Hub, preview]);
});
MathJax.Hub.Queue(['Typeset', MathJax.Hub, preview]);
}
}
}
$('#comment-edit').submit(function (event) {
event.preventDefault();
var id = $('#comment-edit').find('.comment-id').text();
var readback = $('#comment-edit').find('.read-back').text();
$.post($(this).attr('action'), $(this).serialize()).done(function (data) {
$.featherlight.current().close();
$.ajax({
url: readback
}).done(function (data) {
var $comment = $('#comment-' + id);
var $area = $comment.find('.comment-body').first();
$area.html(data);
update_math($comment);
var $edits = $comment.find('.comment-edits').first();
$edits.text('updated');
}).fail(function () {
console.log('Failed to update comment:' + id);
});
});
});
},
variant: 'featherlight-edit'
});
var $root = $('html, body');
$comments.find('a.comment-link').click(function () {
var href = $.attr(this, 'href');
$root.animate({
scrollTop: $(href).offset().top
}, 500, function () {
window.location.hash = href;
});
return false;
});
$('img.unveil').unveil(200);
window.comment_show_content = function (comment_id) {
var $comment = $('#comment-' + comment_id);
$comment.find('.comment-body').show();
$comment.find('.bad-comment-body').hide();
};
});
</script>
{% endcompress %}

View file

@ -0,0 +1,4 @@
{{ preview_data|markdown('comment', MATH_ENGINE)|reference|str|safe }}
{% if REQUIRE_JAX %}
<div data-config="{{ static('mathjax_config.js') }}" class="require-mathjax-support"></div>
{% endif %}

View file

@ -0,0 +1,3 @@
{% with node=revision.field_dict %}
<div class="comment-body">{{ node.body|markdown('comment', MATH_ENGINE)|reference|str|safe }}</div>
{% endwith %}

View file

@ -0,0 +1,17 @@
<h2>Votes</h2>
<table class="table">
<thead>
<tr>
<th>Voter</th>
<th>Score</th>
</tr>
</thead>
<tbody>
{% for vote in votes %}
<tr>
<td>{{ link_user(vote.voter) }}</td>
<td>{{ vote.score }}</td>
</tr>
{% endfor %}
</tbody>
</table>

View file

@ -0,0 +1,81 @@
{% extends "base.html" %}
{% block media %}
{% block content_media %}{% endblock %}
{% endblock %}
{% block js_media %}
{% compress js %}
<script src="{{ static('libs/clipboard/clipboard.js') }}"></script>
<script src="{{ static('libs/clipboard/tooltip.js') }}"></script>
<script type="text/javascript">
$(function () {
var info_float = $('.info-float');
if (info_float.length) {
var container = $('#content-right');
if (window.bad_browser) {
container.css('float', 'right');
} else if (!featureTest('position', 'sticky')) {
fix_div(info_float, 55);
$(window).resize(function () {
info_float.width(container.width());
});
info_float.width(container.width());
}
}
var copyButton;
$('pre code').each(function () {
$(this).parent().before($('<div>', {'class': 'copy-clipboard'})
.append(copyButton = $('<span>', {
'class': 'btn-clipboard',
'data-clipboard-text': $(this).text(),
'title': 'Click to copy'
}).text('Copy')));
$(copyButton.get(0)).mouseleave(function () {
$(this).attr('class', 'btn-clipboard');
$(this).removeAttr('aria-label');
});
var curClipboard = new Clipboard(copyButton.get(0));
curClipboard.on('success', function (e) {
e.clearSelection();
showTooltip(e.trigger, 'Copied!');
});
curClipboard.on('error', function (e) {
showTooltip(e.trigger, fallbackMessage(e.action));
});
});
});
</script>
{% endcompress %}
{% block content_js_media %}{% endblock %}
{% endblock %}
{% block body %}
<div id="common-content">
<div id="content-right">
<div class="info-float">{% block info_float %}{% endblock %}</div>
</div>
<div id="content-left" class="split-common-content">
<div class="content-description screen">
{% block description %}{% endblock %}
{% block description_end %}
<hr>
{% endblock %}
{% block post_description_end %}{% endblock %}
</div>
{% block comments %}{% endblock %}
</div>
</div>
{% endblock %}
{% block bodyend %}
{% if REQUIRE_JAX %}
{% include "mathjax-load.html" %}
{% endif %}
{% endblock %}

View 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 %}

View 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 %}

View 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 %}

View 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) }}">&laquo; {{ _('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') }} &raquo;</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 %}

View 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 %}

View 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('') }}&amp;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
View 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 %}

View 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>

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View file

@ -0,0 +1,7 @@
{% if not title %}
{% include "contest/tag-title.html" %}
<br><br>
<hr>
{% endif %}
{{ tag.description|markdown('contest_tag') }}

View 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 %}

View 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 %}

39
templates/error.html Normal file
View file

@ -0,0 +1,39 @@
<html>
<head>
<title>{{ code }} - {{ id }}</title>
<style>
body {
color: #FFFFFF;
background-color: #000080;
font-family: Lucida Console, Monospace, serif;
font-size: 14px;
font-smooth: never;
-webkit-font-smoothing: none;
margin-left: 50px;
margin-top: 20px;
}
a {
color: #FFFFFF;
font-weight: bold
}
pre {
font-family: Lucida Console, Monospace, serif;
line-height: 1.3;
font-smooth: never;
-webkit-font-smoothing: none;
white-space: pre-wrap;
}
</style>
</head>
<body>
<h2>SIGSEGV: {{ id }}</h2>
<pre>{{ description }}
site: fatal signal: Segmentation fault
site died (signal <b>{{ code }}</b>, exit -11)<br><br>panic: <a href="javascript:history.back()">go back</a></pre>
{% if request.user.is_superuser and traceback %}
<pre>{{ traceback }}</pre>
{% endif %}
</body>
</html>

0
templates/extra_js.html Normal file
View file

View file

@ -0,0 +1,5 @@
{% if perms.flatpages.change_flatpage %}
<div class="title-line-action">
[<a href="{{ url('admin:flatpages_flatpage_change', flatpage.id) }}">{{ _('Edit') }}</a>]
</div>
{% endif %}

View file

@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block title %}{{ flatpage.title }} - {{ SITE_LONG_NAME }}{% endblock %}
{% block og_title %}
<meta property="og:title" content="{{ flatpage.title }} - {{ SITE_LONG_NAME }}">
{% endblock %}
{% block content_title %}{{ flatpage.title }}{% endblock %}
{% block header %}
{% include "flatpages/admin_link.html" %}
{% endblock %}
{% block body %}
{{ render_django(flatpage.content) }}
{% endblock %}

View file

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block title %}{{ flatpage.title }} - {{ SITE_LONG_NAME }}{% endblock %}
{% block og_title %}
<meta property="og:title" content="{{ flatpage.title }} - {{ SITE_LONG_NAME }}">
{% endblock %}
{% block content_title %}{{ flatpage.title }}{% endblock %}
{% block header %}{% include "flatpages/admin_link.html" %}{% endblock %}
{% block body %}
<div class="content-description">{{ flatpage.content|markdown('solution')|reference|str|safe }}</div>
{% endblock %}

View file

@ -0,0 +1,9 @@
{% extends "flatpages/markdown.html" %}
{% block body %}
<div class="content-description">{{ flatpage.content|markdown('solution', MATH_ENGINE)|reference }}</div>
{% endblock %}
{% block bodyend %}
{% if REQUIRE_JAX %}{% include "mathjax-load.html" %}{% endif %}
{% endblock %}

View file

@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block body %}
<h3>{{ message }}</h3>
{% endblock %}

23
templates/home.html Normal file
View file

@ -0,0 +1,23 @@
{% extends "blog/list.html" %}
{% block before_posts %}
{% if i18n_config.home_page_top %}
{{ render_django(i18n_config.home_page_top, request=request, user_count=user_count, problem_count=problem_count, submission_count=submission_count, language_count=language_count, perms=perms) }}
{% endif %}
{% endblock %}
{% block meta %}
{% if i18n_config.meta_description %}
<meta name="description" content="{{ i18n_config['meta_description'] }}">
{% endif %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"url": "{{ DMOJ_SCHEME }}://{{ site.domain }}/",
"potentialAction": {
"@type": "SearchAction",
"target": "{{ DMOJ_SCHEME }}://{{ site.domain }}/problems/?search={search_term_string}",
"query-input": "required name=search_term_string"
}
}
</script>
{% endblock %}

View file

@ -0,0 +1 @@
{{ preview_data|markdown('license') }}

13
templates/license.html Normal file
View file

@ -0,0 +1,13 @@
{% extends "common-content.html" %}
{% block description %}
{% cache 3600 'license_html' license.id %}
{{ license.text|markdown('license') }}
{% endcache %}
{% endblock %}
{% block info_float %}
{% if perms.judge.change_license %}
<div><a href="{{ url('admin:judge_license_change', license.id) }}">{{ _('Edit') }}</a></div>
{% endif %}
<div><b>{{ _('Source:') }}</b> <a href="{{ license.link }}">{{ license.link }}</a></div>
{% endblock %}

31
templates/list-pages.html Normal file
View file

@ -0,0 +1,31 @@
<ul class="pagination">
{% if page_obj.has_previous() %}
{% if page_obj.previous_page_number() == 1 and first_page_href != None %}
<li><a href="{{ first_page_href }}">«</a></li>
{% else %}
<li><a href="{{ page_prefix or '' }}{{ page_obj.previous_page_number() }}{{ page_suffix or '' }}">«</a></li>
{% endif %}
{% else %}
<li class="disabled-page"><span>«</span></li>
{% endif %}
{% for page in page_obj.page_range %}
{% if not page %}
<li class="disabled-page"><span>...</span></li>
{% else %}
<li{% if page == page_obj.number %} class="active-page"{% endif %}><a href="
{%- if page == 1 and first_page_href != None -%}
{{ first_page_href }}
{%- else -%}
{{ page_prefix or '' }}{{ page }}{{ page_suffix or '' }}
{%- endif -%}
">{{ page }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next() %}
<li><a href="{{ page_prefix or '' }}{{ page_obj.next_page_number() }}{{ page_suffix or '' }}">»</a></li>
{% else %}
<li class="disabled-page"><span>»</span></li>
{% endif %}
</ul>

View file

@ -0,0 +1,12 @@
<script type="text/javascript" src="{{ static('mathjax_config.js') }}"></script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML"></script>
<script type="text/javascript">
window.reload_mathjax = function () {
MathJax.Hub.queue.Push(function () {
$('.tex-image').hide();
$('.tex-text').show();
});
};
window.reload_mathjax();
</script>

7
templates/messages.html Normal file
View file

@ -0,0 +1,7 @@
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li class="{{ message.tags }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}

View file

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{% block title %}{{ _('Newsletter') }}{% endblock title %}</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" >
{% block header %}
{% endblock header %}
</head>
<body>
{% block body %}
{% endblock body %}
</body>
</html>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{{ newsletter.title }}: {{ message.title }}</title>
</head>
<body>
{% for article in message.articles.all() %}
<div>{{ article.text|safe }}</div>
{% if article.url %}
<div><a href="{{ article.url }}">Read more</a></div>
{% endif %}
{% endfor %}
<a href="http://{{ site.domain }}{{ url('newsletter_unsubscribe_request', newsletter.slug) }}" style="color:#999;float:right">Unsubscribe</a>
{% if submission and submission.publish %}
<a href="http://{{ site.domain }}{{ submission.get_absolute_url }}" style="color:#999">Read message online</a>
{% endif %}
</body>
</html>

View file

@ -0,0 +1,15 @@
++++++++++++++++++++
{{ newsletter.title|safe }}: {{ message.title|safe }}
++++++++++++++++++++
{% for article in message.articles.all() %}
{{ article.title|safe }}
{{ article.text|striptags|safe }}
{% endfor %}
++++++++++++++++++++
Unsubscribe: http://{{ site }}{{ url('newsletter_unsubscribe_request', newsletter.slug) }}

View file

@ -0,0 +1 @@
{{ message.title|safe }}

View file

@ -0,0 +1,20 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Subscription to {{ newsletter.title }}</title>
</head>
<body>
Dear {{ subscription.name }},
you, or someone in your name requested a subscription to {{ newsletter.title }}.
If you would like to confirm your subscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.subscribe_activate_url }}
Kind regards,
{{ newsletter.sender }}
</body>
</html>

View file

@ -0,0 +1,9 @@
Dear {{ subscription.name|safe }},
you, or someone in your name requested a subscription to {{ newsletter.title|safe }}.
If you would like to confirm your subscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.subscribe_activate_url }}
Kind regards,
{{ newsletter.sender|safe }}

View file

@ -0,0 +1 @@
{{ newsletter.title|safe }} - Confirm subscription

View file

@ -0,0 +1,20 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unsubscription from {{ newsletter.title }}</title>
</head>
<body>
Dear {{ subscription.name }},
you, or someone in your name requested unsubscription from {{ newsletter.title }}.
If you would like to confirm your unsubscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.unsubscribe_activate_url }}
Kind regards,
{{ newsletter.sender }}
</body>
</html>

View file

@ -0,0 +1,9 @@
Dear {{ subscription.name|safe }},
you, or someone in your name requested unsubscription from {{ newsletter.title|safe }}.
If you would like to confirm your unsubscription, please follow this activation link:
http://{{ site.domain }}{{ subscription.unsubscribe_activate_url }}
Kind regards,
{{ newsletter.sender|safe }}

View file

@ -0,0 +1 @@
{{ newsletter.title|safe }} - Confirm unsubscription

View file

@ -0,0 +1,20 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Update of subscription to {{ newsletter.title }}</title>
</head>
<body>
Dear {{ subscription.name }},
you, or someone in your name requested updating your personal information for {{ newsletter.title }}.
To make changes to your information in our database, please follow this activation link:
http://{{ site.domain }}{{ subscription.update_activate_url }}
Kind regards,
{{ newsletter.sender }}
</body>
</html>

View file

@ -0,0 +1,9 @@
Dear {{ subscription.name|safe }},
you, or someone in your name requested updating your personal information for {{ newsletter.title|safe }}.
To make changes to your information in our database, please follow this activation link:
http://{{ site.domain }}{{ subscription.update_activate_url }}
Kind regards,
{{ newsletter.sender|safe }}

View file

@ -0,0 +1 @@
{{ newsletter.title|safe }} - Update information

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}{{ object.title }} - Newsletter - {{ SITE_LONG_NAME }}{% endblock %}
{% block content_title %}Newsletter: {{ object.title }}{% endblock %}
{% block body %}
<ul>
<li><a href="{{ url('newsletter_subscribe_request', object.slug) }}">Subscribe</a></li>
<li><a href="{{ url('newsletter_unsubscribe_request', object.slug) }}">Unsubscribe</a></li>
<li><a href="{{ url('newsletter_archive', object.slug) }}">Archive</a></li>
<li><a href="{{ url('newsletter_list') }}">Back to list</a></li>
</ul>
{% endblock %}

View file

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% block title %}Newsletter list - {{ SITE_LONG_NAME }}{% endblock %}
{% block content_title %}Newsletter list{% endblock %}
{% block body %}
{% if request.user.is_authenticated %}
<form method="POST" action="" class="form-area">
{% csrf_token %}
{{ formset.management_form }}
<table>
<tr>
<th>Newsletter</th>
<th>Subscribe</th>
</tr>
{% for form in formset.forms %}
<tr>
<td>{{ form.id }}{{ form.newsletter }}
<a href="{{ url('newsletter_archive', form.instance.newsletter.slug) }}">
{{ form.instance.newsletter.title }}</a>
</td>
<td>{{ form.subscribed }}</td>
</tr>
{% endfor %}
</table>
<hr>
<p>
<input id="id_submit" name="submit" value="Update subscriptions" type="submit" style="float: right">
</p>
</form>
{% else %}
<table class="form-area">
<tr>
<th>Newsletter</th>
</tr>
{% for newsletter in object_list %}
<tr>
<td><a href="{{ url('newsletter_detail', newsletter.slug) }}">{{ newsletter.title }}</a></td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}{{ object.title }} - Newsletter Archive - {{ SITE_LONG_NAME }}{% endblock %}
{% block content_title %}Newsletter Archive: {{ object.title }}{% endblock %}
{% block body %}
<ul>
{% for submission in latest %}
<li><a href="{{ submission.get_absolute_url }}">{{ submission }}</a></li>
{% endfor %}
</ul>
<hr>
<p><a href="{{ url('newsletter_list') }}">Back to list</a></p>
{% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block title %}Newsletter {{ newsletter.title }} {{ action }} activate{% endblock %}
{% block body %}
<h1>Newsletter {{ newsletter.title }} {{ action }} activate</h1>
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" type="submit" value="Activate"></p>
</form>
{% endblock %}

View file

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block title %}Newsletter subscribe{% endblock %}
{% block body %}
<h1>Newsletter subscribe {{ newsletter.title }}</h1>
{% if error %}
<p>
Due to a technical error we were not able to submit your confirmation email.
This could be because your email address is invalid.
</p>
{% else %}
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" value="Subscribe" type="submit"></p>
</form>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block title %}Newsletter {{ newsletter.title }} {{ action }} activate{% endblock %}
{% block body %}
<h1>Newsletter {{ newsletter.title }} {{ action }} activate</h1>
<p>Your subscription has successfully been activated.</p>
{% endblock %}

View file

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block title %}Newsletter subscribe{% endblock %}
{% block body %}
<h1>Newsletter subscribe {{ newsletter.title }}</h1>
<p>Your subscription request was successfully received and an activation email has been sent to you. In that email
you will find a link which you need to follow in order to activate your subscription.</p>
{% endblock %}

View file

@ -0,0 +1,22 @@
{% extends "base.html" %}
{% block title %}Newsletter subscribe{% endblock %}
{% block body %}
<h1>Newsletter subscribe {{ newsletter.title }}</h1>
<p>Welcome, {{ request.user }}!</p>
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% else %}
Do you want to subscribe to this newsletter?
<form enctype="multipart/form-data" method="post"
action="{{ url('newsletter_subscribe_confirm', newsletter.slug) }}">
{% csrf_token %}
<p><input id="id_submit" name="submit" value="Subscribe" type="submit"></p>
</form>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,17 @@
{% extends "base.html" %}
{% block title %}Newsletter unsubscribe{% endblock %}
{% block body %}
<h1>Newsletter unsubscribe {{ newsletter.title }}</h1>
{% if error %}
<p>Due to a technical error we were not able to submit your confirmation email.
This could be because your email address is invalid.</p>
{% else %}
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" value="Unsubscribe" type="submit"></p>
</form>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,9 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}</h1>
<p>{{ _('You have successfully been unsubscribed.') }}</p>
{% endblock body %}

View file

@ -0,0 +1,9 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter unsubscribe') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter unsubscribe') }} {{ newsletter.title }}</h1>
<p>{{ _('Your unsubscription request has successfully been received. An email has been sent to you with a link you need to follow in order to confirm your unsubscription.') }}</p>
{% endblock body %}

View file

@ -0,0 +1,25 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter unsubscribe') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter unsubscribe') }} {{ newsletter.title }}</h1>
<p>Welcome, {{ request.user }}!</p>
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% else %}
{{ _('Do you want to unsubscribe from this newsletter?') }}
<form enctype="multipart/form-data" method="post"
action="{{ url('newsletter_unsubscribe_confirm', newsletter.slug) }}">
{% csrf_token %}
<p><input id="id_submit" name="submit" value="{{ _('Unsubscribe') }}" type="submit"></p>
</form>
{% endif %}
{% endblock body %}

View file

@ -0,0 +1,17 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter update') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter update') }} {{ newsletter.title }}</h1>
{% if error %}
<p>{{ _('Due to a technical error we were not able to submit your confirmation email. This could be because your email address is invalid.') }}</p>
{% else %}
<form enctype="multipart/form-data" method="post" action=".">
{% csrf_token %}
{{ form.as_p() }}
<p><input id="id_submit" name="submit" value="{{ _('Update subscription') }}" type="submit"></p>
</form>
{% endif %}
{% endblock body %}

View file

@ -0,0 +1,9 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter') }} {{ newsletter.title }} {{ action }} {{ _('activate') }}</h1>
<p>{{ _('Your subscription has successfully been updated.') }}</p>
{% endblock body %}

View file

@ -0,0 +1,9 @@
{% extends "newsletter/common.html" %}
{% block title %}{{ _('Newsletter update') }}{% endblock title %}
{% block body %}
<h1>{{ _('Newsletter update') }} {{ newsletter.title }}</h1>
<p>{{ _('Your update request was successfully received and an activation email has been sent to you. In that email you will find a link which you need to follow in order to update your subscription.') }}</p>
{% endblock body %}

View file

@ -0,0 +1,48 @@
{% extends "base.html" %}
{% block js_media %}
{{ form.media.js }}
<script type="text/javascript">
window.django = {jQuery: $};
function pluralidx(count) {
return (count == 1) ? 0 : 1;
}
function gettext(msgid) {
return msgid;
}
function interpolate(fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function (match) {
return String(obj[match.slice(2, -2)])
});
} else {
return fmt.replace(/%s/g, function (match) {
return String(obj.shift())
});
}
}
</script>
{% endblock %}
{% block media %}
{{ form.media.css }}
<link rel="stylesheet" href="{{ static('admin/css/widgets.css') }}" type="text/css">
<link rel="stylesheet" href="{{ static('admin/css/pagedown.css') }}" type="text/css">
<link rel="stylesheet" href="{{ static('problem_edit.css') }}" type="text/css">
<style>
#id_about {
width: 500px;
}
</style>
{% endblock %}
{% block body %}
<form action="" method="post" class="form-area">
{% csrf_token %}
<table border="0" style="text-align:left">{{ form.as_table() }}</table>
<button type="submit">{{ _('Update') }}</button>
</form>
{% endblock %}

View file

@ -0,0 +1,63 @@
{% extends "common-content.html" %}
{% block content_js_media %}
<script type="text/javascript">
$(function () {
$('.leave-organization').click(function () {
return confirm('{{ _('Are you sure you want to leave this organization?') }}\n' +
{% if organization.is_open %}
'{{ _('You will have to rejoin to show up on the organization leaderboard.') }}'
{% else %}
'{{ _('You will have to request membership in order to join again.') }}'
{% endif %}
);
});
});
</script>
{% endblock %}
{% block info_float %}
{% if request.user.is_authenticated %}
{% if request.profile in organization %}
<form method="post" action="{{ url('leave_organization', organization.id, organization.slug) }}">
{% csrf_token %}
<input type="submit" class="unselectable button full leave-organization" value="{{ _('Leave organization') }}">
</form>
{% elif organization.is_open %}
<form method="post" action="{{ url('join_organization', organization.id, organization.slug) }}">
{% csrf_token %}
<input type="submit" class="unselectable button full" value="{{ _('Join organization') }}">
</form>
{% else %}
<a href="{{ url('request_organization', organization.id, organization.slug) }}"
class="unselectable button full">{{ _('Request membership') }}</a>
{% endif %}
<hr>
{% endif %}
{% if can_edit %}
<div><a href="{{ url('edit_organization', organization.id, organization.slug) }}">{{ _('Edit organization') }}</a></div>
{% if not organization.is_open %}
<div>
<a href="{{ url('organization_requests_pending', organization.id, organization.slug) }}">{{ _('View requests') }}</a>
</div>
{% endif %}
{% endif %}
{% if perms.judge.change_organization %}
<div>
<a href="{{ url('admin:judge_organization_change', organization.id) }}">{{ _('Admin organization') }}</a>
</div>
{% endif %}
<div>
<a href="{{ organization.get_users_url() }}">{{ _('View members') }}</a>
</div>
{% endblock %}
{% block description %}
{% cache 3600 'organization_html' organization.id MATH_ENGINE %}
{{ organization.about|markdown('organization-about', MATH_ENGINE)|reference|str|safe }}
{% endcache %}
{% endblock %}

View file

@ -0,0 +1,36 @@
{% extends "base.html" %}
{% block js_media %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$("#organization-table").tablesorter();
});
</script>
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% set tab = 'organizations' %}
{% set title = _('Organizations') %}
{% include "user/user-list-tabs.html" %}
{% endblock %}
{% block body %}
<table id="organization-table" class="table">
<thead>
<tr>
<th style="width:85%">{{ _('Name') }}</th>
<th>{{ _('Members') }}</th>
</tr>
</thead>
<tbody>
{% for org in organizations %}
<tr>
<td><a href="{{ org.get_absolute_url() }}">{{ org.name }}</a></td>
<td><a href="{{ org.get_users_url() }}">{{ org.member_count }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block js_media %}{{ form.media.js }}{% endblock %}
{% block media %}{{ form.media.css }}{% endblock %}
{% block body %}
<form action="" method="post" class="form-area">
{% csrf_token %}
<table border="0" style="text-align:left">{{ form.as_table() }}</table>
<button type="submit">{{ _('Create') }}</button>
</form>
{% endblock %}

View file

@ -0,0 +1,4 @@
{{ preview_data|markdown('organization-about', MATH_ENGINE)|reference|str|safe }}
{% if REQUIRE_JAX %}
<div data-config="{{ static('mathjax_config.js') }}" class="require-mathjax-support"></div>
{% endif %}

View file

@ -0,0 +1,35 @@
{% extends "base.html" %}
{% block media %}
<style>
th {
text-align: left
}
</style>
{% endblock %}
{% block body %}
<table>
<tr>
<th>{{ _('User:') }}</th>
<td>{{ link_user(object.user) }}</td>
</tr>
<tr>
<th>{{ _('Organization:') }}</th>
<td>
{% with org=object.organization %}
<a href="{{ org.get_absolute_url() }}">{{ org.name }}</a>
{% endwith %}
</td>
</tr>
<tr>
<th>{{ _('Time:') }}</th>
<td>{{ object.time|date(_("N j, Y, g:i a")) }}</td>
</tr>
<tr>
<th colspan="2">{{ _('Reason:') }}</th>
</tr>
<tr>
<td colspan="2" style="padding-left: 2em">{{ object.reason }}</td>
</tr>
</table>
{% endblock %}

View file

@ -0,0 +1,30 @@
{% extends "base.html" %}
{% block body %}
{% include "organization/requests/tabs.html" %}
{% if requests %}
<table>
<tr>
<th>{{ _('User') }}</th>
<th>{{ _('Time') }}</th>
<th>{{ _('State') }}</th>
<th>{{ _('Reason') }}</th>
</tr>
{% for r in requests %}
<tr id="request-{{ r.id }}">
<td>{{ link_user(r.user) }}</td>
<td>
<a href="{{ url('request_organization_detail', object.id, object.slug, r.id) }}">
{{- r.time|date(_("N j, Y, H:i")) -}}
</a>
</td>
<td>{{ r.state }}</td>
<td>{{ r.reason|truncatechars(50) }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>{{ _('There are no requests to approve.') }}</p>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,39 @@
{% extends "base.html" %}
{% block body %}
{% include "messages.html" %}
{% include "organization/requests/tabs.html" %}
{% if formset.forms %}
<form action="" method="post">
{% csrf_token %}
{{ formset.management_form }}
<table>
<tr>
<th>{{ _('User') }}</th>
<th>{{ _('Time') }}</th>
<th>{{ _('State') }}</th>
<th>{{ _('Reason') }}</th>
{% if formset.can_delete %}
<th>{{ _('Delete?') }}</th>
{% endif %}
</tr>
{% for form in formset %}
<tr id="request-{{ form.instance.id }}">
<td>{{ form.id }}{{ link_user(form.instance.user) }}</td>
<td><a href="{{ url('request_organization_detail', object.id, object.slug, form.instance.id) }}">
{{ form.instance.time|date(_("N j, Y, H:i")) }}
</a></td>
<td>{{ form.state }}</td>
<td>{{ form.instance.reason|truncatechars(50) }}</td>
{% if formset.can_delete %}
<td>{{ form.DELETE }}</td>
{% endif %}
</tr>
{% endfor %}
</table>
<button type="submit">{{ _('Update') }}</button>
</form>
{% else %}
<p>{{ _('There are no requests to approve.') }}</p>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,22 @@
{% extends "base.html" %}
{% block js_media %}
<script type="text/javascript">
$(function () {
$('#id_reason').keydown(function (e) {
if (e.ctrlKey && (e.keyCode === 13 || e.keyCode === 10)) {
$(this).closest('form').submit();
}
});
});
</script>
{% endblock %}
{% block body %}
<form action="" method="post" class="form-area">
{% csrf_token %}
<p><label for="{{ form.reason.id_for_label }}"><b>{{ _('Your reason for joining:') }}</b></label></p>
<p>{{ form.reason }}</p>
<button type="submit">{{ _('Request') }}</button>
</form>
{% endblock %}

View file

@ -0,0 +1,16 @@
<div class="tabs">
<ul>
<li{% if tab == 'pending' %} class="active"{% endif %}>
<a href="{{ url('organization_requests_pending', object.id, object.slug) }}">{{ _('Pending') }}</a>
</li>
<li{% if tab == 'log' %} class="active"{% endif %}>
<a href="{{ url('organization_requests_log', object.id, object.slug) }}">{{ _('Log') }}</a>
</li>
<li{% if tab == 'approved' %} class="active"{% endif %}>
<a href="{{ url('organization_requests_approved', object.id, object.slug) }}">{{ _('Approved') }}</a>
</li>
<li{% if tab == 'rejected' %} class="active"{% endif %}>
<a href="{{ url('organization_requests_rejected', object.id, object.slug) }}">{{ _('Rejected') }}</a>
</li>
</ul>
</div>

View file

@ -0,0 +1,19 @@
{% extends "user/users-table.html" %}
{% block before_point_head %}
{% if is_admin %}
<th class="header"></th>
{% endif %}
{% endblock %}
{% block before_point %}
{% if is_admin %}
<td>
<form action="{{ kick_url }}" method="POST" class="kick-form">
{% csrf_token %}
<input type="hidden" name="user" value="{{ user.id }}">
<a href="#" class="button">{{ _('Kick') }}</a>
</form>
</td>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,33 @@
{% extends "user/base-users.html" %}
{% block users_media %}
<style>
#users-table td:nth-child(2), #users-table th:nth-child(2) {
border-right: none;
text-align: left;
}
.kick-form .button {
margin: -8px 0;
}
</style>
{% if is_admin %}
<style>#users-table td:nth-child(3), #users-table th:nth-child(3) {
border-right: none;
}
</style>
{% endif %}
{% endblock %}
{% block users_js_media %}
<script type="text/javascript">
$(function () {
$('form.kick-form').find('a.button').click(function () {
$(this).parent().submit();
return false;
})
});
</script>
{% endblock %}
{% block users_table %}{% include "organization/users-table.html" %}{% endblock %}

14
templates/pagedown.html Normal file
View file

@ -0,0 +1,14 @@
<div id="{{ id|safe }}-wmd-wrapper" class="wmd-wrapper">
<div class="wmd-panel">
<div id="{{ id|safe }}_wmd_button_bar"></div>
<textarea{{ attrs|safe }}>{{ body }}</textarea>
</div>
{% if show_preview %}
<div id="{{ id|safe }}-preview" data-preview-url="{{ preview_url }}" data-textarea-id="{{ id }}"
data-timeout="{{ preview_timeout or '' }}" class="wmd-panel wmd-preview dmmd-preview {{ extra_classes }}">
<div class="dmmd-preview-update"><i class="fa fa-refresh"></i> Update Preview</div>
<div class="dmmd-preview-content content-description"></div>
</div>
{% endif %}
</div>

View file

@ -0,0 +1,9 @@
<div class="wmd-wrapper" id="{{ id }}-wmd-wrapper">
<div class="wmd-panel">
<div id="{{ id|safe }}_wmd_button_bar"></div>
<textarea{{ attrs|safe }}>{{ body }}</textarea>
</div>
{% if show_preview %}
<div id="{{ id|safe }}_wmd_preview" class="wmd-panel wmd-preview content-description"></div>
{% endif %}
</div>

View file

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% block media %}
<style>
#problem-clone-panel {
position: relative;
margin: 5em auto auto -10em;
top: 40%;
left: 50%;
}
#problem-code-container {
margin: 0.5em 0;
}
#id_code {
width: 100%;
}
ul.errorlist {
list-style-type: none;
padding-left: 0;
text-align: center;
}
</style>
{% endblock %}
{% block body %}
<form id="problem-clone-panel" action="" method="post" class="form-area">
{% csrf_token %}
{% if form.errors %}
<div id="form-errors">
{{ form.code.errors }}
</div>
{% endif %}
<div><label class="inline-header grayed">{{ _('Enter a new code for the cloned problem:') }}</label></div>
<div id="problem-code-container"><span class="fullwidth">{{ form.code }}</span></div>
<hr>
<button style="float:right;" type="submit">{{ _('Clone!') }}</button>
</form>
{% endblock %}

451
templates/problem/data.html Normal file
View file

@ -0,0 +1,451 @@
{% extends "base.html" %}
{% block js_media %}
<script type="text/javascript">
window.valid_files = {{valid_files_json}};
$(function () {
});
</script>
<script type="text/javascript" src="{{ static('libs/jquery-sortable.js') }}"></script>
<script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
<script type="text/javascript">
$(function () {
function update_select2() {
$('tbody:not(.extra-row-body) .type-column select').select2({
minimumResultsForSearch: -1
});
}
update_select2();
function autofill_if_exists($select, file) {
if (!$select.val() && ~window.valid_files.indexOf(file))
$select.val(file).trigger('change');
}
var $table = $('#case-table');
$table.on('add-row', function (e, $tr) {
update_select2();
$tr.find('input').filter('[id$=file]').each(function () {
var $select, val = $(this).replaceWith($select = $('<select>').attr({
id: $(this).attr('id'),
name: $(this).attr('name'),
style: 'width: 100%'
})).val();
$select.select2({
data: window.valid_files,
allowClear: true,
placeholder: ''
}).val(val).trigger('change').on('change', function () {
var val = $select.val();
if (val) {
if ($select.attr('id').endsWith('input_file'))
autofill_if_exists($tr.find('select[id$=output_file]'), val.replace(/in(?!.*?in)/, 'out'));
else
autofill_if_exists($tr.find('select[id$=input_file]'), val.replace(/out(?!.*?out)/, 'in'));
}
});
});
});
var order = 0;
function handle_table_reorder() {
var in_batch = false;
$table.find('tbody:first tr').each(function () {
switch ($(this).attr('data-type')) {
case 'C':
$(this).find('input[id$=points], input[id$=pretest]').toggle(!in_batch);
break;
case 'S':
in_batch = true;
break;
case 'E':
in_batch = false;
}
});
}
function try_parse_json(json) {
try {
return JSON.parse(json);
} catch (e) {
return {};
}
}
function checker_precision($checker) {
var $td = $checker.parent();
var $args = $td.find('input');
var $precision = $('<input>', {
type: 'number',
value: try_parse_json($args.val()).precision || 6,
title: 'precision (decimal digits)',
style: 'width: 4em'
}).change(function () {
if ($checker.val().startsWith('floats'))
$args.val(JSON.stringify({precision: parseInt($(this).val())}));
else
$args.val('');
}).appendTo($td);
$checker.change(function () {
$precision.toggle($checker.val().startsWith('floats')).change();
}).change();
}
function swap_row($a, $b) {
var $a_order = $a.find('input[id$=order]'), $b_order = $b.find('input[id$=order]');
var order = $a_order.val();
$a_order.val($b_order.val());
$b_order.val(order);
$b.after($a);
$a.find('span.order').text($a_order.val());
$b.find('span.order').text($b_order.val());
handle_table_reorder();
}
checker_precision($('#id_problem-data-checker'));
$table.on('add-row', function (e, $tr) {
var $order = $tr.find('input').filter('[id$=order]').attr('type', 'hidden').val(++order);
$order.after($('<span>', {'class': 'order'}).text($order.val()))
.after($('<i>', {'class': 'fa fa-fw fa-lg fa-ellipsis-v'}));
var $opts = $tr.find('input').slice(2, 6);
var $files = $tr.find('select').slice(1, 3);
var $checker = $files.end().last();
$tr.find('select[id$=type]').change(function () {
var $this = $(this), val = $this.val(), disabled;
switch (val) {
case 'S':
case 'E':
disabled = val == 'S';
$opts.toggle(val == 'S');
$files.siblings('.select2').hide();
$checker.toggle(val == 'S');
break;
default:
$opts.toggle(val == 'C');
$files.siblings('.select2').toggle(val == 'C');
$checker.toggle(val == 'C');
var $prevs = $tr.prevAll('tr[data-type=S], tr[data-type=E]');
disabled = $prevs.length && $prevs.get(0).getAttribute('data-type') == 'S';
$tr.find('input[id$=points], input[id$=pretest]').toggle(val == 'C' && !disabled);
}
$tr.attr('data-type', val).nextUntil('tr[data-type=S], tr[data-type=E], tr[data-type=""]')
.find('input[id$=points], input[id$=pretest]').toggle(!disabled);
}).change();
var tooltip_classes = 'tooltipped tooltipped-s';
$tr.find('a.edit-generator-args').mouseover(function () {
switch ($tr.attr('data-type')) {
case 'C':
case 'S':
var $this = $(this).addClass(tooltip_classes);
$this.attr('aria-label', $this.prev().val() || '(none)');
}
}).mouseout(function () {
$(this).removeClass(tooltip_classes).removeAttr('aria-label');
}).featherlight($('.generator-args-editor'), {
beforeOpen: function () {
switch ($tr.attr('data-type')) {
case 'C':
case 'S':
return true;
default:
return false;
}
},
afterOpen: function () {
var $input = this.$currentTarget.prev();
this.$instance.find('.generator-args-editor')
.find('textarea').val($input.val()).end()
.find('.button').click(function () {
$input.val($(this).prev().val());
$.featherlight.current().close();
}).end()
.show();
}
});
checker_precision($tr.find('select[id$=checker]'));
}).find('tbody:first').find('tr').each(function () {
$table.trigger('add-row', [$(this)]);
});
$('form').submit(function () {
$table.find('tbody:first').find('tr').each(function () {
var filled = false;
$(this).find('input, select').each(function () {
var $this = $(this);
if (!$this.attr('name'))
return;
if ($this.attr('type') === 'checkbox')
filled |= $this.is(':checked');
else if (!$this.attr('name').endsWith('order'))
filled |= !!$this.val();
});
if (!filled)
$(this).find('input[id$=order]').val('');
});
});
var $total = $('#id_cases-TOTAL_FORMS');
$('a#add-case-row').click(function () {
var $tr;
$table.find('tbody:first').append($tr = $($table.find('.extra-row-body').html()
.replace(/__prefix__/g, $total.val())));
$tr.find('.type-column select option[value="C"]').attr('selected', true);
$total.val(parseInt($total.val()) + 1);
$table.trigger('add-row', [$tr]);
window.scrollBy(0, $tr.height());
return false;
});
var oldIndex;
$table.sortable({
containerSelector: 'table',
itemPath: '> tbody:first',
itemSelector: 'tr',
handle: 'i.fa-ellipsis-v',
placeholder: '<tr class="placeholder">',
onDragStart: function ($item, container, _super) {
oldIndex = $item.index();
_super($item, container);
},
onDrop: function ($item, container, _super) {
var newIndex = $item.index();
if (newIndex > oldIndex) {
var order = parseInt($item.parent().children().slice(oldIndex, newIndex).each(function () {
var $order = $(this).find('input[id$=order]');
$order.val(parseInt($order.val()) - 1).siblings('span.order').text($order.val());
}).last().after($item).find('input[id$=order]').val());
$item.find('input[id$=order]').val(order + 1).siblings('span.order').text(order + 1);
} else if (newIndex < oldIndex) {
var order = parseInt($item.parent().children().slice(newIndex + 1, oldIndex + 1).each(function () {
var $order = $(this).find('input[id$=order]');
$order.val(parseInt($order.val()) + 1).siblings('span.order').text($order.val());
}).first().before($item).find('input[id$=order]').val());
$item.find('input[id$=order]').val(order - 1).siblings('span.order').text(order - 1);
}
if (newIndex != oldIndex)
handle_table_reorder();
_super($item, container);
}
});
var $controls = $('#column-visible');
var problem = $controls.attr('data-problem');
$controls.find('input').change(function () {
var $this = $(this), suffix = $this.attr('data-suffix'), checked = $this.is(':checked');
$table.find('.' + suffix.replace(/_/g, '-')).toggle(checked);
localStorage.setItem('data-visible:' + problem + ':' + suffix, checked ? '1' : '0')
}).each(function () {
var $this = $(this), suffix = $this.attr('data-suffix'), filled = false;
filled = localStorage.getItem('data-visible:' + problem + ':' + suffix);
if (filled !== null)
filled = filled == '1';
else {
filled = false;
$table.find('[id$=' + suffix + ']').each(function () {
filled |= !!$(this).val();
});
}
$this.prop('checked', filled).trigger('change');
});
});
</script>
{% endblock %}
{% block media %}
<style>
#case-table .select2 {
text-align: initial;
}
.order-column {
width: 1em;
}
.bad-file input, .bad-file .select2-selection {
border-color: red;
}
span.order {
padding-right: 0.5em;
}
body.dragging, body.dragging * {
cursor: move !important;
}
.dragged {
position: absolute;
opacity: 0.5;
z-index: 2000;
}
tr.placeholder {
display: block;
background: red;
position: relative;
margin: 0;
padding: 0;
border: none;
}
tr.placeholder:before {
content: "";
position: absolute;
width: 0;
height: 0;
border: 5px solid transparent;
border-left-color: red;
margin-top: -5px;
left: -5px;
border-right: none;
}
i.fa-ellipsis-v {
cursor: move;
}
.edit-generator-args {
position: relative;
}
.generator-args-editor textarea {
display: block;
width: 100%;
margin-bottom: 0.5em;
height: 8em;
}
.generator-args-editor .button {
display: block;
float: right;
}
#case-table tbody td {
white-space: nowrap;
}
.type-column {
width: 8em;
}
ul.errorlist {
border: 3px red solid;
border-radius: 5px;
padding-top: 1em;
padding-bottom: 1em;
background: #e99;
}
</style>
{% endblock %}
{% block header %}
{% if data_form.instance.has_yml %}
<div class="title-line-action">
[<a href="{{ url('problem_data_init', problem.code) }}">{{ _('View YAML') }}</a>]
</div>
{% endif %}
{% endblock %}
{% block body %}
{% if data_form.instance.feedback %}
<ul class="errorlist">
<li>{{ data_form.instance.feedback }}</li>
</ul>
{% endif %}
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ cases_formset.management_form }}
<table class="table">{{ data_form.as_table() }}</table>
<div id="column-visible" data-problem="{{ problem.code }}">
<strong>{{ _('Show columns:') }}</strong>
<label>
<input type="checkbox" data-suffix="output_prefix">
{{ _('Output prefix') }}
</label>
<label>
<input type="checkbox" data-suffix="output_limit">
{{ _('Output limit') }}
</label>
<label>
<input type="checkbox" data-suffix="checker">
{{ _('Checker') }}
</label>
<label>
<input type="checkbox" data-suffix="generator_args">
{{ _('Generator args') }}
</label>
</div>
<table id="case-table" class="table">
<thead>
<tr>
<th class="order-column"></th>
<th class="type-column">{{ _('Type') }}</th>
<th>{{ _('Input file') }}</th>
<th>{{ _('Output file') }}</th>
<th>{{ _('Points') }}</th>
<th>{{ _('Pretest?') }}</th>
<th class="output-prefix">{{ _('Output prefix') }}</th>
<th class="output-limit">{{ _('Output limit') }}</th>
<th class="checker">{{ _('Checker') }}</th>
<th class="generator-args">{{ _('Generator args') }}</th>
{% if cases_formset.can_delete %}
<th>{{ _('Delete?') }}</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for form in all_case_forms %}
{% if form.non_field_errors() %}
<tr>
<td colspan="{{ 9 + cases_formset.can_delete }}">{{ form.non_field_errors() }}</td>
</tr>
{% endif %}
{% if form.prefix and '__prefix__' in form.prefix %}
</tbody>
<tbody class="extra-row-body" style="display: none">
{% endif %}
<tr data-type="{{ form['type'].value() }}">
<td>{{ form.id }}{{ form.order.errors }}{{ form.order }}</td>
<td class="type-column">{{ form.type.errors }}{{ form.type }}</td>
<td{% if not (form.empty_permitted or form['type'].value() != 'C' or
form['input_file'].value() in valid_files) %} class="bad-file"{% endif %}>
{{ form.input_file.errors }}{{ form.input_file }}
</td>
<td{% if not (form.empty_permitted or form['type'].value() != 'C' or
form['output_file'].value() in valid_files) %} class="bad-file"{% endif %}>
{{ form.output_file.errors }}{{ form.output_file }}
</td>
<td>{{ form.points.errors }}{{ form.points }}</td>
<td>{{ form.is_pretest.errors }}{{ form.is_pretest }}</td>
<td class="output-prefix">{{ form.output_prefix.errors }}{{ form.output_prefix }}</td>
<td class="output-limit">{{ form.output_limit.errors }}{{ form.output_limit }}</td>
<td class="checker">
{{ form.checker.errors }}{{ form.checker }}{{ form.checker_args.errors }}{{ form.checker_args }}
</td>
<td class="generator-args">{{ form.generator_args.errors }}{{ form.generator_args }}
<a href="javascript:void(0)" class="edit-generator-args">
<i class="fa fa-pencil"></i>
{{ _('Edit') }}
</a>
</td>
{% if cases_formset.can_delete %}
<td>{{ form.DELETE }}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" value="{{ _('Submit!') }}" class="button">
<a id="add-case-row" href="#"><i class="fa fa-plus"></i> {{ _('Add new case') }}</a>
</form>
<div style="display: none" class="generator-args-editor"><textarea></textarea><a class="button">Save</a></div>
{% endblock %}

View file

@ -0,0 +1,40 @@
{% extends "common-content.html" %}
{% block content_js_media %}
{% include "comments/media-js.html" %}
{% endblock %}
{% block content_media %}
{% include "comments/media-css.html" %}
{% endblock %}
{% block header %}
<div style="float:right">
{% if perms.judge.change_problem %}
[<a href="{{ url('admin:judge_problem_change', problem.id) }}">{{ _('Edit') }}</a>]
{% endif %}
</div>
{% endblock %}
{% block body %}
<div class="content-description">
{% if not has_solved_problem %}
<div class="alert alert-danger">{{ _('Remember to use this editorial <b>only</b> when stuck, and <b>not to copy-paste code from it</b>. Please be respectful to the problem author and editorialist. <br><br> <b>Submitting an official solution before solving the problem yourself is a bannable offence.</b>') }}</div>
{% endif %}
{% with authors=solution.authors.all() %}
{% if authors %}
<p>Authors: {{ link_users(authors) }}</p>
{% endif %}
{% endwith %}
{{ solution.content|markdown('solution', MATH_ENGINE)|reference|str|safe }}
</div>
<hr>
{% include "comments/list.html" %}
{% endblock %}
{% block bodyend %}
{% if REQUIRE_JAX %}
{% include "mathjax-load.html" %}
{% endif %}
{% include "comments/math.html" %}
{% endblock %}

311
templates/problem/list.html Normal file
View file

@ -0,0 +1,311 @@
{% extends "common-content.html" %}
{% block media %}
<link rel="stylesheet" href="{{ static('libs/nouislider.min.css') }}">
<noscript>
<style>#category, #types {
visibility: visible;
}
</style>
</noscript>
{% if not request.in_contest %}
<style>
#problem-table th {
padding: 0;
}
a.hot-problem-link:hover > .hot-problem-count {
visibility: visible;
}
span.hot-problem-count {
color: #555;
font-size: 0.75em;
vertical-align: super;
visibility: hidden;
padding-left: 0.25em;
position: relative;
}
ul.problem-list {
padding: 0 !important;
}
</style>
{% endif %}
{% endblock %}
{% block js_media %}
<script>
window.point_start = {{point_start}};
window.point_end = {{point_end}};
window.point_values = {{point_values|json|safe}};
</script>
{% compress js %}
<script src="{{ static('libs/nouislider.min.js') }}" type="text/javascript"></script>
<script>
$(function () {
var $form = $('form#filter-form');
var $search = $('#search');
var $category = $('#category');
function prep_form() {
$search.prop('disabled', !$search.val());
$category.prop('disabled', !$category.val());
}
function clean_submit() {
prep_form();
$form.submit();
}
$category.select2().css({'visibility': 'visible'}).change(clean_submit);
$('#types').select2({multiple: 1, placeholder: '{{ _('Filter by type...') }}'})
.css({'visibility': 'visible'});
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
$search.keypress(function (e) {
if (e.keyCode == 13)
$('#go').click();
});
$('#random').click(function (e) {
var action = $form.attr('action');
$form.attr('action', '{{ url('problem_random') }}').attr('target', '_blank').submit();
$form.attr('action', action).attr('target', '');
e.preventDefault();
});
$('#go').click(clean_submit);
$('input#full_text, input#hide_solved, input#show_types').click(function () {
prep_form();
($('<form>').attr('action', window.location.pathname + '?' + $form.serialize())
.append($('<input>').attr('type', 'hidden').attr('name', 'csrfmiddlewaretoken')
.attr('value', $.cookie('csrftoken')))
.attr('method', 'POST').appendTo($('body')).submit());
});
var info_float = $('.info-float');
var container = $('#content-right');
if (window.bad_browser) {
container.css('float', 'right');
} else if (!featureTest('position', 'sticky')) {
fix_div(info_float, 55);
$(window).resize(function () {
info_float.width(container.width());
});
info_float.width(container.width());
}
var intFormatter = {
to: function (value) {
return value;
},
from: function (value) {
return +value;
}
};
var $slider = $('#point-slider');
if ($slider.length) {
var $start = $('#point-start');
var $end = $('#point-end');
noUiSlider.create($slider[0], {
start: [point_start, point_end],
connect: true,
snap: true,
tooltips: [intFormatter, intFormatter],
range: point_values
}).on('change', function (values) {
var start = +values[0], end = +values[1];
$start.prop('disabled', start === point_values.min).val(start);
$end.prop('disabled', end === point_values.max).val(end);
});
}
});
</script>
{% endcompress %}
{% if request.in_contest %}
{% compress js %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$.tablesorter.addParser({
id: 'solvedsort',
is: function (s) {
return false;
},
format: function (s, table, cell, cellIndex) {
return $(cell).attr('solved');
},
type: 'numeric'
});
$('#problem-table').tablesorter({
headers: {
0: {
sorter: 'solvedsort'
}
},
textExtraction: function (node) {
node = $(node);
var text = node.text().replace(/^\s+|\s+$/g, '');
return (node.hasClass('p') ? text.replace(/p$/, '') : text);
}
});
});
</script>
{% endcompress %}
{% endif %}
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% set tab = 'list' %}
{% set title = 'Problems' %}
{% include "problem/problem-list-tabs.html" %}
{% endblock %}
{% block body %}
{% if page_obj.num_pages > 1 %}
<div style="margin-bottom: 7px; margin-top: 11px;">
{% include "list-pages.html" %}
</div>
{% endif %}
<div id="common-content">
{% block before_table %}{% endblock %}
{% if not request.in_contest %}
<div id="content-right" class="problems">
<div class="info-float">
{% include "problem/search-form.html" %}
{% if hot_problems %}
<div class="sidebox">
<h3>{{ _('Hot problems') }} <i class="fa fa-fire"></i></h3>
<div class="sidebox-content">
<ul class="problem-list">{% for problem in hot_problems %}
<li><a href="{{ url('problem_detail', problem.code) }}" class="hot-problem-link">
{{ problem.name }}
</a></li>
{% endfor %}</ul>
</div>
</div>
{% endif %}
</div>
</div>
{% endif %}
<div id="content-left" class="problems">
<table id="problem-table" class="table striped">
<thead>
<tr>
{% if request.in_contest %}
{% if request.user.is_authenticated %}
<th class="solved"><i class="fa fa-check"></i></th>
{% endif %}
<th class="problem">{{ _('Problem') }}</th>
<th class="category">{{ _('Category') }}</th>
{% if show_types %}
<th>{{ _('Types') }}</th>
{% endif %}
<th class="points">{{ _('Points') }}</th>
<th class="users">{{ _('Users') }}</th>
{% else %}
{% if request.user.is_authenticated %}
<th class="solved">
<a href="{{ sort_links.solved }}"><i class="fa fa-check"></i>{{ sort_order.solved }}
</a>
</th>
{% endif %}
<th class="problem">
<a href="{{ sort_links.name }}">{{ _('Problem') }}{{ sort_order.name }}</a>
</th>
<th class="category">
<a href="{{ sort_links.group }}">{{ _('Category') }}{{ sort_order.group }}</a>
</th>
{% if show_types %}
<th>
<a href="{{ sort_links.type }}">{{ _('Types') }}{{ sort_order.type }}</a>
</th>
{% endif %}
<th class="points">
<a href="{{ sort_links.points }}">{{ _('Points') }}{{ sort_order.points }}</a>
</th>
<th class="ac-rate">
<a href="{{ sort_links.ac_rate }}">{{ _('AC %%') }}{{ sort_order.ac_rate }}</a>
</th>
<th class="users">
<a href="{{ sort_links.user_count }}">{{ _('Users') }}{{ sort_order.user_count }}</a>
</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for problem in problems %}
<tr>
{% if request.user.is_authenticated %}
{% if problem.id in completed_problem_ids %}
<td solved="1">
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest %}
<i class="solved-problem-color fa fa-check-circle"></i>
{% else %}
<i class="solved-problem-color fa fa-lock"></i>
{% endif %}
</a>
</td>
{% elif problem.id in attempted_problems %}
<td solved="0">
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest %}
<i class="attempted-problem-color fa fa-minus-circle"></i>
{% else %}
<i class="attempted-problem-color fa fa-lock"></i>
{% endif %}
</a>
</td>
{% else %}
<td solved="-1">
{% if problem.is_public or request.in_contest %}
<i class="unsolved-problem-color fa fa-minus-circle"></i>
{% else %}
<i class="unsolved-problem-color fa fa-lock"></i>
{% endif %}
</td>
{% endif %}
{% endif %}
<td class="problem">
<a href="{{ url('problem_detail', problem.code) }}">{{ problem.i18n_name }}</a>
</td>
<td class="category">{{ problem.group.full_name }}</td>
{% if show_types %}
<td class="types">
{% for type in problem.types_list %}
<span class="type-tag">{{ type }}</span>{% if not loop.last %}, {% endif %}
{% endfor %}
</td>
{% endif %}
<td class="p">{{ problem.points|floatformat }}{% if problem.partial %}p{% endif %}</td>
{% if not request.in_contest %}
<td class="ac-rate">{{ problem.ac_rate|floatformat(1) }}%</td>
{% endif %}
<td class="users">
<a href="{{ url('ranked_submissions', problem.code) }}">
{% if not request.in_contest or not hide_contest_scoreboard %}
{{ problem.user_count }}
{% else %}
???
{% endif %}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
</div>
</div>
<br>
{% endblock %}

Some files were not shown because too many files have changed in this diff Show more