Merge branch 'LQDJudge:master' into master
This commit is contained in:
commit
ff9b86ea13
2370 changed files with 30872 additions and 13914 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
{% block body %}
|
||||
{% if request.organization %}
|
||||
{% cache 3600 'organization_html' request.organization.id MATH_ENGINE %}
|
||||
{% cache 3600 'organization_html' request.organization.id %}
|
||||
{{ request.organization.about|markdown|reference|str|safe }}
|
||||
{% endcache %}
|
||||
{% else %}
|
||||
|
|
|
@ -11,25 +11,25 @@
|
|||
class="like-button actionbar-button {% if pagevote.vote_score(request.profile) == 1 %}voted{% endif %}"
|
||||
onclick="javascript:pagevote_upvote({{ pagevote.id }}, event)">
|
||||
<span class="pagevote-score" id="pagevote-score-{{pagevote.id}}">{{ pagevote.score }}</span>
|
||||
<i class="fa fa-thumbs-o-up" style="font-size: large;"></i>
|
||||
<i class="far fa-thumbs-up" style="font-size: large;"></i>
|
||||
<span class="actionbar-text">{{_("Like")}}</span>
|
||||
</span>
|
||||
<span id="dislike-button-{{pagevote.id}}"
|
||||
class="dislike-button actionbar-button {% if pagevote.vote_score(request.profile) == -1 %}voted{% endif %}"
|
||||
onclick="javascript:pagevote_downvote({{ pagevote.id }}, event)">
|
||||
<i class="fa fa-thumbs-o-down" style="font-size: large;"></i>
|
||||
<i class="far fa-thumbs-down" style="font-size: large;"></i>
|
||||
</span>
|
||||
</span>
|
||||
{% if not hide_actionbar_comment %}
|
||||
<span class="actionbar-block">
|
||||
<span class="actionbar-button actionbar-comment">
|
||||
<i class="fa fa-comment-o" style="font-size: large;"></i>
|
||||
<i class="far fa-comment" style="font-size: large;"></i>
|
||||
<span class="actionbar-text">
|
||||
{{_("Comment")}}
|
||||
</span>
|
||||
{% if comment_count %}
|
||||
{% if all_comment_count %}
|
||||
<span style="margin-left: 0.2em">
|
||||
({{ comment_count }})
|
||||
({{ all_comment_count }})
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
|
@ -37,9 +37,9 @@
|
|||
{% endif %}
|
||||
<span class="actionbar-block">
|
||||
<span id="bookmark-button-{{bookmark.id}}"
|
||||
class="bookmark-button actionbar-button {% if bookmark.get_bookmark(request.profile) == True %} bookmarked {% endif %}"
|
||||
class="bookmark-button actionbar-button {% if bookmark.is_bookmarked_by(request.profile) %} bookmarked {% endif %}"
|
||||
onclick="javascript:bookmark({{ bookmark.id }}, event)">
|
||||
<i class="fa fa-bookmark-o" style="font-size: large;"></i>
|
||||
<i class="far fa-bookmark" style="font-size: large;"></i>
|
||||
<span class="actionbar-text">{{_("Bookmark")}}</span>
|
||||
</span>
|
||||
</span>
|
||||
|
@ -53,7 +53,7 @@
|
|||
{% if actionbar_report_url %}
|
||||
<span class="actionbar-block">
|
||||
<a class="actionbar-button black" href="{{actionbar_report_url}}">
|
||||
<i class="fa fa-flag-o" style="font-size: large;"></i>
|
||||
<i class="fa fa-flag" style="font-size: large;"></i>
|
||||
<span class="actionbar-text">{{_("Report")}}</span>
|
||||
</a>
|
||||
</span>
|
||||
|
|
|
@ -50,10 +50,9 @@
|
|||
<link rel="stylesheet" type="text/css" href="{{ static('markdown.css') }}">
|
||||
{% 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 %}
|
||||
{% if INLINE_FONTAWESOME %}
|
||||
<link rel="stylesheet" href="{{ static('fontawesome/css/all.min.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') }}">
|
||||
|
@ -70,10 +69,8 @@
|
|||
{% endif %}
|
||||
{% block media %}{% endblock %}
|
||||
{% if use_darkmode %}
|
||||
{% compress css %}
|
||||
<link rel="stylesheet" href="{{ static('darkmode.css') }}">
|
||||
<link rel="stylesheet" href="{{ static('darkmode-svg.css') }}">
|
||||
{% endcompress %}
|
||||
<link rel="stylesheet" href="{{ static('darkmode.css') }}">
|
||||
<link rel="stylesheet" href="{{ static('darkmode-svg.css') }}">
|
||||
{% endif %}
|
||||
|
||||
<noscript>
|
||||
|
@ -92,10 +89,19 @@
|
|||
@media(min-width: 800px) {
|
||||
#page-container {
|
||||
background: {{request.profile.css_background|safe}};
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
{% if not INLINE_JQUERY %}
|
||||
<script src="{{ JQUERY_JS }}"></script>
|
||||
{% else %}
|
||||
<script src="{{ static('libs/jquery-3.4.1.min.js') }}"></script>
|
||||
{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
<svg width="0" height="0" style="display: block">
|
||||
|
@ -113,11 +119,11 @@
|
|||
<li>
|
||||
<a href="{{ node.path }}" id="fa-icon-links" class="normal-text nav-{{ node.key }}{% if node.key in nav_tab %} active{% endif %}">
|
||||
<span class="nav-fa-icon{{'-active' if node.key in nav_tab else''}}">
|
||||
{% if node.key == "problems" %} <i class="fa fa-pencil"></i> {% endif %}
|
||||
{% if node.key == "problems" %} <i class="fa fa-puzzle-piece"></i> {% endif %}
|
||||
{% if node.key == "submit" %} <i class="fa fa-code"></i> {% endif %}
|
||||
{% if node.key == "user" %} <i class="fa fa-user"></i> {% endif %}
|
||||
{% if node.key == "contest" %} <i class="fa fa-graduation-cap"></i> {% endif %}
|
||||
{% if node.key == "group" %} <i class="fa fa-group"></i> {% endif %}
|
||||
{% if node.key == "contest" %} <i class="fa fa-ranking-star"></i> {% endif %}
|
||||
{% if node.key == "group" %} <i class="fa fa-building-columns"></i> {% endif %}
|
||||
{% if node.key == "about" %} <i class="fa fa-at"></i> {% endif %}
|
||||
</span>
|
||||
{{ user_trans(node.label) }}
|
||||
|
@ -135,7 +141,7 @@
|
|||
<div style="display: flex; font-size: larger; align-items: center; height: 100%; gap: 1em;">
|
||||
{% if request.user.is_authenticated %}
|
||||
<span title="{{_('Chat')}}">
|
||||
<a id="chat-icon" href="{{ url('chat', '') }}" class="fa fa-wechat navbar-icon" aria-hidden="true" style="font-size: 22.5px;">
|
||||
<a id="chat-icon" href="{{ url('chat', '') }}" class="fab fa-weixin navbar-icon" aria-hidden="true" style="font-size: 22.5px;">
|
||||
{% set unread_chat = request.profile.count_unread_chat_boxes %}
|
||||
{% if unread_chat %}
|
||||
<sub class="unread_boxes">{{unread_chat}}</sub>
|
||||
|
@ -145,7 +151,7 @@
|
|||
|
||||
{% set unseen_cnt = request.profile.count_unseen_notifications %}
|
||||
<span title="{{_('Notification')}}" class="{{ 'notification-open' if unseen_cnt > 0 }}">
|
||||
<a href="{{ url('notification') }}" class="fa fa-bell-o navbar-icon" id="notification" aria-hidden="true" style="font-size: 22.5px;">
|
||||
<a href="{{ url('notification') }}" class="far fa-bell navbar-icon" id="notification" aria-hidden="true" style="font-size: 22.5px;">
|
||||
{% if unseen_cnt > 0 %}
|
||||
<sub class="unread_boxes">{{unseen_cnt}}</sub>
|
||||
{% endif %}
|
||||
|
@ -168,43 +174,48 @@
|
|||
{{ language.name_local }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="popper-arrow" data-popper-arrow></div>
|
||||
</div>
|
||||
</span>
|
||||
<span title="{{_('Dark Mode')}}">
|
||||
<a class="fa fa-moon-o navbar-icon black" id="nav-darkmode-icon" aria-hidden="true" href="?darkmode=1" style="font-size: 22.5px;"></a>
|
||||
<a class="far fa-moon navbar-icon black" id="nav-darkmode-icon" aria-hidden="true" href="?darkmode=1" style="font-size: 22.5px;"></a>
|
||||
</span>
|
||||
{% if request.user.is_authenticated %}
|
||||
<span id="user-links">
|
||||
<img src="{{ gravatar(request.profile, 32) }}" height="24" width="24">
|
||||
<img class="user-img" src="{{ gravatar(request.profile, 32) }}" height="24" width="24">
|
||||
<i class="fa fa-angle-down" style="font-size: 18px; padding-top: 8px;"></i>
|
||||
</span>
|
||||
<div class="dropdown" id="userlink_dropdown" role="tooptip">
|
||||
<div class="popper-arrow" data-popper-arrow></div>
|
||||
<a href="{{ url('user_page') }}">
|
||||
<div class="dropdown-item">{{ _('Profile') }}</div>
|
||||
<div class="dropdown-item"><i class="fa fa-user"></i> {{ _('Profile') }}</div>
|
||||
</a>
|
||||
{% if request.user.is_staff or request.user.is_superuser %}
|
||||
<a href="{{ url('admin:index') }}">
|
||||
<div class="dropdown-item">{{ _('Admin') }}</div>
|
||||
<div class="dropdown-item"><i class="fa fa-user-shield"></i> {{ _('Admin') }}</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if request.user.is_superuser %}
|
||||
<a href="{{ url('internal_problem') }}">
|
||||
<div class="dropdown-item">{{ _('Internal') }}</div>
|
||||
<div class="dropdown-item"><i class="fa fa-circle-info"></i> {{ _('Internal') }}</div>
|
||||
</a>
|
||||
<a href="{{ url('site_stats') }}">
|
||||
<div class="dropdown-item">{{ _('Stats') }}</div>
|
||||
<div class="dropdown-item"><i class="fa fa-chart-pie"></i> {{ _('Stats') }}</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{{ url('user_bookmark') }}">
|
||||
<div class="dropdown-item"><i class="fa fa-bookmark"></i> {{ _('Bookmarks') }}</div>
|
||||
</a>
|
||||
<a href="{{ url('user_edit_profile') }}">
|
||||
<div class="dropdown-item">{{ _('Edit profile') }}</div>
|
||||
<div class="dropdown-item"><i class="fa fa-gear"></i> {{ _('Settings') }}</div>
|
||||
</a>
|
||||
{% if request.user.is_impersonate %}
|
||||
<a href="{{ url('impersonate-stop') }}">
|
||||
<div class="dropdown-item">Stop impersonating</div>
|
||||
<div class="dropdown-item"><i class="fa fa-eye"></i> {{_('Stop impersonating')}}</div>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="#" id="logout" class="red">
|
||||
<div class="dropdown-item">
|
||||
<div class="dropdown-item"><i class="fa fa-right-from-bracket"></i>
|
||||
{{ _('Log out') }}
|
||||
<form id="logout-form" action="{{ url('auth_logout') }}" method="POST">
|
||||
{% csrf_token %}
|
||||
|
@ -242,9 +253,9 @@
|
|||
</div>
|
||||
<div id="contest-info-toggle" class="{{'contest-info-toggle-mode-on' if request.contest_mode else 'contest-info-toggle-mode-off'}}">
|
||||
{% if request.contest_mode %}
|
||||
<i class="fa fa-toggle-on white"></i> {{_('Compete')}}
|
||||
<i class="fa fa-toggle-on white"></i> {{_('In contest')}}
|
||||
{% else %}
|
||||
<i class="fa fa-toggle-off white"></i> {{_('General')}}
|
||||
<i class="fa fa-toggle-off white"></i> {{_('Out contest')}}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -272,15 +283,9 @@
|
|||
<div id="announcement">{{ i18n_config.announcement|safe }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if not INLINE_JQUERY %}
|
||||
<script src="{{ JQUERY_JS }}"></script>
|
||||
{% endif %}
|
||||
<script src="https://unpkg.com/@popperjs/core@2"></script>
|
||||
{% 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/popper.min.js') }}"></script>
|
||||
<script src="{{ static('libs/jquery-cookie.js') }}"></script>
|
||||
<script src="{{ static('libs/jquery-taphold.js') }}"></script>
|
||||
<script src="{{ static('libs/jquery.unveil.js') }}"></script>
|
||||
|
@ -290,6 +295,7 @@
|
|||
{% include "extra_js.html" %}
|
||||
<script src="{{ static('common.js') }}"></script>
|
||||
<script src="{{ static('libs/clipboard/tooltip.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
|
||||
<script>
|
||||
moment.locale('{{ LANGUAGE_CODE }}');
|
||||
$(function () {
|
||||
|
@ -373,15 +379,12 @@
|
|||
{{ 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 %}
|
||||
|
||||
<div id="extra_js">
|
||||
{% block extra_js %}{% endblock %}
|
||||
</div>
|
||||
{% block bodyend %}{% endblock %}
|
||||
<script src="{{ static('katex_config.js') }}"></script>
|
||||
{% include "katex-load.html" %}
|
||||
{% block footer %}
|
||||
<footer>
|
||||
<span id="footer-content">
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<div class="post-full">
|
||||
<div class="post-title">{{ title }}</div>
|
||||
<div class="time">
|
||||
{% with authors=post.authors.all() %}
|
||||
{% with authors=post.get_authors() %}
|
||||
{% if authors %}
|
||||
<span class="post-authors">{{ link_users(authors) }}</span>
|
||||
{% endif %}
|
||||
|
@ -30,14 +30,14 @@
|
|||
{% if post.is_editable_by(request.user) %}
|
||||
<span> [<a href="{{ url('admin:judge_blogpost_change', post.id) }}">{{ _('Edit') }}</a>]</span>
|
||||
{% endif %}
|
||||
{% if valid_user_to_show_edit %}
|
||||
{% for org in valid_org_to_show_edit %}
|
||||
{% if editable_orgs %}
|
||||
{% for org in editable_orgs %}
|
||||
<span> [<a href="{{ url('edit_organization_blog', org.id , org.slug , post.id) }}">{{ _('Edit in') }} {{org.slug}}</a>]</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="body content-description">
|
||||
{% cache 86400 'post_content' post.id MATH_ENGINE %}
|
||||
{% cache 86400 'post_content' post.id %}
|
||||
{{ post.content|markdown|reference|str|safe}}
|
||||
{% endcache %}
|
||||
</div>
|
||||
|
@ -49,8 +49,5 @@
|
|||
|
||||
{% block bodyend %}
|
||||
{{ super() }}
|
||||
{% if REQUIRE_JAX %}
|
||||
{% include "mathjax-load.html" %}
|
||||
{% endif %}
|
||||
{% include "comments/math.html" %}
|
||||
{% endblock %}
|
|
@ -1,35 +1,32 @@
|
|||
{% for post in posts%}
|
||||
{% for post in posts %}
|
||||
<section class="{% if post.sticky %}sticky {% endif %}blog-box">
|
||||
{% if post.is_organization_private and show_organization_private_icon %}
|
||||
<div style="margin-bottom: 1em; display: flex;">
|
||||
{% for org in post.organizations.all() %}
|
||||
{% include "organization/tag.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div style="margin-bottom: 0.5em">
|
||||
<span class="time">
|
||||
{% with authors=post.authors.all() %}
|
||||
<span class="post-content-header time">
|
||||
{% with authors=post.get_authors() %}
|
||||
{%- if authors -%}
|
||||
<img src="{{gravatar(authors[0])}}" style="width: 1.5em; border-radius: 50%; margin-bottom: -0.3em">
|
||||
<span class="user-img" style="width: 1.5em; height: 1.5em">
|
||||
<img src="{{gravatar(authors[0])}}" loading="lazy">
|
||||
</span>
|
||||
<span class="post-authors">{{ link_users(authors) }}</span>
|
||||
{%- endif -%}
|
||||
{% endwith %}
|
||||
•
|
||||
{{ relative_time(post.publish_on, abs=_('on {time}'), rel=_('{time}')) -}}
|
||||
{{ relative_time(post.publish_on) }}
|
||||
{%- if post.sticky %} •
|
||||
<i title="Sticky" class="fa fa-star fa-fw"></i>{% endif -%}
|
||||
{% if post.is_organization_private and show_organization_private_icon %}
|
||||
•
|
||||
<span>
|
||||
{% for org in post.organizations.all() %}
|
||||
<span class="organization-tag" style="display: inherit;">
|
||||
<a href="{{ org.get_absolute_url() }}">
|
||||
<i class="fa fa-lock"></i> {{ org.name }}
|
||||
</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
<span style="float: right">
|
||||
<a href="{{ url('blog_post', post.id, post.slug) }}#comments" class="blog-comment-count-link">
|
||||
<i class="fa fa-comments blog-comment-icon"></i>
|
||||
<span class="blog-comment-count">
|
||||
{{- post.comments.filter(hidden=False).count() or 0 -}}
|
||||
{{ comment_count(post) }}
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
|
@ -39,8 +36,8 @@
|
|||
</h2>
|
||||
<div class="blog-description">
|
||||
<div class="summary content-description">
|
||||
{% cache 86400 'post_summary' post.id %}
|
||||
{{ post.summary|default(post.content, true)|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% cache 86400 'post_content' post.id %}
|
||||
{{ post.content|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% endcache %}
|
||||
</div>
|
||||
<div class="show-more"> {{_("...More")}} </div>
|
||||
|
|
|
@ -2,19 +2,20 @@
|
|||
{% block three_col_media %}
|
||||
{% include "blog/media-css.html" %}
|
||||
<style>
|
||||
@media (max-width: 799px) {
|
||||
.title {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
.time {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.no-clarifications-message {
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.org-logo {
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.organization-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -100,8 +101,9 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include 'profile-table.html' %}
|
||||
{% include 'contests-countdown.html' %}
|
||||
{% include 'recent-organization.html' %}
|
||||
{% include 'top-users.html' %}
|
||||
{% include 'recent-organization.html' %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -5,9 +5,6 @@
|
|||
{% block title %} {{_('Chat Box')}} {% endblock %}
|
||||
{% block js_media %}
|
||||
|
||||
{% if REQUIRE_JAX %}
|
||||
{% include "mathjax-load.html" %}
|
||||
{% endif %}
|
||||
{% include "comments/math.html" %}
|
||||
<script type="text/javascript" src="{{ static('event.js') }}"></script>
|
||||
<script type="module" src="https://unpkg.com/emoji-picker-element@1"></script>
|
||||
|
@ -82,13 +79,15 @@
|
|||
{% include 'chat/user_online_status.html' %}
|
||||
</div>
|
||||
<div id="chat-box">
|
||||
<img src="{{static('loading.gif')}}" id="loader" style="display: none;">
|
||||
<span id="loader" style="font-size: 2em; display: none;">
|
||||
<i class="fa fa-spinner fa-pulse"></i>
|
||||
</span>
|
||||
<ul id="chat-log">
|
||||
{% include 'chat/message_list.html' %}
|
||||
</ul>
|
||||
</div>
|
||||
<div id="chat-input-container">
|
||||
<textarea maxlength="5000" id="chat-input" placeholder="{{_('Enter your message')}}"></textarea>
|
||||
<textarea maxlength="{{5000 if room else 200}}" id="chat-input" placeholder="{{_('Enter your message')}}"></textarea>
|
||||
<div class="chat-input-icon" id="emoji-button" href="#" title="{{_('Emoji')}}"><i class="icofont-slightly-smile"></i>
|
||||
</div>
|
||||
<div class="chat-input-icon" id="submit-button">
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
.profile-pic {
|
||||
height: 2.6em;
|
||||
width: 2.6em;
|
||||
border-radius: 50%;
|
||||
margin-top: 0.1em;
|
||||
float: left;
|
||||
}
|
||||
|
@ -115,7 +114,17 @@
|
|||
#setting {
|
||||
position: relative;
|
||||
}
|
||||
#setting-button {
|
||||
.setting-button {
|
||||
height: 2.3em;
|
||||
width: 2.5em;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding-top: 2px;
|
||||
}
|
||||
.user-setting-button {
|
||||
height: 2.3em;
|
||||
width: 2.5em;
|
||||
border-radius: 50%;
|
||||
|
@ -217,9 +226,15 @@
|
|||
.active-span {
|
||||
display: none;
|
||||
}
|
||||
#chat-area {
|
||||
display: none;
|
||||
}
|
||||
{% if not room %}
|
||||
#chat-area {
|
||||
display: none;
|
||||
}
|
||||
{% else %}
|
||||
.chat-left-panel {
|
||||
display: none;
|
||||
}
|
||||
{% endif %}
|
||||
.back-button {
|
||||
margin-right: 1em;
|
||||
font-size: 1.5em;
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
let isMobile = window.matchMedia("only screen and (max-width: 799px)").matches;
|
||||
|
||||
function load_next_page(last_id, refresh_html=false) {
|
||||
if (refresh_html) {
|
||||
window.lock = true;
|
||||
$('#chat-log').html('');
|
||||
$('#loader').show();
|
||||
}
|
||||
var param = {
|
||||
'last_id': last_id,
|
||||
'only_messages': true,
|
||||
|
@ -9,12 +14,11 @@
|
|||
$.get("{{ url('chat', '') }}" + window.room_id, param)
|
||||
.fail(function() {
|
||||
console.log("Fail to load page, last_id = " + last_id);
|
||||
window.lock = false;
|
||||
})
|
||||
.done(function(data) {
|
||||
if (refresh_html) {
|
||||
$('#chat-log').html('');
|
||||
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
||||
window.lock = true;
|
||||
}
|
||||
var time = refresh_html ? 0 : 200;
|
||||
|
||||
|
@ -32,8 +36,7 @@
|
|||
$('#chat-log').prepend(data);
|
||||
}
|
||||
|
||||
register_time($('.time-with-rel'));
|
||||
merge_authors();
|
||||
postProcessMessages();
|
||||
|
||||
if (!refresh_html) {
|
||||
$chat_box.scrollTop(scrollTopOfBottom($chat_box) - lastMsgPos);
|
||||
|
@ -47,6 +50,13 @@
|
|||
})
|
||||
}
|
||||
|
||||
function postProcessMessages() {
|
||||
register_time($('.time-with-rel'));
|
||||
renderKatex();
|
||||
populateCopyButton();
|
||||
merge_authors();
|
||||
}
|
||||
|
||||
function scrollTopOfBottom(container) {
|
||||
return container[0].scrollHeight - container.innerHeight()
|
||||
}
|
||||
|
@ -64,7 +74,7 @@
|
|||
}
|
||||
})}
|
||||
|
||||
function refresh_status() {
|
||||
function refresh_status(refresh_chat_info=false) {
|
||||
$.get("{{url('online_status_ajax')}}")
|
||||
.fail(function() {
|
||||
console.log("Fail to get online status");
|
||||
|
@ -78,6 +88,7 @@
|
|||
register_toggle($(this));
|
||||
});
|
||||
register_click_space();
|
||||
register_setting(false);
|
||||
color_selected_room();
|
||||
}
|
||||
})
|
||||
|
@ -86,6 +97,10 @@
|
|||
'user': window.other_user_id,
|
||||
};
|
||||
|
||||
if (refresh_chat_info) {
|
||||
$('#chat-info').html('');
|
||||
}
|
||||
|
||||
$.get("{{url('user_online_status_ajax')}}", data)
|
||||
.fail(function() {
|
||||
console.log("Fail to get user online status");
|
||||
|
@ -93,7 +108,7 @@
|
|||
.done(function(data) {
|
||||
$('#chat-info').html(data);
|
||||
register_time($('.time-with-rel'));
|
||||
register_setting();
|
||||
register_setting(true);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -102,9 +117,7 @@
|
|||
|
||||
$('#chat-log').append($data);
|
||||
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
||||
register_time($('.time-with-rel'));
|
||||
MathJax.typeset();
|
||||
merge_authors();
|
||||
postProcessMessages();
|
||||
}
|
||||
|
||||
function add_new_message(message, room, is_self_author) {
|
||||
|
@ -157,10 +170,8 @@
|
|||
else {
|
||||
add_new_message(message, room, true);
|
||||
}
|
||||
MathJax.typeset();
|
||||
register_time($('.time-with-rel'));
|
||||
remove_unread_current_user();
|
||||
merge_authors();
|
||||
postProcessMessages();
|
||||
},
|
||||
error: function (data) {
|
||||
console.log('Fail to check message');
|
||||
|
@ -219,7 +230,6 @@
|
|||
if ($("#chat-input").val().trim()) {
|
||||
$('#chat-input-container').height('auto');
|
||||
var body = $('#chat-input').val().trim();
|
||||
// body = body.split('\n').join('\n\n');
|
||||
|
||||
var message = {
|
||||
body: body,
|
||||
|
@ -228,12 +238,16 @@
|
|||
};
|
||||
|
||||
$('#chat-input').val('');
|
||||
$('#chat-input').css('height', '70%');
|
||||
|
||||
add_message_from_template(body, message.tmp_id);
|
||||
|
||||
$.post("{{ url('post_chat_message') }}", message)
|
||||
.fail(function(res) {
|
||||
console.log('Fail to send message');
|
||||
var $body = $('#message-text-'+ message.tmp_id);
|
||||
$body.css('text-decoration', 'line-through');
|
||||
$body.css('background', 'red');
|
||||
})
|
||||
.done(function(res, status) {
|
||||
$('#empty_msg').hide();
|
||||
|
@ -295,9 +309,11 @@
|
|||
history.replaceState(null, '', "{{url('chat', '')}}" + window.room_id);
|
||||
load_next_page(null, true);
|
||||
update_last_seen();
|
||||
refresh_status();
|
||||
$('#chat-input').focus();
|
||||
refresh_status(true);
|
||||
|
||||
show_right_panel();
|
||||
$('#chat-input').focus();
|
||||
$('#chat-input').val('').trigger('input');
|
||||
}
|
||||
window.lock_click_space = true;
|
||||
if (encrypted_user) {
|
||||
|
@ -307,6 +323,7 @@
|
|||
window.other_user_id = data.other_user_id;
|
||||
color_selected_room();
|
||||
callback();
|
||||
$('#chat-input').attr('maxlength', 5000);
|
||||
})
|
||||
.fail(function() {
|
||||
console.log('Fail to get_or_create_room');
|
||||
|
@ -317,6 +334,7 @@
|
|||
window.other_user_id = '';
|
||||
color_selected_room();
|
||||
callback();
|
||||
$('#chat-input').attr('maxlength', 200);
|
||||
}
|
||||
window.lock_click_space = false;
|
||||
}
|
||||
|
@ -363,18 +381,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
function register_setting() {
|
||||
$('#setting-button').on('click', function() {
|
||||
$('#setting-content').toggle();
|
||||
function register_setting(is_on_user_status_bar) {
|
||||
let $setting_button = is_on_user_status_bar ? $('.user-setting-button') : $('.setting-button');
|
||||
$setting_button.on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
$('.setting-content').not($(this).siblings('.setting-content')).hide();
|
||||
$(this).siblings('.setting-content').toggle();
|
||||
});
|
||||
$('#setting-content li').on('click', function() {
|
||||
$(this).children('a')[0].click();
|
||||
})
|
||||
$('#setting-content a').on('click', function() {
|
||||
$('.setting-content a').on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
var href = $(this).attr('href');
|
||||
href += '?next=' + window.location.pathname;
|
||||
$(this).attr('href', href);
|
||||
})
|
||||
$(document).on('click', function() {
|
||||
$('.setting-content').hide();
|
||||
});
|
||||
}
|
||||
$(function() {
|
||||
$('#loader').hide();
|
||||
|
@ -456,12 +478,13 @@
|
|||
|
||||
const button = document.querySelector('#emoji-button');
|
||||
const tooltip = document.querySelector('.tooltip');
|
||||
Popper.createPopper(button, tooltip, {
|
||||
placement: isMobile ? 'auto-end' : 'left-end',
|
||||
const popper = Popper.createPopper(button, tooltip, {
|
||||
placement: isMobile ? 'auto-end' : 'left',
|
||||
});
|
||||
|
||||
function toggleEmoji() {
|
||||
tooltip.classList.toggle('shown')
|
||||
tooltip.classList.toggle('shown');
|
||||
popper.update();
|
||||
}
|
||||
$('#emoji-button').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
@ -500,7 +523,9 @@
|
|||
$('#search-handle').select2({
|
||||
placeholder: '<i class="fa fa-search"></i> {{ _('Search by handle...') }}',
|
||||
ajax: {
|
||||
url: '{{ url('chat_user_search_select2_ajax') }}'
|
||||
url: '{{ url('chat_user_search_select2_ajax') }}',
|
||||
delay: 250,
|
||||
cache: true,
|
||||
},
|
||||
minimumInputLength: 1,
|
||||
escapeMarkup: function (markup) {
|
||||
|
@ -547,7 +572,8 @@
|
|||
characterData: false
|
||||
})
|
||||
}
|
||||
register_setting();
|
||||
register_setting(true);
|
||||
register_setting(false);
|
||||
color_selected_room();
|
||||
|
||||
$('#chat-input').on('input', function() {
|
||||
|
@ -560,5 +586,8 @@
|
|||
});
|
||||
|
||||
$('#submit-button').on('click', submit_chat);
|
||||
register_copy_clipboard($("#chat-input"), () => {
|
||||
$('#chat-input').trigger('input');
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -1,6 +1,6 @@
|
|||
<li class="message" id="message-{{ message.id }}" message-id="{{ message.id }}">
|
||||
<a href="{{ url('user_page', message.author.username) }}">
|
||||
<img src="{{ gravatar(message.author, 135) }}" class="profile-pic">
|
||||
<img loading="lazy" src="{{ gravatar(message.author, 135) }}" class="profile-pic user-img">
|
||||
</a>
|
||||
<div class="body-message">
|
||||
<div class="user-time">
|
||||
|
@ -23,7 +23,7 @@
|
|||
{{_('Mute')}}
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="message-text message-text-other">
|
||||
<div class="message-text message-text-other" id="message-text-{{ message.id }}">
|
||||
{{message.body|markdown(lazy_load=False)|reference|str|safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,4 +6,5 @@
|
|||
{% endfor %}
|
||||
{% else %}
|
||||
<center id="empty_msg">{{_('You are connect now. Say something to start the conversation.')}}</center>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<li class="status-row" id="lobby_row">
|
||||
<div class="status-container">
|
||||
<img src="{{ static('icons/logo.png') }}" style="height:1.3em">
|
||||
<img loading="lazy" src="{{ static('icons/icon.svg') }}" style="height:32px">
|
||||
</div>
|
||||
<span style="padding-left:0.5em">
|
||||
<b>{{_('Lobby')}}</b>
|
||||
|
@ -23,10 +23,9 @@
|
|||
{% for user in section.user_list %}
|
||||
<li class="click_space status-row" id="click_space_{{user.user.id}}" value="{{user.url}}">
|
||||
<div class="status-container">
|
||||
<img src="{{ gravatar(user.user, 135) }}" class="status-pic">
|
||||
<img loading="lazy" src="{{ gravatar(user.user, 135) }}" class="status-pic user-img">
|
||||
<svg style="position:absolute;" height="32" width="32">
|
||||
<circle class="status-circle"
|
||||
fill="{{'green' if user.is_online else 'red'}}"/>
|
||||
<circle class="status-circle" fill="{{'green' if user.is_online else 'red'}}"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="status-user">
|
||||
|
@ -44,8 +43,19 @@
|
|||
{{user.unread_count}}
|
||||
</span>
|
||||
{% endif %}
|
||||
<div style="margin-right: 0.3em; position: relative;">
|
||||
<div class="control-button small setting-button">
|
||||
<i class="fa fa-ellipsis-h"></i>
|
||||
</div>
|
||||
<div class="setting-content">
|
||||
<a href="{{url('toggle_ignore', user.user.id)}}" class="red">
|
||||
{{_('Ignore')}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
</div>
|
||||
{% if other_user %}
|
||||
<div class="status-container" style="height: 3em; width: 3em;">
|
||||
<img src="{{ gravatar(other_user, 135) }}" class="info-pic">
|
||||
<img src="{{ gravatar(other_user, 135) }}" class="info-pic user-img">
|
||||
<svg style="position:absolute; height:100%; width: 100%; transform: rotate(180deg);" >
|
||||
<circle class="info-circle"
|
||||
fill="{{'green' if other_online else 'red'}}"/>
|
||||
|
@ -11,7 +11,7 @@
|
|||
</div>
|
||||
{% else %}
|
||||
<div class="status-container" style="height: 3em;">
|
||||
<img src="{{ static('icons/logo.png') }}" class="info-pic" style="border-radius: 0px;">
|
||||
<img src="{{ static('icons/icon.svg') }}" class="info-pic" style="border-radius: 0px;">
|
||||
</div>
|
||||
{% endif %}
|
||||
<span class="info-name username">
|
||||
|
@ -27,22 +27,20 @@
|
|||
{% endif %}
|
||||
|
||||
{% if other_user %}
|
||||
<span style="margin-right: 0.3em" id="setting">
|
||||
<div class="control-button small" style="" id="setting-button">
|
||||
<div style="margin-right: 0.3em; position: relative;">
|
||||
<div class="control-button small user-setting-button">
|
||||
<i class="fa fa-ellipsis-h"></i>
|
||||
</div>
|
||||
<div id="setting-content">
|
||||
<li>
|
||||
<a href="{{url('toggle_ignore', other_user.id)}}" class=" {{'green' if is_ignored else 'red'}}">
|
||||
{% if is_ignored %}
|
||||
{{_('Unignore')}}
|
||||
{% else %}
|
||||
{{_('Ignore')}}
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
<div class="setting-content">
|
||||
<a href="{{url('toggle_ignore', other_user.id)}}" class=" {{'green' if is_ignored else 'red'}}">
|
||||
{% if is_ignored %}
|
||||
{{_('Unignore')}}
|
||||
{% else %}
|
||||
{{_('Ignore')}}
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="active-span">{{online_count}} {{_('users are online')}}</span>
|
||||
{% endif %}
|
|
@ -1,5 +1,5 @@
|
|||
{% for node in mptt_tree(comment_list) recursive %}
|
||||
<li id="comment-{{ node.id }}" data-revision="{{ node.revisions - 1 }}" data-max-revision="{{ node.revisions - 1 }}"
|
||||
<li id="comment-{{ node.id }}" data-revision="{{ node.revision_count - 1 }}" data-max-revision="{{ node.revision_count - 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">
|
||||
|
@ -24,21 +24,16 @@
|
|||
</div>
|
||||
<div class="detail">
|
||||
<div class="header">
|
||||
{% with author=node.author, user=node.author.user %}
|
||||
<a href="{{ url('user_page', user.username) }}" class="user comment-img">
|
||||
<img src="{{ gravatar(author, 135) }}" class="gravatar">
|
||||
</a>
|
||||
{% endwith %}
|
||||
{{ link_user(node.author) }},
|
||||
{{ link_user(node.author_id, show_image=True) }}
|
||||
{{ relative_time(node.time, abs=_('{time}'), rel=_('{time}')) }}
|
||||
<span class="comment-spacer"></span>
|
||||
<span class="comment-operation">
|
||||
{% if node.revisions > 1 %}
|
||||
{% if node.revision_count > 1 %}
|
||||
<span class="comment-edits">
|
||||
<a href="javascript:show_revision({{ node.id }}, -1)" class="previous-revision">←</a>
|
||||
<span class="comment-edit-text">
|
||||
{% if node.revisions > 2 %}
|
||||
{% trans edits=node.revisions - 1 %}edit {{ edits }}{% endtrans %}
|
||||
{% if node.revision_count > 2 %}
|
||||
{% trans edits=node.revision_count - 1 %}edit {{ edits }}{% endtrans %}
|
||||
{% else %}
|
||||
{{ _('edited') }}
|
||||
{% endif %}
|
||||
|
@ -53,10 +48,9 @@
|
|||
<i class="fa fa-link fa-fw"></i>
|
||||
</a>
|
||||
{% if profile and not comment_lock %}
|
||||
{% set can_edit = node.author.id == profile.id and not profile.mute %}
|
||||
{% 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">
|
||||
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}" href="#" title="{{ _('Edit') }}" class="edit-link">
|
||||
<i class="fa fa-pencil fa-fw"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
|
@ -69,9 +63,9 @@
|
|||
<a href="javascript:reply_comment({{ 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>
|
||||
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}" href="#" 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>
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
{{ comment.page_title }}
|
||||
</a>
|
||||
</h3>
|
||||
{% with author=comment.author %}
|
||||
{% if author %}
|
||||
{% with author_id=comment.author_id %}
|
||||
{% if author_id %}
|
||||
<div class="problem-feed-info-entry">
|
||||
<i class="fa fa-pencil-square-o fa-fw"></i>
|
||||
<span class="pi-value">{{ link_user(author) }}</span>
|
||||
<i class="far fa-pen-to-square"></i>
|
||||
<span class="pi-value">{{ link_user(author_id) }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
|
|
@ -1,36 +1,8 @@
|
|||
<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('mathjax3_config.js') }}',
|
||||
dataType: "script",
|
||||
cache: true,
|
||||
success: function () {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js',
|
||||
dataType: "script",
|
||||
cache: true,
|
||||
success: function () {
|
||||
mathjax_pagedown($);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
let loading_gif = "<img src=\"{{static('loading.gif')}}\" style=\"height: 3em; margin-bottom: 3px\" class=\"loading\">";
|
||||
let loading_gif = "<i class=\"fa fa-spinner fa-pulse loading\" style=\"font-size: 1.5em; margin-bottom: 1em;\"></i>";
|
||||
window.reply_comment = function (parent) {
|
||||
var $comment_reply = $('#comment-' + parent + '-reply');
|
||||
var reply_id = 'reply-' + parent;
|
||||
|
@ -61,10 +33,8 @@
|
|||
});
|
||||
|
||||
function update_math($comment) {
|
||||
if ('MathJax' in window) {
|
||||
var $body = $comment.find('.comment-body');
|
||||
MathJax.typeset($body[0]);
|
||||
}
|
||||
var $body = $comment.find('.comment-body');
|
||||
renderKatex($body[0]);
|
||||
}
|
||||
|
||||
window.show_revision = function (comment_id, offset) {
|
||||
|
@ -145,7 +115,7 @@
|
|||
$comment_loading.hide();
|
||||
var $comment = $("#comment-" + id + "-children");
|
||||
$comment.append(data);
|
||||
MathJax.typeset($('#comments')[0]);
|
||||
renderKatex($('#comments')[0]);
|
||||
register_time($('.time-with-rel'));
|
||||
}
|
||||
})
|
||||
|
@ -188,7 +158,7 @@
|
|||
var $comment = $("#comment-" + id + "-children");
|
||||
$comment.append(data);
|
||||
}
|
||||
MathJax.typeset($('#comments')[0]);
|
||||
renderKatex($('#comments')[0]);
|
||||
register_time($('.time-with-rel'));
|
||||
}
|
||||
})
|
||||
|
@ -241,13 +211,14 @@
|
|||
afterOpen: function () {
|
||||
register_dmmd_preview($('#id-edit-comment-body-preview'));
|
||||
if ('DjangoPagedown' in window) {
|
||||
DjangoPagedown.createEditor(
|
||||
$('#wmd-input-id-edit-comment-body').closest('.wmd-wrapper')[0]
|
||||
);
|
||||
register_copy_clipboard($('#wmd-input-id-edit-comment-body'));
|
||||
var $wmd = $('.featherlight .wmd-wrapper');
|
||||
if ($wmd.length) {
|
||||
window.DjangoPagedown.createEditor($wmd.get(0));
|
||||
if ('MathJax' in window) {
|
||||
var preview = $('.featherlight div.wmd-preview')[0];
|
||||
MathJax.typeset(preview);
|
||||
}
|
||||
var preview = $('.featherlight div.wmd-preview')[0];
|
||||
renderKatex(preview);
|
||||
}
|
||||
}
|
||||
$('#comment-edit').submit(function (event) {
|
||||
|
@ -271,6 +242,11 @@
|
|||
});
|
||||
});
|
||||
},
|
||||
beforeClose: function() {
|
||||
DjangoPagedown.destroyEditor(
|
||||
$('#wmd-input-id-edit-comment-body').closest('.wmd-wrapper')[0]
|
||||
);
|
||||
},
|
||||
variant: 'featherlight-edit'
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
{{ preview_data|markdown|reference|str|safe }}
|
||||
{% if REQUIRE_JAX %}
|
||||
<div data-config="{{ static('mathjax3_config.js') }}" class="require-mathjax-support"></div>
|
||||
{% endif %}
|
||||
{{ preview_data|markdown|reference|str|safe }}
|
|
@ -21,34 +21,6 @@
|
|||
info_float.width(container.width());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this
|
||||
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 %}
|
||||
|
@ -71,10 +43,4 @@
|
|||
{% block comments %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyend %}
|
||||
{% if REQUIRE_JAX %}
|
||||
{% include "mathjax-load.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
7
templates/contest/contest-datetime-js.html
Normal file
7
templates/contest/contest-datetime-js.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('.time-remaining').each(function () {
|
||||
count_down($(this));
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -1,10 +1,3 @@
|
|||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('.time-remaining').each(function () {
|
||||
count_down($(this));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<div id="banner">
|
||||
<a href="https://www.timeanddate.com/worldclock/fixedtime.html?msg={{ contest.name|urlquote('') }}&iso=
|
||||
{{- contest.start_time|utc|date('Y-m-d\TH:i:s') }}" class="date">
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<div class="left-sidebar">
|
||||
{{ make_tab_item('list', 'fa fa-list', url('contest_list'), _('List')) }}
|
||||
{{ make_tab_item('list', 'fa fa-list', url('contest_list'), _('All')) }}
|
||||
{{ make_tab_item('official', 'far fa-check-circle', url('official_contest_list'), _('Official')) }}
|
||||
{{ make_tab_item('calendar', 'fa fa-calendar', url('contest_calendar', now.year, now.month), _('Calendar')) }}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_contest_changelist'), _('Admin')) }}
|
||||
{% if perms.judge.change_contest %}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_contest_changelist'), _('Admin'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
</div>
|
|
@ -9,7 +9,7 @@
|
|||
<div class="left-sidebar">
|
||||
{% if can_access %}
|
||||
{{ make_tab_item('detail', 'fa fa-info-circle', url('contest_view', contest.key), _('Info')) }}
|
||||
{% if contest.ended or can_edit %}
|
||||
{% if (contest.ended and not contest.is_in_contest(request.user)) or can_edit %}
|
||||
{{ make_tab_item('stats', 'fa fa-pie-chart', url('contest_stats', contest.key), _('Statistics')) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@ -19,13 +19,12 @@
|
|||
{{ make_tab_item('ranking', 'fa fa-bar-chart', url('contest_ranking', contest.key), _('Rankings')) }}
|
||||
{% if request.user.is_authenticated and can_access %}
|
||||
{{ make_tab_item('participation', 'fa fa-users', url('contest_participation_own', contest.key), _('Participation')) }}
|
||||
{{ make_tab_item('submissions', 'fa fa-code', url('contest_submissions', contest.key), _('Submissions')) }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ make_tab_item('ranking', 'fa fa-bar-chart', None, _('Hidden Rankings')) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if request.user.is_superuser and contest_has_hidden_subtasks %}
|
||||
{{ make_tab_item('resolver', 'fa fa-check', url('resolver', contest.key), _('Resolver')) }}
|
||||
{{ make_tab_item('resolver', 'fa fa-check', url('resolver', contest.key), _('Resolver'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
{% if show_final_ranking %}
|
||||
{{ make_tab_item('final_ranking', 'fa fa-bar-chart', url('contest_final_ranking', contest.key), _('Final rankings')) }}
|
||||
|
@ -34,6 +33,6 @@
|
|||
{% if perms.judge.moss_contest and has_moss_api_key %}
|
||||
{{ make_tab_item('moss', 'fa fa-gavel', url('contest_moss', contest.key), _('MOSS')) }}
|
||||
{% endif %}
|
||||
{{ make_tab_item('edit', 'fa fa-edit', url('admin:judge_contest_change', contest.id), _('Edit')) }}
|
||||
{{ make_tab_item('edit', 'fa fa-edit', url('admin:judge_contest_change', contest.id), _('Edit'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
{% include "contest/media-js.html" %}
|
||||
{% include "comments/media-js.html" %}
|
||||
{% include "actionbar/media-js.html" %}
|
||||
{% include "contest/contest-datetime-js.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block two_col_media %}
|
||||
|
@ -77,11 +78,15 @@
|
|||
</form>
|
||||
{% endif %}
|
||||
<div style="clear: both"></div>
|
||||
<div class="content-description">
|
||||
{% cache 3600 'contest_html' contest.id MATH_ENGINE %}
|
||||
{{ contest.description|markdown|reference|str|safe }}
|
||||
{% endcache %}
|
||||
</div>
|
||||
|
||||
{% if contest.is_organization_private %}
|
||||
<div style="display: flex; margin-bottom: 1em">
|
||||
{% for org in contest.organizations.all() %}
|
||||
{% include "organization/tag.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if editable_organizations or is_clonable %}
|
||||
<div style="display: flex; gap: 0.5em;">
|
||||
{% for org in editable_organizations %}
|
||||
|
@ -95,6 +100,12 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div style="padding: 0 1em;">
|
||||
{% cache 3600 'contest_html' contest.id %}
|
||||
{{ contest.description|markdown|reference|str|safe }}
|
||||
{% endcache %}
|
||||
</div>
|
||||
|
||||
{% if contest.ended or request.user.is_superuser or is_editor or is_tester %}
|
||||
<hr>
|
||||
<div class="contest-problems">
|
||||
|
|
|
@ -42,16 +42,17 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for rank, item in total_rank %}
|
||||
{% for rank, item in page_obj %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ rank }}
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<span class="username {{ item.css_class }} wrapline" href="{{url('user_page', item.user.username)}}" >{{item.user.username}}</span>
|
||||
<a href="{{url('user_page', item.username)}}"> <span class="username {{ item.css_class }} wrapline">{{item.username}}</span></a>
|
||||
</div>
|
||||
<div>{{item.user.first_name}}</div>
|
||||
<div>{{item.first_name}}</div>
|
||||
<div>{{item.last_name}}</div>
|
||||
</td>
|
||||
{% for point_contest, rank_contest in item.point_contests %}
|
||||
<td>
|
||||
|
@ -68,4 +69,9 @@
|
|||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
<div style="margin-top: 10px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,83 +1,51 @@
|
|||
{% extends "two-column-content.html" %}
|
||||
{% extends "three-column-content.html" %}
|
||||
{% block meta %}
|
||||
<meta name="description" content="The {{ SITE_NAME }}'s contest list - past, present, and future.">
|
||||
{% endblock %}
|
||||
|
||||
{% block two_col_media %}
|
||||
{% block three_col_media %}
|
||||
<style>
|
||||
.non-padding-top {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.content-description ul {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.btn-contest {
|
||||
display: inline-block;
|
||||
padding: 1px 6px;
|
||||
}
|
||||
|
||||
.contest-group-header {
|
||||
padding-bottom: 1em;
|
||||
#search-contest {
|
||||
width: 100%;
|
||||
height: 2.3em;
|
||||
}
|
||||
|
||||
{% if page_obj and page_obj.number > 1%}
|
||||
#ongoing-table {
|
||||
display: none;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
#search-contest, #search-org, #search-btn {
|
||||
width: 100%;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
#search-contest {
|
||||
height: 2.5em;
|
||||
}
|
||||
#search-btn {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
#filter-form input {
|
||||
padding-left: 8px;
|
||||
}
|
||||
#search-org {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
#filter-form input {
|
||||
margin: 0 0.5em 0 0!important;
|
||||
padding-left: 8px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
#search-contest {
|
||||
width: 30%;
|
||||
height: 2.3em;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 0;
|
||||
padding-top: 4px !important;
|
||||
}
|
||||
|
||||
#search-org {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
#search-btn {
|
||||
display: inline-block;
|
||||
height: 2.3em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.contest-format-user {
|
||||
flex: 0.5 !important;
|
||||
}
|
||||
.participate-button {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
{% block contest_list_media %}{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block two_col_js %}
|
||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
||||
{% block three_col_js %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('#active-url').attr('href', changeTabParameter('active'));
|
||||
$('#current-url').attr('href', changeTabParameter('current'));
|
||||
$('#future-url').attr('href', changeTabParameter('future'));
|
||||
$('#past-url').attr('href', changeTabParameter('past'));
|
||||
|
||||
var $form = $('form#filter-form');
|
||||
$('input#show_orgs').click(function () {
|
||||
$form.submit();
|
||||
|
||||
$('#hide_organization_contests').click(function () {
|
||||
submitFormWithParams($form, "POST");
|
||||
});
|
||||
$('#go').click(function() {
|
||||
submitFormWithParams($form, "GET");
|
||||
});
|
||||
$('.time-remaining').each(function () {
|
||||
count_down($(this));
|
||||
|
@ -86,12 +54,29 @@
|
|||
$('.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.') }}');
|
||||
let q = '{{ _('Are you sure you want to join?') }}\n' +
|
||||
'{{ _('Joining a contest for the first time starts your timer, after which it becomes unstoppable.') }}';
|
||||
{% if request.in_contest %}
|
||||
q += " {{ _('By joining in this contest, you will automatically leave contest') }} \"{{ request.participation.contest.name }}\". ";
|
||||
{% endif %}
|
||||
return confirm(q);
|
||||
});
|
||||
|
||||
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Groups') }}...'})
|
||||
.css({'visibility': 'visible'});
|
||||
$form.on('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
$('#search-contest').keypress(function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
$('#go').click();
|
||||
}
|
||||
});
|
||||
|
||||
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Groups') }}...'});
|
||||
|
||||
$('#order').select2();
|
||||
|
||||
// var tooltip_classes = 'tooltipped tooltipped-e';
|
||||
//
|
||||
|
@ -105,300 +90,145 @@
|
|||
// });
|
||||
});
|
||||
</script>
|
||||
{% block contest_list_js %}{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block left_sidebar %}
|
||||
{% include "contest/contest-list-tabs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% macro contest_head(contest) %}
|
||||
<a href="{{ url('contest_view', contest.key) }}" class="contest-list-title" style="margin-right: 5px;">
|
||||
{{contest.name}}
|
||||
</a>
|
||||
<br>
|
||||
<div class="contest-tags" style="margin-top: 5px;">
|
||||
{% if not contest.is_visible %}
|
||||
<span class="contest-tag contest-tag-hidden">
|
||||
<i class="fa fa-eye-slash"></i> {{ _('hidden') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if contest.is_editable %}
|
||||
<span class="contest-tag contest-tag-edit">
|
||||
<a href="{{ url('organization_contest_edit', organization.id, organization.slug, contest.key) }}" class="white">
|
||||
<i class="fa fa-edit"></i> {{ _('Edit') }}
|
||||
</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if contest.is_private %}
|
||||
<span class="contest-tag contest-tag-private">
|
||||
<i class="fa fa-lock"></i> {{ _('private') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if not hide_contest_orgs %}
|
||||
{% if contest.is_organization_private %}
|
||||
{% for org in contest.organizations.all() %}
|
||||
<span class="contest-tag contest-tag-org">
|
||||
<a href="{{ org.get_absolute_url() }}">
|
||||
<i class="fa fa-lock"></i> {{ org.name }}
|
||||
</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if contest.is_rated %}
|
||||
<span class="contest-tag contest-tag-rated">
|
||||
<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 %}
|
||||
{% block right_sidebar %}
|
||||
<div class="right-sidebar">
|
||||
{% include "contest/search-form.html" %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
{% endblock %}
|
||||
|
||||
{% macro time_left(contest, padding_top = true) %}
|
||||
<div class="time time-left {{ 'non-padding-top' if padding_top == false }}">
|
||||
{% 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 %}
|
||||
{% trans time_limit=contest.time_limit|timedelta('localized-no-seconds') %}{{ time_limit }} window{% endtrans %}
|
||||
{% else %}
|
||||
{% trans duration=contest.contest_window_length|timedelta('localized-no-seconds') %}{{ duration }} long{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
{% from "contest/macros.html" import contest_head, time_left, user_count, contest_format_user %}
|
||||
|
||||
{% macro user_count(contest, user) %}
|
||||
{% if contest.can_see_own_scoreboard(user) %}
|
||||
<a href="{{ url('contest_ranking', contest.key) }}">{{ contest.user_count }}</a>
|
||||
{% macro contest_join(contest, request, is_past=False) %}
|
||||
{% if request.in_contest and request.participation.contest == contest %}
|
||||
<button class="small" disabled>{{ _('In contest') }}</button>
|
||||
{% elif is_past %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full small"
|
||||
value="{{ _('Virtual join') }}">
|
||||
</form>
|
||||
{% elif request.profile.id in contest.editor_ids or request.profile.id in contest.tester_ids %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full small"
|
||||
value="{{ _('Spectate') }}">
|
||||
</form>
|
||||
{% else %}
|
||||
{{ contest.user_count }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro contest_join(contest, request) %}
|
||||
{% if not request.in_contest %}
|
||||
{% if request.profile in contest.authors.all() or request.profile in contest.curators.all() or request.profile in contest.testers.all() %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full small"
|
||||
value="{{ _('Spectate') }}">
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full small join-warning"
|
||||
value="{{ _('Join') }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full small join-warning"
|
||||
value="{{ _('Join') }}">
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block middle_content %}
|
||||
<div class="content-description">
|
||||
<form id="filter-form">
|
||||
<input id="search-contest" type="text" name="contest" value="{{ contest_query or '' }}"
|
||||
placeholder="{{ _('Search contests...') }}">
|
||||
{% if organizations %}
|
||||
<select id="search-org" name="orgs" multiple>
|
||||
{% for org in organizations %}
|
||||
<option value="{{ org.id }}"{% if org.id in org_query %} selected{% endif %}>
|
||||
{{ org.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="tabs tabs-no-flex" style="width: 100%;margin-left: auto;margin-right: auto;">
|
||||
<ul>
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="{{'active' if current_tab=='active'}}">
|
||||
<a id='active-url'>{{ _('Active') }}
|
||||
{% if active_count %}
|
||||
({{active_count}})
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<button id="search-btn" class="btn-green small"> {{ _('Search')}} </button>
|
||||
{% if organizations %}
|
||||
<div>
|
||||
<input id="show_orgs" type="checkbox" name="show_orgs" value="1" {% if show_orgs %}checked{% endif %}>
|
||||
<label for="show_orgs">{{ _('Hide organization contests') }}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if create_url %}
|
||||
<a href="{{create_url}}" class="button small" style="float: right"><i class="fa fa-plus"></i> {{ _('Create')}}</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if active_participations %}
|
||||
<h3 class="toggle open contest-group-header">
|
||||
<i class="fa fa-chevron-right fa-fw"></i>
|
||||
{{ _('Active Contests') }}
|
||||
</h3>
|
||||
<div class="toggled">
|
||||
<li class="{{'active' if current_tab=='current'}}">
|
||||
<a id='current-url'>{{ _('Ongoing') }}
|
||||
{% if current_count %}
|
||||
({{current_count}})
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="{{'active' if current_tab=='future'}}">
|
||||
<a id='future-url'>{{ _('Upcoming') }}
|
||||
{% if future_count %}
|
||||
({{future_count}})
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="{{'active' if current_tab=='past'}}">
|
||||
<a id='past-url'>{{ _('Past') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% for participation in active_participations %}
|
||||
{% with contest=participation.contest %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest) }}
|
||||
</div>
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{% if contest.start_time %}
|
||||
{% if contest.time_limit %}
|
||||
<span class="time">
|
||||
{% trans countdown=participation.end_time|as_countdown %}Window ends in {{countdown}}{% endtrans %}
|
||||
</span>
|
||||
{% elif contest.time_before_end %}
|
||||
<span class="time">{% trans countdown=contest.end_time|as_countdown %}Ends in {{countdown}}{% endtrans %}</span>
|
||||
{% endif %}
|
||||
{{ time_left(contest) }}
|
||||
{% if request.user.is_authenticated and current_tab == 'active' %}
|
||||
{% if contests %}
|
||||
{% for participation in contests %}
|
||||
{% with contest=participation.contest %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest, organization) }}
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{% if contest.start_time %}
|
||||
{{ time_left(contest) }}
|
||||
{% if contest.time_limit %}
|
||||
<span class="time">
|
||||
{% trans countdown=participation.end_time|as_countdown %}Window ends in {{countdown}}{% endtrans %}
|
||||
</span>
|
||||
{% elif contest.time_before_end %}
|
||||
<span class="time">{% trans countdown=contest.end_time|as_countdown %}Ends in {{countdown}}{% endtrans %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Format') }} </div>
|
||||
{{ contest.format.name }}
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Users') }} </div>
|
||||
{{ user_count(contest, request.user) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest contest-format-user">
|
||||
{{ contest_format_user(contest, request, is_official=is_official) }}
|
||||
<div class="participate-button">
|
||||
{{ contest_join(contest, request) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
<div style="margin-top: 10px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i> {{ _('There is no active contest at this time.') }} </i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<h3 class="toggle open contest-group-header">
|
||||
<i class="fa fa-chevron-right fa-fw"></i>
|
||||
{{ _('Ongoing Contests') }}
|
||||
</h3>
|
||||
{% if current_contests %}
|
||||
<div id="ongoing-table" class="toggled">
|
||||
{% for contest in current_contests %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest) }}
|
||||
</div>
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{% if contest.start_time %}
|
||||
{% if contest.time_before_end %}
|
||||
<span class="time">{% trans countdown=contest.end_time|as_countdown %}Ends in {{countdown}}{% endtrans %}</span>
|
||||
{% endif %}
|
||||
{{ time_left(contest) }}
|
||||
{% if current_tab == 'current' %}
|
||||
{% if contests %}
|
||||
{% for contest in contests %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest, organization) }}
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{% if contest.start_time %}
|
||||
{{ time_left(contest) }}
|
||||
{% if contest.time_before_end %}
|
||||
<span class="time">{% trans countdown=contest.end_time|as_countdown %}Ends in {{countdown}}{% endtrans %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Format') }} </div>
|
||||
{{ contest.format.name }}
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Users') }} </div>
|
||||
{{ user_count(contest, request.user) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest contest-format-user">
|
||||
{{ contest_format_user(contest, request, is_official=is_official) }}
|
||||
<div class="participate-button">
|
||||
{{ contest_join(contest, request) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<br>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="toggled">
|
||||
<i> {{ _('There is no ongoing contest at this time.') }} </i>
|
||||
<br>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h3 class="toggle open contest-group-header">
|
||||
<i class="fa fa-chevron-right fa-fw"></i>
|
||||
{{ _('Upcoming Contests') }}
|
||||
</h3>
|
||||
{% if future_contests %}
|
||||
<div class="toggled">
|
||||
{% for contest in future_contests %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest) }}
|
||||
</div>
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{% if contest.start_time %}
|
||||
{% if contest.time_before_start %}
|
||||
<span class="time">{{ _('Starting in %(countdown)s.', countdown=contest.start_time|as_countdown) }}</span>
|
||||
{% endif %}
|
||||
{{ time_left(contest) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Format') }} </div>
|
||||
{{ contest.format.name }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="toggled">
|
||||
<i>{{ _('There is no scheduled contest at this time.') }}</i>
|
||||
<br>
|
||||
</div>
|
||||
{% endif %}
|
||||
<br>
|
||||
|
||||
<h3 class="toggle open contest-group-header">
|
||||
{{ _('Past Contests') }}
|
||||
</h3>
|
||||
{% if past_contests %}
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
<div style="margin-bottom: 10px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for contest in past_contests %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest) }}
|
||||
</div>
|
||||
<div class="info-contest" style="flex: 1.5">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{{ time_left(contest, false) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Format') }} </div>
|
||||
{{ contest.format.name }}
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Users') }} </div>
|
||||
{{ user_count(contest, request.user) }}
|
||||
</div>
|
||||
{% if not request.in_contest %}
|
||||
<div class="participate-button">
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full small"
|
||||
value="{{ _('Virtual join') }}">
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
|
@ -407,10 +237,73 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="toggled">
|
||||
<i> {{ _('There is no past contest.') }} </i>
|
||||
<br>
|
||||
</div>
|
||||
<i> {{ _('There is no ongoing contest at this time.') }} </i>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if current_tab == 'future' %}
|
||||
{% if contests %}
|
||||
{% for contest in contests %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest, organization) }}
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{% if contest.start_time %}
|
||||
{{ time_left(contest) }}
|
||||
{% if contest.time_before_start %}
|
||||
<span class="time">{{ _('Starting in %(countdown)s.', countdown=contest.start_time|as_countdown) }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest contest-format-user">
|
||||
{{ contest_format_user(contest, request, show_user=False, is_official=is_official) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
<div style="margin-top: 10px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i>{{ _('There is no scheduled contest at this time.') }}</i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if current_tab == 'past' %}
|
||||
{% if contests %}
|
||||
{% for contest in contests %}
|
||||
<div class="list-contest">
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Contests') }} </div>
|
||||
{{ contest_head(contest, organization) }}
|
||||
</div>
|
||||
<div class="info-contest">
|
||||
<div class="contest-title"> {{ _('Time') }} </div>
|
||||
<div class="contest-block">
|
||||
{{ time_left(contest) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-contest contest-format-user">
|
||||
{{ contest_format_user(contest, request, is_official=is_official) }}
|
||||
<div class="participate-button">
|
||||
{{ contest_join(contest, request, is_past=True) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
<div style="margin-top: 10px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i> {{ _('There is no past contest.') }} </i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
100
templates/contest/macros.html
Normal file
100
templates/contest/macros.html
Normal file
|
@ -0,0 +1,100 @@
|
|||
{% macro contest_head(contest, organization=None) %}
|
||||
<a href="{{ url('contest_view', contest.key) }}" class="contest-list-title" style="margin-right: 5px;">
|
||||
{{contest.name}}
|
||||
</a>
|
||||
<div class="contest-tags">
|
||||
{% if not contest.is_visible %}
|
||||
<span class="contest-tag contest-tag-hidden">
|
||||
<i class="fa fa-eye-slash"></i> {{ _('hidden') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if organization and contest.is_editable %}
|
||||
<span class="contest-tag contest-tag-edit">
|
||||
<a href="{{ url('organization_contest_edit', organization.id, organization.slug, contest.key) }}" class="white">
|
||||
<i class="fa fa-edit"></i> {{ _('Edit') }}
|
||||
</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if contest.is_private %}
|
||||
<span class="contest-tag contest-tag-private">
|
||||
<i class="fa fa-lock"></i> {{ _('private') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if not organization %}
|
||||
{% if contest.is_organization_private %}
|
||||
{% for org in contest.organizations.all() %}
|
||||
{% include "organization/tag.html" %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if contest.is_rated %}
|
||||
<span class="contest-tag contest-tag-rated">
|
||||
<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 %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro time_left(contest) %}
|
||||
<div class="time-left">
|
||||
{% if contest.time_limit %}
|
||||
<div>
|
||||
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
|
||||
</div>
|
||||
<div>
|
||||
<b>{{_("End")}}</b>: {{ contest.end_time|date(_("H:i d/m/Y")) }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div>
|
||||
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<b>{{_("Length")}}</b>:
|
||||
{% if contest.time_limit %}
|
||||
{% trans time_limit=contest.time_limit|timedelta('localized-no-seconds') %}{{ time_limit }}{% endtrans %}
|
||||
{% else %}
|
||||
{% trans duration=contest.contest_window_length|timedelta('localized-no-seconds') %}{{ duration }}{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro user_count(contest, user) %}
|
||||
{% if contest.can_see_own_scoreboard(user) %}
|
||||
<a href="{{ url('contest_ranking', contest.key) }}"><i class="fa fa-users"></i> {{ contest.user_count }}</a>
|
||||
{% else %}
|
||||
<i class="fa fa-users"></i>{{ contest.user_count }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro contest_format_user(contest, request, show_user=True, is_official=False) %}
|
||||
{% if is_official %}
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<div><b>{{ _('Format') }}</b>: {{ contest.format.name }}</div>
|
||||
<div><b>{{ _('Category') }}</b>: {{ contest.official.category.name }}</div>
|
||||
<div><b>{{ _('Location') }}</b>: {{ contest.official.location.name }}</div>
|
||||
<div><b>{{ _('Year') }}</b>: {{ contest.official.year }}</div>
|
||||
{% if show_user %}
|
||||
<div class="contest-title" style="margin-top: 0.4em">{{ user_count(contest, request.user) }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<div class="contest-title"> {{ _('Format') }} </div>
|
||||
<div style="flex-grow: 1">{{ contest.format.name }}</div>
|
||||
{% if show_user %}
|
||||
<div class="contest-title" style="margin-top: 0.4em">{{ user_count(contest, request.user) }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
|
@ -149,8 +149,12 @@
|
|||
});
|
||||
|
||||
$('.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.') }}');
|
||||
let q = '{{ _('Are you sure you want to join?') }}\n' +
|
||||
'{{ _('Joining a contest starts your timer, after which it becomes unstoppable.') }}';
|
||||
{% if current_contest %}
|
||||
q += " {{ _('By joining in this contest, you will automatically leave contest') }} \"{{ current_contest.name }}\". ";
|
||||
{% endif %}
|
||||
return confirm(q);
|
||||
});
|
||||
|
||||
var url = '{{ url('contest_participation', contest.key, '__username__') }}';
|
||||
|
@ -161,7 +165,9 @@
|
|||
$('#search-contest').select2({
|
||||
placeholder: placeholder,
|
||||
ajax: {
|
||||
url: '{{ url('contest_user_search_select2_ajax', contest.key) }}'
|
||||
url: '{{ url('contest_user_search_select2_ajax', contest.key) }}',
|
||||
cache: true,
|
||||
delay: 250,
|
||||
},
|
||||
minimumInputLength: 1,
|
||||
escapeMarkup: function (markup) {
|
||||
|
|
57
templates/contest/official-search-form.html
Normal file
57
templates/contest/official-search-form.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
<div class="sidebox">
|
||||
<h3 class="colored-text"><i class="fa fa-search"></i>{{ _('Contest search') }}</h3>
|
||||
<div class="sidebox-content">
|
||||
<form id="filter-form" method="GET">
|
||||
<input id="search-contest" type="text" name="contest" value="{{ contest_query or '' }}"
|
||||
placeholder="{{ _('Search contests...') }}">
|
||||
|
||||
<div class="filter-form-group">
|
||||
<label class="bold-text margin-label" for="year_from"><i class="non-italics">{{ _('Year') }}</i></label>
|
||||
<div class="year-range">
|
||||
<input type="number" name="year_from" id="year_from" value="{{ year_from or '' }}"
|
||||
placeholder="{{ _('From') }}">
|
||||
<input type="number" name="year_to" id="year_to" value="{{ year_to or '' }}"
|
||||
placeholder="{{ _('To') }}" style="float: right">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-form-group">
|
||||
<label class="bold-text margin-label" for="category"><i class="non-italics">{{ _('Category') }}</i></label>
|
||||
<select id="category" name="category" multiple>
|
||||
{% for cat in categories %}
|
||||
<option value="{{ cat.id }}"{% if cat.id in selected_categories %} selected{% endif %}>
|
||||
{{ cat.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-form-group">
|
||||
<label class="bold-text margin-label" for="location"><i class="non-italics">{{ _('Location') }}</i></label>
|
||||
<select id="location" name="location" style="width: 100%" multiple>
|
||||
{% for loc in locations %}
|
||||
<option value="{{ loc.id }}"{% if loc.id in selected_locations %} selected{% endif %}>
|
||||
{{ loc.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-form-group">
|
||||
<label for="order" class="bold-text margin-label">{{ _('Order by') }}</label>
|
||||
<select id="order" name="order" style="width: 100%">
|
||||
<option value="">---</option>
|
||||
{% for value, name in all_sort_options %}
|
||||
<option value="{{value}}"{% if selected_order == value%} selected{% endif %}>
|
||||
{{ name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-submit-group">
|
||||
<a id="go" class="button small">{{ _('Go') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
42
templates/contest/official_list.html
Normal file
42
templates/contest/official_list.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
{% extends "contest/list.html" %}
|
||||
|
||||
{% block contest_list_media %}
|
||||
<style type="text/css">
|
||||
.contest-format-user {
|
||||
flex: 1 !important;
|
||||
}
|
||||
|
||||
.year-range {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.year-range input {
|
||||
width: 45%;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block contest_list_js %}
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$("#category").select2();
|
||||
$("#location").select2();
|
||||
$('#year_from').keypress(function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
$('#go').click();
|
||||
}
|
||||
});
|
||||
$('#year_to').keypress(function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
$('#go').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block right_sidebar %}
|
||||
<div class="right-sidebar">
|
||||
{% include "contest/official-search-form.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,4 +1 @@
|
|||
{{ preview_data|markdown|reference|str|safe }}
|
||||
{% if REQUIRE_JAX %}
|
||||
<div data-config="{{ static('mathjax3_config.js') }}" class="require-mathjax-support"></div>
|
||||
{% endif %}
|
|
@ -1,10 +1,6 @@
|
|||
<style>
|
||||
#users-table .username {
|
||||
min-width: 15em;
|
||||
}
|
||||
|
||||
#users-table td {
|
||||
height: 2.5em;
|
||||
min-height: 2.5em;
|
||||
}
|
||||
|
||||
#users-table a {
|
||||
|
@ -32,8 +28,11 @@
|
|||
}
|
||||
|
||||
.user-name {
|
||||
position: relative;
|
||||
padding-left: 2em !important;
|
||||
padding-left: 1em !important;
|
||||
padding-right: 1em !important;
|
||||
display: flex;
|
||||
min-width: max-content;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.organization-column {
|
||||
|
@ -43,7 +42,6 @@
|
|||
}
|
||||
|
||||
.featherlight-content {
|
||||
border-radius: 10px;
|
||||
height: 80%;
|
||||
width: 60%;
|
||||
overflow: auto;
|
||||
|
|
|
@ -13,18 +13,23 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block user_footer %}
|
||||
{% if user.user.first_name %}
|
||||
{% set profile = user.user %}
|
||||
{% if profile.first_name %}
|
||||
<div style="font-weight: 600; display: none" class="fullname gray">
|
||||
{{ user.user.first_name }}
|
||||
{{ profile.first_name }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if user.user.last_name %}
|
||||
{% if profile.last_name %}
|
||||
<div class="school gray" style="display: none"><div style="font-weight: 600">
|
||||
{{- user.user.last_name -}}
|
||||
{{ profile.last_name }}
|
||||
</div></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block user_link %}
|
||||
{{ link_user(user.user, show_image=True) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block user_data %}
|
||||
{% if user.participation.virtual %}
|
||||
<sub class="gray">[{{user.participation.virtual}}]</sub>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block users_js_media %}
|
||||
{% include "contest/contest-datetime-js.html" %}
|
||||
{% if can_edit %}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
|
@ -127,12 +128,14 @@
|
|||
|
||||
{% block before_table %}
|
||||
{% include "contest/contest-datetime.html" %}
|
||||
<div style="margin-bottom: 0.5em">
|
||||
{% if page_type == 'participation' %}
|
||||
{% if contest.can_see_full_scoreboard(request.user) %}
|
||||
{% if page_type == 'participation' %}
|
||||
{% if contest.can_see_full_scoreboard(request.user) %}
|
||||
<div style="margin-bottom: 0.5em">
|
||||
<input id="search-contest" type="text" placeholder="{{ _('View user participation') }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div style="margin-bottom: 0.5em">
|
||||
<input id="show-schools-checkbox" type="checkbox" style="vertical-align: bottom">
|
||||
<label for="show-schools-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Show schools') }}</label>
|
||||
|
||||
|
@ -147,8 +150,8 @@
|
|||
<label for="show-total-score-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Total score only') }}</label>
|
||||
<input id="show-virtual-checkbox" type="checkbox" style="vertical-align: bottom;">
|
||||
<label id="show-virtual-label" for="show-virtual-checkbox" style="vertical-align: bottom; margin-right: 1em;">{{ _('Show virtual participation') }}</label>
|
||||
<img src="{{static('loading.gif')}}" style="height: 1em; display:none;" id="loading-gif"></img>
|
||||
<a href="#" onclick="download_ranking_as_csv()" style="float: right;">
|
||||
<i class="fa fa-spinner fa-pulse" style="display: none" id="loading-gif"></i>
|
||||
<a href="#" onclick="download_ranking_as_csv()">
|
||||
<i class="fa fa-download" aria-hidden="true"></i>
|
||||
{{ _('Download as CSV') }}
|
||||
</a>
|
||||
|
|
40
templates/contest/search-form.html
Normal file
40
templates/contest/search-form.html
Normal file
|
@ -0,0 +1,40 @@
|
|||
<div class="sidebox">
|
||||
<h3 class="colored-text"><i class="fa fa-search"></i>{{ _('Contest search') }}</h3>
|
||||
<div class="sidebox-content">
|
||||
<form id="filter-form" method="GET">
|
||||
<input id="search-contest" type="text" name="contest" value="{{ contest_query or '' }}"
|
||||
placeholder="{{ _('Search contests...') }}">
|
||||
{% if organizations %}
|
||||
<div style="margin-bottom: 1em;">
|
||||
<input id="hide_organization_contests" type="checkbox" name="hide_organization_contests" value="1" {% if hide_organization_contests %}checked{% endif %}>
|
||||
<label for="hide_organization_contests">{{ _('Hide organization contests') }}</label>
|
||||
</div>
|
||||
<label for="search-org" class="bold-text margin-label">{{ _('Group') }}</label>
|
||||
<select id="search-org" name="orgs" multiple>
|
||||
{% for org in organizations %}
|
||||
<option value="{{ org.id }}"{% if org.id in org_query %} selected{% endif %}>
|
||||
{{ org.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
<div class="filter-form-group">
|
||||
<label for="order" class="bold-text margin-label">{{ _('Order by') }}</label>
|
||||
<select id="order" name="order" style="width: 100%">
|
||||
<option value="">---</option>
|
||||
{% for value, name in all_sort_options %}
|
||||
<option value="{{value}}"{% if selected_order == value%} selected{% endif %}>
|
||||
{{ name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-submit-group">
|
||||
<a id="go" class="button small">{{ _('Go') }}</a>
|
||||
{% if create_url %}
|
||||
<a href="{{ create_url }}" class="button small"><i class="fa fa-plus"></i> {{ _('Create') }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
4
templates/contest/submissions.html
Normal file
4
templates/contest/submissions.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
{% extends "submission/list.html" %}
|
||||
{% block left_sidebar %}
|
||||
{% include "contest/contest-tabs.html" %}
|
||||
{% endblock %}
|
|
@ -4,4 +4,4 @@
|
|||
<hr>
|
||||
{% endif %}
|
||||
|
||||
{{ tag.description|markdown }}
|
||||
{{ tag.description }}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% if current_contests %}
|
||||
<div class="blog-sidebox sidebox">
|
||||
<h3 class="bold-text colored-text"><i class="fa fa-trophy"></i> {{ _('Ongoing contests') }}</h3>
|
||||
<h3 class="bold-text colored-text"><i class="fa fa-ranking-star"></i> {{ _('Ongoing contests') }}</h3>
|
||||
<div class="sidebox-content">
|
||||
{% for contest in current_contests %}
|
||||
<div class="contest">
|
||||
|
@ -18,7 +18,7 @@
|
|||
|
||||
{% if future_contests %}
|
||||
<div class="blog-sidebox sidebox">
|
||||
<h3 class="bold-text colored-text"><i class="fa fa-trophy"></i>{{ _('Upcoming contests') }}</h3>
|
||||
<h3 class="bold-text colored-text"><i class="fa fa-ranking-star"></i>{{ _('Upcoming contests') }}</h3>
|
||||
<div class="sidebox-content">
|
||||
{% for contest in future_contests %}
|
||||
<div class="contest">
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Courses</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
{% extends "two-column-content.html" %}
|
||||
|
||||
{% block left_sidebar %}
|
||||
{% include "course/left_sidebar.html" %}
|
||||
{% endblock %}
|
39
templates/course/course.html
Normal file
39
templates/course/course.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
{% extends "course/base.html" %}
|
||||
|
||||
{% block middle_content %}
|
||||
<center><h2>{{title}}</h2></center>
|
||||
<h3 class="course-content-title">{{_("About")}}</h3>
|
||||
<div>
|
||||
{{ course.about|markdown|reference|str|safe }}
|
||||
</div>
|
||||
<h3 class="course-content-title">{{_("Lessons")}}</h3>
|
||||
<ul class="lesson-list">
|
||||
{% for lesson in lessons %}
|
||||
<a href="{{url('course_lesson_detail', course.slug, lesson.id)}}">
|
||||
{% set progress = lesson_progress[lesson.id] %}
|
||||
<li>
|
||||
<div class="lesson-title">
|
||||
{{ lesson.title }}
|
||||
<div class="lesson-points">
|
||||
{{progress['achieved_points'] | floatformat(1)}} / {{lesson.points}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar" style="width: {{progress['percentage']}}%;">{{progress['percentage']|floatformat(0)}}%</div>
|
||||
</div>
|
||||
</li>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h3 class="course-content-title">
|
||||
{% set total_progress = lesson_progress['total'] %}
|
||||
{% set achieved_points = total_progress['achieved_points'] %}
|
||||
{% set total_points = total_progress['total_points'] %}
|
||||
{% set percentage = total_progress['percentage'] %}
|
||||
|
||||
{{_("Total achieved points")}}:
|
||||
<span style="float: right; font-weight: normal;">
|
||||
{{ achieved_points | floatformat(2) }} / {{ total_points }} ({{percentage|floatformat(1)}}%)
|
||||
</span>
|
||||
</h3>
|
||||
{% endblock %}
|
58
templates/course/edit_lesson.html
Normal file
58
templates/course/edit_lesson.html
Normal file
|
@ -0,0 +1,58 @@
|
|||
{% extends "course/base.html" %}
|
||||
|
||||
{% block two_col_media %}
|
||||
{{ form.media.css }}
|
||||
<style type="text/css">
|
||||
.field-order, .field-title, .field-points {
|
||||
display: inline-flex;
|
||||
}
|
||||
.form-header {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block two_col_js %}
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
|
||||
{% block middle_content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ formset.management_form }}
|
||||
{% for form in formset %}
|
||||
<h3 class="toggle {{'open' if form.errors else 'closed'}} form-header"><i class="fa fa-chevron-right fa-fw"></i>
|
||||
{% if form.title.value() %}
|
||||
{{form.order.value()}}. {{form.title.value()}}
|
||||
{% else %}
|
||||
+ {{_("Add new")}}
|
||||
{% endif %}
|
||||
</h3>
|
||||
<div class="toggled" style="{{'display: none;' if not form.errors}} margin-bottom: 1em">
|
||||
{{form.id}}
|
||||
{% if form.errors %}
|
||||
<div class="alert alert-danger alert-dismissable">
|
||||
<a href="#" class="close">x</a>
|
||||
{{_("Please fix below errors")}}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for field in form %}
|
||||
{% if not field.is_hidden %}
|
||||
<div style="margin-bottom: 1em;">
|
||||
{{ field.errors }}
|
||||
<label for="{{field.id_for_label }}"><b>{{ field.label }}{% if field.field.required %}<span class="red"> * </span>{% endif %}:</b> </label>
|
||||
<div class="org-field-wrapper field-{{field.name}}" id="org-field-wrapper-{{field.html_name}}">
|
||||
{{ field }}
|
||||
</div>
|
||||
{% if field.help_text %}
|
||||
<small class="org-help-text"><i class="fa fa-exclamation-circle"></i> {{ field.help_text|safe }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<hr/>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<input type="submit" value="{{_('Save')}}" style="float: right">
|
||||
</form>
|
||||
{% endblock %}
|
127
templates/course/grades.html
Normal file
127
templates/course/grades.html
Normal file
|
@ -0,0 +1,127 @@
|
|||
{% extends "course/base.html" %}
|
||||
|
||||
{% block two_col_media %}
|
||||
<style type="text/css">
|
||||
table {
|
||||
font-size: 15px;
|
||||
}
|
||||
td {
|
||||
height: 2.5em;
|
||||
}
|
||||
.user-name {
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
#search-input {
|
||||
float: right;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block two_col_js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
var $searchInput = $("#search-input");
|
||||
var $usersTable = $("#users-table");
|
||||
var tableBorderColor = $('#users-table td').css('border-bottom-color');
|
||||
|
||||
$searchInput.on("keyup", function() {
|
||||
var value = $(this).val().toLowerCase();
|
||||
$("#users-table tbody tr").filter(function() {
|
||||
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
||||
});
|
||||
|
||||
if(value) {
|
||||
$('#users-table').css('border-bottom', '1px solid ' + tableBorderColor);
|
||||
} else {
|
||||
$('#users-table').css('border-bottom', '');
|
||||
}
|
||||
});
|
||||
|
||||
$('#sortSelect').select2({
|
||||
minimumResultsForSearch: -1,
|
||||
width: "10em",
|
||||
});
|
||||
|
||||
$('#sortSelect').on('change', function() {
|
||||
var rows = $('#users-table tbody tr').get();
|
||||
var sortBy = $(this).val();
|
||||
rows.sort(function(a, b) {
|
||||
var keyA = $(a).find(sortBy === 'username' ? '.user-name' : 'td:last-child').text().trim();
|
||||
var keyB = $(b).find(sortBy === 'username' ? '.user-name' : 'td:last-child').text().trim();
|
||||
|
||||
if(sortBy === 'total') {
|
||||
// Convert percentage string to number for comparison
|
||||
keyA = -parseFloat(keyA.replace('%', ''));
|
||||
keyB = -parseFloat(keyB.replace('%', ''));
|
||||
}
|
||||
else {
|
||||
keyA = keyA.toLowerCase();
|
||||
keyB = keyB.toLowerCase();
|
||||
}
|
||||
|
||||
if(keyA < keyB) return -1;
|
||||
if(keyA > keyB) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
$.each(rows, function(index, row) {
|
||||
$('#users-table tbody').append(row);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block middle_content %}
|
||||
<center><h2>{{title}}</h2></center>
|
||||
{% set lessons = course.lessons.all() %}
|
||||
{{_("Sort by")}}:
|
||||
<select id="sortSelect">
|
||||
<option value="username">{{_("Username")}}</option>
|
||||
<option value="total">{{_("Score")}}</option>
|
||||
</select>
|
||||
<input type="text" id="search-input" placeholder="{{_('Search')}}" autofocus>
|
||||
<table class="table striped" id="users-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{_('Student')}}</th>
|
||||
{% if grades|length > 0 %}
|
||||
{% for lesson in lessons %}
|
||||
<th class="points">
|
||||
<a href="{{url('course_lesson_detail', course.slug, lesson.id)}}">
|
||||
{{ lesson.title }}
|
||||
<div class="point-denominator">{{lesson.points}}</div>
|
||||
</a>
|
||||
</th>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<th>{{_('Total')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for student, grade in grades.items() %}
|
||||
<tr>
|
||||
<td class="user-name">
|
||||
<div>
|
||||
{{link_user(student)}}
|
||||
</div>
|
||||
<div>
|
||||
{{student.first_name}}
|
||||
</div>
|
||||
</td>
|
||||
{% for lesson in lessons %}
|
||||
<td class="partial-score">
|
||||
<a href="{{url('course_lesson_detail', course.slug, lesson.id)}}?user={{student.username}}">
|
||||
{{ grade[lesson.id]['percentage'] | floatformat(0) }}%
|
||||
</a>
|
||||
</td>
|
||||
{% endfor %}
|
||||
<td style="font-weight: bold">
|
||||
{{ grade['total']['percentage'] | floatformat(0) }}%
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
10
templates/course/left_sidebar.html
Normal file
10
templates/course/left_sidebar.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<div class="left-sidebar">
|
||||
{{ make_tab_item('home', 'fa fa-home', course.get_absolute_url(), _('Home')) }}
|
||||
{% if is_editable %}
|
||||
{{ make_tab_item('edit_lesson', 'fa fa-edit', url('edit_course_lessons', course.slug), _('Edit lessons')) }}
|
||||
{{ make_tab_item('grades', 'fa fa-check-square', url('course_grades', course.slug), _('Grades')) }}
|
||||
{% endif %}
|
||||
{% if perms.judge.change_course %}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_course_change', course.id), _('Admin'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
</div>
|
39
templates/course/lesson.html
Normal file
39
templates/course/lesson.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
{% extends "course/base.html" %}
|
||||
|
||||
{% block two_col_media %}
|
||||
<style>
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block middle_content %}
|
||||
<center><h2>{{title}}</h2></center>
|
||||
<h3 class="course-content-title">{{_("Content")}}</h3>
|
||||
<div>
|
||||
{{ lesson.content|markdown|reference|str|safe }}
|
||||
</div>
|
||||
<h3 class="course-content-title">{{_("Problems")}}</h3>
|
||||
<ul class="course-problem-list">
|
||||
{% for problem in lesson.problems.all() %}
|
||||
<a href="{{url('problem_detail', problem.code)}}">
|
||||
<li>
|
||||
{% if problem.id in completed_problem_ids %}
|
||||
<i class="solved-problem-color fa fa-check-circle"></i>
|
||||
{% elif problem.id in attempted_problems %}
|
||||
<i class="attempted-problem-color fa fa-minus-circle"></i>
|
||||
{% else %}
|
||||
<i class="unsolved-problem-color fa fa-minus-circle"></i>
|
||||
{% endif %}
|
||||
<span class="problem-name">{{problem.name}}</span>
|
||||
{% set pp = problem_points[problem.id] %}
|
||||
<span class="score">
|
||||
{% if pp %}
|
||||
{{pp.case_points|floatformat(1)}} / {{pp.case_total|floatformat(0)}}
|
||||
{% else %}
|
||||
0
|
||||
{% endif %}
|
||||
</span>
|
||||
</li>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
|
@ -1,19 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Enrolling</h1>
|
||||
{% for course in enrolling %}
|
||||
<h2> {{ course }} </h2>
|
||||
{% extends "two-column-content.html" %}
|
||||
|
||||
{% block two_col_media %}
|
||||
{% endblock %}
|
||||
|
||||
{% block left_sidebar %}
|
||||
<div class="left-sidebar">
|
||||
{{ make_tab_item('list', 'fa fa-list', url('course_list'), _('Courses')) }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block middle_content %}
|
||||
<div class="course-list">
|
||||
{% for course in courses %}
|
||||
<div class="course-item">
|
||||
<div class="course-image">
|
||||
<img loading="lazy" src="{{course.image_url}}">
|
||||
</div>
|
||||
<div class="course-content">
|
||||
<a href="{{url('course_detail', course.slug)}}" class="course-name">{{course.name}}</a>
|
||||
{% set teachers = course.get_teachers() %}
|
||||
{% if teachers %}
|
||||
<div class="course-teachers">{{_('Teachers')}}: {{link_users(teachers)}}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<h1> Available </h1>
|
||||
{% for course in available %}
|
||||
<h2> {{ course }} </h2>
|
||||
{% endfor %}
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
{% endblock %}
|
16
templates/custom_file_upload.html
Normal file
16
templates/custom_file_upload.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<center>
|
||||
{% if file_url %}
|
||||
<p>{{_('Your file has been uploaded successfully')}}: <a href="{{ file_url }}" target="_blank">{{ file_url }}</a></p>
|
||||
<a href="{{ url('custom_file_upload') }}" class="button small" style="width: fit-content;">{{_('Upload another file')}}</a>
|
||||
{% else %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<button type="submit">{{_('Upload file')}}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</center>
|
||||
{% endblock %}
|
|
@ -30,9 +30,8 @@
|
|||
window.loading_page = false;
|
||||
window.has_next_page = parseInt($(".has_next").attr("value"));
|
||||
window.page++;
|
||||
MathJax.typeset($('.middle-content')[0]);
|
||||
renderKatex($('.middle-content')[0]);
|
||||
onWindowReady();
|
||||
activateBlogBoxOnClick();
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,4 @@
|
|||
|
||||
{% block body %}
|
||||
<div class="content-description">{{ flatpage.content|markdown|reference }}</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyend %}
|
||||
{% if REQUIRE_JAX %}{% include "mathjax-load.html" %}{% endif %}
|
||||
{% endblock %}
|
4
templates/katex-load.html
Normal file
4
templates/katex-load.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" integrity="sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8" crossorigin="anonymous"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"
|
||||
onload="renderKatex();"></script>
|
|
@ -1,21 +1,23 @@
|
|||
{% set layout='no_wrapper' %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block media %}
|
||||
<style>
|
||||
main{
|
||||
body{
|
||||
overflow: hidden;
|
||||
}
|
||||
#content{
|
||||
width: 100%;
|
||||
}
|
||||
#content.wrapper{
|
||||
height: calc(100vh - 50px);
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.form-area{
|
||||
float: left;
|
||||
width: 47%;
|
||||
height: 100%
|
||||
#content-body {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.wmd-preview{
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
|
@ -23,60 +25,53 @@
|
|||
.width-controller{
|
||||
width: 51%;
|
||||
}
|
||||
.wmd-input{
|
||||
height: calc(100vh - 72px);
|
||||
#id_body-preview{
|
||||
overflow: scroll;
|
||||
}
|
||||
.right-markdown{
|
||||
height: calc(100vh - 72px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.wrap{
|
||||
display: flex;
|
||||
.form-area {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_media %}
|
||||
<script>
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
|
||||
return function executedFunction(...args) {
|
||||
const context = this;
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func.apply(context, args);
|
||||
};
|
||||
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
function update_preview() {
|
||||
$.ajax({
|
||||
url: "{{url('blog_preview')}}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
preview: $(this).val()
|
||||
},
|
||||
success: function(data) {
|
||||
$('#display').html(data);
|
||||
renderKatex();
|
||||
populateCopyButton();
|
||||
},
|
||||
error: function(error) {
|
||||
console.log(error.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#wmd-input-id_body").on("keyup", function() {
|
||||
const csrfToken = "{{ csrf_token }}";
|
||||
$.ajax({
|
||||
url: "{{url('blog_preview')}}",
|
||||
type: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': csrfToken, // Include the CSRF token in the headers
|
||||
},
|
||||
data: {
|
||||
preview: $(this).val()
|
||||
},
|
||||
success: function(data) {
|
||||
$('#display').html(data);
|
||||
MathJax.typeset();
|
||||
},
|
||||
error: function(error) {
|
||||
alert(error);
|
||||
console.log(error.message)
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const leftDiv = document.getElementById("wmd-input-id_body");
|
||||
const rightDiv = document.getElementById("display");
|
||||
|
||||
leftDiv.addEventListener("scroll", function() {
|
||||
rightDiv.scrollTop = leftDiv.scrollTop;
|
||||
});
|
||||
|
||||
rightDiv.addEventListener("scroll", function() {
|
||||
leftDiv.scrollTop = rightDiv.scrollTop;
|
||||
});
|
||||
const debounced_update_preview = debounce(update_preview, 250);
|
||||
$("#wmd-input-id_body").on("keyup", debounced_update_preview);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -86,8 +81,6 @@
|
|||
<script src="{{ static('pagedown/Markdown.Editor.js') }}"></script>
|
||||
<script src="{{ static('pagedown-extra/Markdown.Extra.js') }}"></script>
|
||||
<script src="{{ static('pagedown_init.js') }}"></script>
|
||||
<script src="{{ static('mathjax3_config.js') }}"></script>
|
||||
<script src="http://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
|
||||
<script src="{{ static('pagedown_math.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -98,46 +91,44 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="wrap">
|
||||
<div id="new-comment" class="form-area">
|
||||
<input type="hidden" name="parent" id="id_parent">
|
||||
<div class="comment-post-wrapper">
|
||||
<div id="comment-form-body"><div class="wmd-wrapper image-upload-enabled">
|
||||
<div class="wmd-panel">
|
||||
<div id="wmd-button-bar-id_body"></div>
|
||||
<textarea id="wmd-input-id_body" class="wmd-input" name="body" required=""></textarea>
|
||||
</div>
|
||||
<div id="id_body-preview" data-preview-url="{{url('comment_preview')}}" data-textarea-id="wmd-input-id_body" data-timeout="1000" class="wmd-panel wmd-preview dmmd-preview dmmd-no-button">
|
||||
<div class="dmmd-preview-update"><i class="fa fa-refresh"></i> {{_('Update Preview')}}</div>
|
||||
<div class="dmmd-preview-content content-description"></div>
|
||||
</div>
|
||||
<div class="pagedown-image-upload">
|
||||
<h2>{{_('Insert Image')}}</h2>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label class="label">{{_('From the web')}}</label>
|
||||
<input class="url-input" type="text" placeholder="http://">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label class="label">{{_('From your computer')}}</label>
|
||||
<input class="file-input" type="file" name="image" id="file" data-action="/pagedown/image-upload/" accept="image/*">
|
||||
</div>
|
||||
</div>
|
||||
<div class="submit-row">
|
||||
<div class="submit-loading"></div>
|
||||
<input class="submit-input show" type="submit" value="{{_('Save')}}" name="_addanother">
|
||||
<p class="deletelink-box"><a href="#" class="close-image-upload deletelink">{{_('Cancel')}}</a></p>
|
||||
<div id="new-comment" class="form-area">
|
||||
<input type="hidden" name="parent" id="id_parent">
|
||||
<div class="comment-post-wrapper">
|
||||
<div id="comment-form-body"><div class="wmd-wrapper image-upload-enabled">
|
||||
<div class="wmd-panel">
|
||||
<div id="wmd-button-bar-id_body"></div>
|
||||
<textarea id="wmd-input-id_body" class="wmd-input" name="body" required=""></textarea>
|
||||
</div>
|
||||
<div id="id_body-preview" data-preview-url="{{url('comment_preview')}}" data-textarea-id="wmd-input-id_body" data-timeout="1000" class="wmd-panel wmd-preview dmmd-preview dmmd-no-button">
|
||||
<div class="dmmd-preview-update"><i class="fa fa-refresh"></i> {{_('Update Preview')}}</div>
|
||||
<div class="dmmd-preview-content content-description"></div>
|
||||
</div>
|
||||
<div class="pagedown-image-upload">
|
||||
<h2>{{_('Insert Image')}}</h2>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label class="label">{{_('From the web')}}</label>
|
||||
<input class="url-input" type="text" placeholder="http://">
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label class="label">{{_('From your computer')}}</label>
|
||||
<input class="file-input" type="file" name="image" id="file" data-action="/pagedown/image-upload/" accept="image/*">
|
||||
</div>
|
||||
</div>
|
||||
<div class="submit-row">
|
||||
<div class="submit-loading"></div>
|
||||
<input class="submit-input show" type="submit" value="{{_('Save')}}" name="_addanother">
|
||||
<p class="deletelink-box"><a href="#" class="close-image-upload deletelink">{{_('Cancel')}}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="id_body-preview" data-preview-url="{{url('comment_preview')}}" data-textarea-id="wmd-input-id_body" data-timeout="1000" class="width-controller wmd-panel wmd-preview dmmd-preview dmmd-no-button dmmd-preview-has-content">
|
||||
<div class="right-markdown dmmd-preview-content content-description" id="display"></div>
|
||||
</div>
|
||||
<div id="id_body-preview" data-preview-url="{{url('comment_preview')}}" data-textarea-id="wmd-input-id_body" data-timeout="1000" class="width-controller wmd-panel wmd-preview dmmd-preview dmmd-no-button dmmd-preview-has-content">
|
||||
<div class="right-markdown dmmd-preview-content content-description" id="display"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
<script type="text/javascript" src="{{ static('mathjax3_config.js') }}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
{% if not has_notifications %}
|
||||
{% if not notifications %}
|
||||
<h2 style="text-align: center;">{{ _('You have no notifications') }}</h2>
|
||||
{% else %}
|
||||
<table class="table">
|
||||
|
@ -14,7 +14,7 @@
|
|||
{% for notification in notifications %}
|
||||
<tr class="{{ 'highlight' if not notification.seen }}">
|
||||
<td>
|
||||
{{ link_user(notification.author) }}
|
||||
{{ link_user(notification.author_id) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ notification.category }}
|
||||
|
@ -31,5 +31,8 @@
|
|||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
<div style="margin-top: 10px;">
|
||||
{% include "list-pages.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
#org-field-wrapper-end_time,
|
||||
#org-field-wrapper-time_limit,
|
||||
#org-field-wrapper-format_name,
|
||||
#org-field-wrapper-freeze_after {
|
||||
#org-field-wrapper-freeze_after,
|
||||
#org-field-wrapper-rate_limit {
|
||||
display: inline-flex;
|
||||
}
|
||||
.problems-problem {
|
||||
|
|
|
@ -14,10 +14,5 @@
|
|||
$(this).parent().submit();
|
||||
}
|
||||
});
|
||||
|
||||
$('#control-panel a').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
navigateTo($(this));
|
||||
})
|
||||
});
|
||||
</script>
|
|
@ -10,16 +10,9 @@
|
|||
{% block middle_title %}
|
||||
<div class="page-title">
|
||||
<div class="tabs" style="border: none;">
|
||||
<h2><img src="{{logo_override_image}}" style="height: 3rem; vertical-align: middle">
|
||||
<h2><img src="{{logo_override_image}}" style="height: 3rem; vertical-align: middle; border-radius: 5px;">
|
||||
{{title}}
|
||||
</h2>
|
||||
{% if is_member %}
|
||||
<div>
|
||||
<a href="{{organization_subdomain}}" target="_blank">
|
||||
{{_('Subdomain')}}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<span class="spacer"></span>
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
|
@ -31,7 +24,8 @@
|
|||
</form>
|
||||
{% else %}
|
||||
<a href="{{ url('request_organization', organization.id, organization.slug) }}"
|
||||
class="unselectable button">{{ _('Request membership') }}</a>
|
||||
class="unselectable button">
|
||||
{{ _('Request membership') }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -47,7 +41,7 @@
|
|||
<h3><i class="fa fa-info-circle"></i>{{ _('About') }}</h3>
|
||||
<div class="sidebox-content">
|
||||
<div style="margin: 0.3em;">
|
||||
{% cache 3600 'organization_html' organization.id MATH_ENGINE %}
|
||||
{% cache 3600 'organization_html' organization.id %}
|
||||
{{ organization.about|markdown|reference|str|safe }}
|
||||
{% endcache %}
|
||||
</div>
|
||||
|
|
|
@ -1,49 +1,110 @@
|
|||
{% extends "two-column-content.html" %}
|
||||
{% extends "three-column-content.html" %}
|
||||
|
||||
{% block two_col_media %}
|
||||
<style>
|
||||
.organization-container .organization-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
{% block three_col_js %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('#mine-tab').attr('href', changeTabParameter('mine'));
|
||||
$('#public-tab').attr('href', changeTabParameter('public'));
|
||||
$('#private-tab').attr('href', changeTabParameter('private'));
|
||||
|
||||
.org-logo {
|
||||
vertical-align: middle;
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.toggle {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
var $form = $('form#filter-form');
|
||||
|
||||
$('#go').click(function() {
|
||||
submitFormWithParams($form, "GET");
|
||||
});
|
||||
|
||||
$form.on('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
$('#search-organization').keypress(function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
$('#go').click();
|
||||
}
|
||||
});
|
||||
|
||||
$('#order').select2();
|
||||
});
|
||||
</script>
|
||||
{% block contest_list_js %}{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title_ruler %}{% endblock %}
|
||||
|
||||
{% block left_sidebar %}
|
||||
{% include "user/user-left-sidebar.html" %}
|
||||
<div class="left-sidebar">
|
||||
{% if request.user.is_authenticated %}
|
||||
{{ make_tab_item('mine', 'fa fa-user', request.path + '?tab=mine', _('Mine')) }}
|
||||
{% endif %}
|
||||
{{ make_tab_item('public', 'fa fa-globe', request.path + '?tab=public', _('Public')) }}
|
||||
{{ make_tab_item('private', 'fa fa-lock', request.path + '?tab=private', _('Private')) }}
|
||||
{% if request.user.is_superuser %}
|
||||
{{ make_tab_item('import', 'fa fa-table', url('import_users'), _('Import'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro org_list(title, queryset) %}
|
||||
{% block right_sidebar %}
|
||||
<div class="right-sidebar">
|
||||
{% include "organization/search-form.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro org_list(queryset, tab) %}
|
||||
{% if queryset %}
|
||||
<h3 style="padding-bottom: 1em" class="toggle open"><i class="fa fa-chevron-right fa-fw"></i> {{title}} ({{queryset.count()}})</h3>
|
||||
<div class="organization-container toggled">
|
||||
<div class="organization-container">
|
||||
{% for org in queryset %}
|
||||
<a href="{{ org.get_absolute_url() }}" class="organization-row" title="{{org.about}}">
|
||||
<img class="org-logo" data-src="{{ org.logo_override_image or static('icons/icon.png') }}">
|
||||
<span style="margin-right: auto">{{ org.name }}</span>
|
||||
<span style="font-weight: normal"><i>{{ org.member_count }} {{_('members')}}</i></span>
|
||||
</a>
|
||||
<div class="organization-card" style="cursor: pointer;" onclick="location.href='{{ org.get_absolute_url() }}';">
|
||||
{% if org.logo_override_image %}
|
||||
<img class="org-logo" loading="lazy" src="{{ org.logo_override_image }}">
|
||||
{% else %}
|
||||
<img class="org-logo" loading="lazy" src="{{ static('icons/icon.svg') }}" onerror="this.onerror=null;this.src='{{ static('icons/logo.svg') }}';">
|
||||
{% endif %}
|
||||
<div class="org-details">
|
||||
<span style="font-weight: bold;">{{ org.name }}</span>
|
||||
<span style="margin-bottom: 0"><i>{{ org.member_count }} {{ _('members') }}</i></span>
|
||||
</div>
|
||||
{% if tab == 'mine' %}
|
||||
<div class="background-royalblue button small">{{ _('View') }}</div>
|
||||
{% elif tab == 'public' %}
|
||||
<form method="post" action="{{ url('join_organization', org.id, org.slug) }}">
|
||||
{% csrf_token %}
|
||||
<input type="submit" style="width: 100%" class="background-royalblue button small" value="{{ _('Join') }}">
|
||||
</form>
|
||||
{% else %}
|
||||
<a href="{{ url('request_organization', org.id, org.slug) }}" style="font-size: 15px;" class="background-royalblue button small">{{ _('Request membership') }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if page_obj and page_obj.num_pages > 1 %}
|
||||
{% include "list-pages.html" %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block middle_content %}
|
||||
<a style="float: right" class="button small" href="{{url('organization_add')}}">{{_("Create group")}}</a>
|
||||
{{ org_list(_('My groups'), my_organizations) }}
|
||||
{{ org_list(_('Open groups'), open_organizations) }}
|
||||
{{ org_list(_('Private groups'), private_organizations) }}
|
||||
{% endblock %}
|
||||
{% if current_tab == 'mine' %}
|
||||
{% if organizations %}
|
||||
{{ org_list(organizations, 'mine') }}
|
||||
{% else %}
|
||||
<i> {{ _('You have not joined any organization yet.') }} </i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if current_tab == 'public' %}
|
||||
{% if organizations %}
|
||||
{{ org_list(organizations, 'public') }}
|
||||
{% else %}
|
||||
<i> {{ _('There is no public organization.') }} </i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if current_tab == 'private' %}
|
||||
{% if organizations %}
|
||||
{{ org_list(organizations, 'private') }}
|
||||
{% else %}
|
||||
<i> {{ _('There is no private organization.') }} </i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -1,14 +1,14 @@
|
|||
<div class="left-sidebar">
|
||||
{{ make_tab_item('home', 'fa fa-home', organization.get_absolute_url(), _('Home')) }}
|
||||
{% if is_member or can_edit %}
|
||||
{{ make_tab_item('problems', 'fa fa-list', organization.get_problems_url(), _('Problems')) }}
|
||||
{{ make_tab_item('contests', 'fa fa-trophy', organization.get_contests_url(), _('Contests')) }}
|
||||
{{ make_tab_item('submissions', 'fa fa-book', organization.get_submissions_url(), _('Submissions')) }}
|
||||
{{ make_tab_item('problems', 'fa fa-puzzle-piece', organization.get_problems_url(), _('Problems')) }}
|
||||
{{ make_tab_item('contests', 'fa fa-ranking-star', organization.get_contests_url(), _('Contests')) }}
|
||||
{{ make_tab_item('submissions', 'fa fa-code', organization.get_submissions_url(), _('Submissions')) }}
|
||||
{% endif %}
|
||||
{% if is_member or can_edit or organization.is_open %}
|
||||
{{ make_tab_item('users', 'fa fa-user', organization.get_users_url(), _('Members')) }}
|
||||
{{ make_tab_item('users', 'fa fa-users', organization.get_users_url(), _('Members')) }}
|
||||
{% endif %}
|
||||
{% if perms.judge.change_organization %}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_organization_change', organization.id), _('Admin')) }}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_organization_change', organization.id), _('Admin'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
</div>
|
|
@ -4,62 +4,64 @@
|
|||
<h3><i class="fa fa-cog"></i>{{ _('Controls') }}</h3>
|
||||
<ul id="control-list" class="sidebox-content" style="margin: 0;">
|
||||
{% if can_edit %}
|
||||
<li>
|
||||
<div>
|
||||
<a href="{{ url('edit_organization', organization.id, organization.slug) }}">{{ _('Edit group') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<div class="link-row">
|
||||
<a href="{{ url('edit_organization', organization.id, organization.slug) }}">
|
||||
<i class="fa fa-edit"></i>{{ _('Edit group') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if can_edit and not organization.is_open %}
|
||||
<li>
|
||||
<div>
|
||||
<a href="{{ url('organization_requests_pending', organization.id, organization.slug) }}">{{ _('View requests') }}</a>
|
||||
{% if pending_count > 0 %}
|
||||
<span id="pending-count-box">
|
||||
{{pending_count}}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if can_edit %}
|
||||
<li>
|
||||
<div>
|
||||
<a href="{{ url('add_organization_member', organization.id, organization.slug) }}">{{ _('Add members') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_member %}
|
||||
<li>
|
||||
<div>
|
||||
<a href="{{ url('add_organization_blog', organization.id, organization.slug) }}">{{ _('Add blog') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<div>
|
||||
<a href="{{ url('organization_pending_blogs', organization.id, organization.slug) }}">{{ _('Pending blogs') }}</a>
|
||||
{% if pending_blog_count > 0 %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('organization_requests_pending', organization.id, organization.slug) }}">
|
||||
<i class="fa fa-inbox"></i>{{ _('View requests') }}</a>
|
||||
{% if pending_count > 0 %}
|
||||
<span id="pending-count-box">
|
||||
{{pending_blog_count}}
|
||||
{{pending_count}}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if can_edit %}
|
||||
<li>
|
||||
<div>
|
||||
<a href="{{ url('organization_contest_add', organization.id, organization.slug) }}">{{ _('Add contest') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<div class="link-row">
|
||||
<a href="{{ url('add_organization_member', organization.id, organization.slug) }}">
|
||||
<i class="fa fa-user-plus"></i>{{ _('Add members') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if is_member %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('add_organization_blog', organization.id, organization.slug) }}">
|
||||
<i class="fa fa-pencil"></i>{{ _('Add blog') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('organization_pending_blogs', organization.id, organization.slug) }}">
|
||||
<i class="fa fa-clipboard-list"></i>{{ _('Pending blogs') }}</a>
|
||||
{% if pending_blog_count > 0 %}
|
||||
<span id="pending-count-box">
|
||||
{{pending_blog_count}}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if can_edit %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('organization_contest_add', organization.id, organization.slug) }}">
|
||||
<i class="fa fa-calendar-plus"></i>{{ _('Add contest') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if is_member %}
|
||||
<div class="link-row">
|
||||
<a href="{{ organization_subdomain }}" target="_blank">
|
||||
<i class="fa fa-globe"></i>{{_('Subdomain')}}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if is_member and not is_admin %}
|
||||
<li>
|
||||
<div class="link-row" style="color: red;">
|
||||
<form method="post" action="{{ url('leave_organization', organization.id, organization.slug) }}">
|
||||
{% csrf_token %}
|
||||
<a href="#" class="leave-organization">{{ _('Leave group') }}</a>
|
||||
<a href="#" class="leave-organization">
|
||||
<i class="fa fa-sign-out-alt"></i>{{ _('Leave group') }}</a>
|
||||
</form>
|
||||
</li>
|
||||
</div>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -72,7 +74,7 @@
|
|||
<h3><i class="fa fa-info-circle"></i>{{ _('About') }}</h3>
|
||||
<div class="sidebox-content">
|
||||
<div style="margin: 0.3em;">
|
||||
{% cache 3600 'organization_html' organization.id MATH_ENGINE %}
|
||||
{% cache 3600 'organization_html' organization.id %}
|
||||
{{ organization.about|markdown|reference|str|safe }}
|
||||
{% endcache %}
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
{{ preview_data|markdown|reference|str|safe }}
|
||||
{% if REQUIRE_JAX %}
|
||||
<div data-config="{{ static('mathjax3_config.js') }}" class="require-mathjax-support"></div>
|
||||
{% endif %}
|
24
templates/organization/search-form.html
Normal file
24
templates/organization/search-form.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<div class="sidebox">
|
||||
<h3 class="colored-text"><i class="fa fa-search"></i>{{ _('Organization search') }}</h3>
|
||||
<div class="sidebox-content">
|
||||
<form id="filter-form" method="GET">
|
||||
<input id="search-organization" type="text" name="organization" value="{{ organization_query or '' }}"
|
||||
placeholder="{{ _('Search organizations...') }}">
|
||||
<div class="filter-form-group">
|
||||
<label for="order" class="bold-text margin-label">{{ _('Order by') }}</label>
|
||||
<select id="order" name="order" style="width: 100%">
|
||||
<option value="">---</option>
|
||||
{% for value, name in all_sort_options %}
|
||||
<option value="{{value}}"{% if selected_order == value%} selected{% endif %}>
|
||||
{{ name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-submit-group">
|
||||
<a class="button small" href="{{url('organization_add')}}">{{_("Create group")}}</a>
|
||||
<a id="go" class="button small">{{ _('Go') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
8
templates/organization/tag.html
Normal file
8
templates/organization/tag.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<a href="{{ org.get_absolute_url() }}">
|
||||
<span class="organization-tag" style="gap: 0.2em;">
|
||||
{% if org.logo_override_image %}
|
||||
<img class="user-img" style="height: 1.5em; width: 1.5em;" loading="lazy" src="{{ org.logo_override_image }}">
|
||||
{% endif %}
|
||||
{{ org.name }}
|
||||
</span>
|
||||
</a>
|
|
@ -12,23 +12,24 @@
|
|||
{% endif %}
|
||||
{% if image_upload_enabled %}
|
||||
<div class="pagedown-image-upload">
|
||||
<h2>Insert Image</h2>
|
||||
<h2>{{_("Insert Image")}}</h2>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label class="label">From the web</label>
|
||||
<label class="label">{{_("From the web")}}</label>
|
||||
<input class="url-input" type="text" placeholder="http://" />
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<label class="label">From your computer</label>
|
||||
<label class="label">{{_("From your computer")}}</label>
|
||||
<input class="file-input" type="file" name="image" id="file" data-action="{{ url('pagedown-image-upload') }}" accept="image/*"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="submit-row">
|
||||
<div class="submit-loading"></div>
|
||||
<input class="submit-input show" type="submit" value="Save" name="_addanother">
|
||||
<p class="deletelink-box"><a href="#" class="close-image-upload deletelink">Cancel</a></p>
|
||||
<input class="submit-input show small" type="submit" value="{{_('Save')}}" name="_addanother">
|
||||
<p class="deletelink-box"><a href="#" class="close-image-upload deletelink">{{_("Cancel")}}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -6,36 +6,38 @@
|
|||
window.big_input = (window.valid_files.length > 100);
|
||||
</script>
|
||||
<script type="text/javascript" src="{{ static('jquery-ui.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ static('fine-uploader/jquery.fine-uploader.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$("#problem-data-zipfile_fine_uploader").fineUploader({
|
||||
request: {
|
||||
endpoint: "{{url('problem_zip_upload', problem.code)}}",
|
||||
params: {
|
||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
||||
if (!window.PAGE_FROM_BACK_BUTTON_CACHE) {
|
||||
$("#problem-data-zipfile_fine_uploader").fineUploader({
|
||||
request: {
|
||||
endpoint: "{{url('problem_zip_upload', problem.code)}}",
|
||||
params: {
|
||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
||||
}
|
||||
},
|
||||
chunking: {
|
||||
enabled: true,
|
||||
partSize: 40000000,
|
||||
},
|
||||
resume: {
|
||||
enabled: true
|
||||
},
|
||||
validation: {
|
||||
allowedExtensions: ['zip'],
|
||||
},
|
||||
}).on('complete', function (event, id, name, responseJSON) {
|
||||
console.log(responseJSON);
|
||||
if (!responseJSON.success) {
|
||||
alert('Fail to upload: ' + responseJSON.error);
|
||||
}
|
||||
},
|
||||
chunking: {
|
||||
enabled: true,
|
||||
partSize: 40000000,
|
||||
},
|
||||
resume: {
|
||||
enabled: true
|
||||
},
|
||||
validation: {
|
||||
allowedExtensions: ['zip'],
|
||||
},
|
||||
}).on('complete', function (event, id, name, responseJSON) {
|
||||
console.log(responseJSON);
|
||||
if (!responseJSON.success) {
|
||||
alert('Fail to upload: ' + responseJSON.error);
|
||||
}
|
||||
else {
|
||||
$('#submit-button').click();
|
||||
}
|
||||
});;
|
||||
else {
|
||||
$('#submit-button').click();
|
||||
}
|
||||
});
|
||||
toggle_custom();
|
||||
}
|
||||
|
||||
function update_select2() {
|
||||
$('tbody:not(.extra-row-body) .type-column select').select2({
|
||||
|
@ -133,11 +135,11 @@
|
|||
}).change();
|
||||
}
|
||||
|
||||
(function toggle_custom() {
|
||||
function toggle_custom() {
|
||||
let $checker = $('#id_problem-data-checker')
|
||||
|
||||
let $custom_checker = $('#id_problem-data-custom_checker');
|
||||
let $validator = $('#id_problem-data-custom_validator');
|
||||
let $validator = $('#id_problem-data-custom_checker_cpp');
|
||||
let $interactive = $('#id_problem-data-interactive_judge');
|
||||
let $sig_handler = $('#id_problem-data-signature_handler');
|
||||
let $sig_header = $('#id_problem-data-signature_header');
|
||||
|
@ -165,17 +167,17 @@
|
|||
|
||||
$checker.change(function () {
|
||||
$tr_checker.toggle($checker.val() == 'custom').change();
|
||||
$tr_validator.toggle($checker.val() == 'customval' || $checker.val() == 'testlib').change();
|
||||
$tr_validator.toggle($checker.val() == 'customcpp' || $checker.val() == 'testlib').change();
|
||||
$tr_interactive.toggle($checker.val() == 'interact').change();
|
||||
|
||||
$sample.toggle(['custom', 'customval', 'interact'].includes($checker.val())).change();
|
||||
$sample.toggle(['custom', 'customcpp', 'interact'].includes($checker.val())).change();
|
||||
}).change();
|
||||
|
||||
$ioi_signature.change(function() {
|
||||
$tr_sig_header.toggle($ioi_signature.is(':checked')).change();
|
||||
$tr_sig_handler.toggle($ioi_signature.is(':checked')).change();
|
||||
}).change();
|
||||
})();
|
||||
};
|
||||
|
||||
checker_precision($('#id_problem-data-checker'));
|
||||
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
<p>Authors: {{ link_users(authors) }}</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{{ solution.content|markdown|reference|str|safe }}
|
||||
{% cache 86400 'solution_content' solution.id %}
|
||||
{{ solution.content|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% endcache %}
|
||||
</div>
|
||||
<hr>
|
||||
{% include "actionbar/list.html" %}
|
||||
|
@ -36,8 +38,5 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block bodyend %}
|
||||
{% if REQUIRE_JAX %}
|
||||
{% include "mathjax-load.html" %}
|
||||
{% endif %}
|
||||
{% include "comments/math.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block middle_content %}
|
||||
<div class="tabs tabs-no-flex" style="width: 90%;margin-left: auto;margin-right: auto;">
|
||||
<div class="tabs tabs-no-flex">
|
||||
<ul>
|
||||
<li class="{{'active' if feed_type=='for_you'}}">
|
||||
<a href="{{url('problem_feed')}}">{{_('FOR YOU')}}</a>
|
||||
|
@ -27,5 +27,5 @@
|
|||
<li><a href="{{url('admin:judge_volunteerproblemvote_changelist')}}">{{_('View your votes')}}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% include "problem/feed/problems.html" %}
|
||||
{% include "problem/feed/items.html" %}
|
||||
{% endblock %}
|
|
@ -12,10 +12,10 @@
|
|||
<i class="unsolved-problem-color fa fa-minus-circle"></i>
|
||||
{% endif %}
|
||||
</h3>
|
||||
{% with authors=problem.authors.all() %}
|
||||
{% with authors=problem.get_authors() %}
|
||||
{% if authors %}
|
||||
<div class="problem-feed-info-entry">
|
||||
<i class="fa fa-pencil-square-o fa-fw"></i>
|
||||
<i class="far fa-pen-to-square"></i>
|
||||
<span class="pi-value">{{ link_users(authors) }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -30,7 +30,7 @@
|
|||
{% endif %}
|
||||
<div class="blog-description">
|
||||
<div class='content-description'>
|
||||
{% cache 86400 'problem_html' problem.id MATH_ENGINE LANGUAGE_CODE %}
|
||||
{% cache 86400 'problem_html' problem.id LANGUAGE_CODE %}
|
||||
{{ problem.description|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% endcache %}
|
||||
{% if problem.pdf_description %}
|
|
@ -1,9 +1,9 @@
|
|||
{% if not show_contest_mode %}
|
||||
<div class="left-sidebar">
|
||||
{{ make_tab_item('feed', 'fa fa-pagelines', url('problem_feed'), _('Feed')) }}
|
||||
{{ make_tab_item('feed', 'far fa-lightbulb', url('problem_feed'), _('Feed')) }}
|
||||
{{ make_tab_item('list', 'fa fa-list', url('problem_list'), _('List')) }}
|
||||
{% if request.user.is_superuser %}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
|
@ -86,12 +86,17 @@
|
|||
}
|
||||
|
||||
$category.select2().css({'visibility': 'visible'}).change(clean_submit);
|
||||
$('#types').select2({multiple: 1, placeholder: '{{ _('Filter by type...') }}'})
|
||||
.css({'visibility': 'visible'});
|
||||
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Groups') }}...'})
|
||||
.css({'visibility': 'visible'});
|
||||
$('#search-author').select2({multiple: 1, placeholder: '{{ _('Authors') }}...'})
|
||||
.css({'visibility': 'visible'});
|
||||
$('#types').select2({multiple: 1, placeholder: '{{ _('Filter by type...') }}'});
|
||||
$('#search-org').select2({multiple: 1, placeholder: '{{ _('Groups') }}...'});
|
||||
$('#search-author').select2({
|
||||
multiple: 1,
|
||||
placeholder: '{{ _('Authors') }}...',
|
||||
ajax: {
|
||||
url: '{{ url('problem_authors_select2_ajax') }}',
|
||||
delay: 250,
|
||||
cache: true,
|
||||
}
|
||||
});
|
||||
|
||||
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
|
||||
$search.keypress(function (e) {
|
||||
|
@ -108,7 +113,7 @@
|
|||
|
||||
$('#go').click(clean_submit);
|
||||
|
||||
$('input#full_text, input#hide_solved, input#show_types, input#have_editorial, input#show_solved_only').click(function () {
|
||||
$('input#full_text, input#hide_solved, input#show_types, input#have_editorial, input#show_solved_only, input#show_editorial').click(function () {
|
||||
prep_form();
|
||||
($('<form>').attr('action', window.location.pathname + '?' + form_serialize())
|
||||
.append($('<input>').attr('type', 'hidden').attr('name', 'csrfmiddlewaretoken')
|
||||
|
@ -149,8 +154,7 @@
|
|||
$(".edit-btn").on('click', function() {
|
||||
var pid = $(this).attr('pid');
|
||||
$('#volunteer-types-' + pid).css({'width': '100%'});
|
||||
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'})
|
||||
.css({'visibility': 'visible'});
|
||||
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'});
|
||||
|
||||
$('#form-' + pid).show();
|
||||
$('#submit-' + pid).show();
|
||||
|
|
|
@ -59,6 +59,21 @@
|
|||
placeholder: '{{ _('Leave empty to not filter by result') }}'
|
||||
});
|
||||
|
||||
$('#by-contest-filter').select2({
|
||||
multiple: true,
|
||||
placeholder: '{{ _('Leave empty to not filter by contest') }}',
|
||||
ajax: {
|
||||
url: "{{url('contest_select2')}}",
|
||||
data: function(params) {
|
||||
return {
|
||||
term: params.term,
|
||||
problem_id: {{problem.id}}
|
||||
};
|
||||
},
|
||||
delay: 250,
|
||||
}
|
||||
});
|
||||
|
||||
$('#rescore-all').click(function (e) {
|
||||
e.preventDefault();
|
||||
if (confirm(this.dataset.warning)) {
|
||||
|
@ -157,10 +172,14 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% if in_contest %}
|
||||
<label for="in-contest" name="in_contest">{{ _('In current contest') }}:</label>
|
||||
<input type="checkbox" name="in_contest">
|
||||
{% endif %}
|
||||
<div class="control-group">
|
||||
<label for="by-contest-filter">{{ _('Filter by contest:') }}</label>
|
||||
<select id="by-contest-filter" name="contest" multiple>
|
||||
{% if current_contest %}
|
||||
<option selected value="{{current_contest.id}}">{{ current_contest }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="pane">
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
{{ preview_data|markdown|reference|str|safe }}
|
||||
{% if REQUIRE_JAX %}
|
||||
<div data-config="{{ static('mathjax3_config.js') }}" class="require-mathjax-support"></div>
|
||||
{% endif %}
|
||||
{{ preview_data|markdown|reference|str|safe }}
|
|
@ -1,4 +1,7 @@
|
|||
{% extends "common-content.html" %}
|
||||
|
||||
{% set has_hidden_subtasks = request.in_contest_mode and request.participation.contest.format.has_hidden_subtasks %}
|
||||
|
||||
{% block content_media %}
|
||||
{% include "comments/media-css.html" %}
|
||||
<style>
|
||||
|
@ -62,11 +65,17 @@
|
|||
e.preventDefault();
|
||||
if (!$('#raw_problem').attr('src')) {
|
||||
$('#raw_problem').attr('src', '{{problem.code}}/raw')
|
||||
$('#raw_problem').on('load', function() {
|
||||
renderKatex(frames['raw_problem'].document);
|
||||
setTimeout(() => {
|
||||
frames['raw_problem'].print();
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
while(!$('.math-loaded', frames['raw_problem'].document).length){
|
||||
await new Promise(r => setTimeout(r, 200));
|
||||
else {
|
||||
frames['raw_problem'].print();
|
||||
return;
|
||||
}
|
||||
frames['raw_problem'].print();
|
||||
});
|
||||
$('#clarification_header').on('click', function() {
|
||||
$('#clarification_header_container').hide();
|
||||
|
@ -86,7 +95,7 @@
|
|||
|
||||
{% block title_row %}
|
||||
<div class="problem-title">
|
||||
{% if request.user.is_authenticated %}
|
||||
{% if request.user.is_authenticated and not has_hidden_subtasks %}
|
||||
{% if problem.id in completed_problem_ids %}
|
||||
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
|
||||
{% if problem.is_public or request.in_contest_mode %}
|
||||
|
@ -109,15 +118,10 @@
|
|||
{% if problem.is_organization_private %}
|
||||
<span class="organization-tags">
|
||||
{% for org in problem.organizations.all() %}
|
||||
<span class="organization-tag">
|
||||
<a href="{{ org.get_absolute_url() }}">
|
||||
<i class="fa fa-lock"></i> {{ org.name }}
|
||||
</a>
|
||||
</span>
|
||||
{% include "organization/tag.html" %}
|
||||
{% endfor %}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<span class="spacer"></span>
|
||||
{% if has_render %}
|
||||
<a href="{{ url('problem_pdf', problem.code) }}" class="view-pdf" target="_blank">
|
||||
|
@ -127,7 +131,7 @@
|
|||
<a id="pdf_button" class="view-pdf" href='#'>
|
||||
{% endif %}
|
||||
<span class="pdf-icon">
|
||||
<span class="fa fa-file-pdf-o pdf-icon-logo"></span>
|
||||
<span class="fa fa-file-pdf pdf-icon-logo"></span>
|
||||
<span class="pdf-icon-bar"></span>
|
||||
</span>
|
||||
{{ _('View as PDF') }}
|
||||
|
@ -135,11 +139,17 @@
|
|||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block info_float %}
|
||||
{% if request.user.is_authenticated and request.in_contest_mode and submission_limit %}
|
||||
{% if submissions_left > 0 %}
|
||||
<a href="{{ url('problem_submit', problem.code) }}" class="unselectable button full btn-green small">
|
||||
{{ _('Submit solution') }}
|
||||
<a href="{{ url('problem_submit', problem.code) }}">
|
||||
<button class="btn-green btn btn-primary btn-block btn-round">
|
||||
<span>{{ _('Submit') }}</span>
|
||||
<div class="icon icon-round d-flex align-items-center justify-content-center">
|
||||
<i class="fa fa-paper-plane"></i>
|
||||
</div>
|
||||
</button>
|
||||
</a>
|
||||
<div class="submissions-left">
|
||||
{% trans trimmed counter=submissions_left %}
|
||||
|
@ -149,116 +159,138 @@
|
|||
{% endtrans %}
|
||||
</div>
|
||||
{% else %}
|
||||
<a class="unselectable button full disabled small">{{ _('Submit solution') }}</a>
|
||||
<button class="btn btn-disabled btn-block btn-round">
|
||||
<span>{{ _('Submit') }}</span>
|
||||
<div class="icon icon-round d-flex align-items-center justify-content-center">
|
||||
<i class="fa fa-paper-plane"></i>
|
||||
</div>
|
||||
</button>
|
||||
<div class="no-submissions-left submissions-left">{{ _('0 submissions left') }}</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a href="{{ url('problem_submit', problem.code) }}" class="unselectable button full btn-green small">
|
||||
{{ _('Submit solution') }}
|
||||
<a href="{{ url('problem_submit', problem.code) }}">
|
||||
<button class="btn-green btn btn-primary btn-block btn-round">
|
||||
<span>{{ _('Submit') }}</span>
|
||||
<div class="icon icon-round d-flex align-items-center justify-content-center">
|
||||
<i class="fa fa-paper-plane"></i>
|
||||
</div>
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<hr style="padding-bottom: 0.3em">
|
||||
|
||||
{% if request.user.is_authenticated and has_submissions %}
|
||||
<div>
|
||||
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">{{ _('My submissions') }}</a>
|
||||
<div class="link-row">
|
||||
<a href="{{url('user_submissions', problem.code, request.user.username) }}">
|
||||
<i class="fa fa-address-book"></i><span> {{ _('My submissions') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div><a href="{{ url('chronological_submissions', problem.code) }}">{{ _('All submissions') }}</a></div>
|
||||
<div><a href="{{ url('ranked_submissions', problem.code) }}">{{ _('Best submissions') }}</a></div>
|
||||
{% if editorial and editorial.is_public and
|
||||
not (request.user.is_authenticated and request.in_contest_mode) %}
|
||||
<hr>
|
||||
<div><a href="{{ url('problem_editorial', problem.code) }}">{{ _('Read editorial') }}</a></div>
|
||||
{% endif %}
|
||||
{% if can_edit_problem %}
|
||||
<hr>
|
||||
<div>
|
||||
<a href="{{ url('problem_ticket_list', problem.code) }}">{{ _('Manage tickets') }}
|
||||
{% if num_open_tickets %}<span class="badge">{{ num_open_tickets }}</span>{% endif %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('chronological_submissions', problem.code) }}">
|
||||
<i class="fa fa-rectangle-list"></i><span> {{ _('All submissions') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div><a href="{{ url('admin:judge_problem_change', problem.id) }}">{{ _('Edit problem') }}</a></div>
|
||||
{% if not problem.is_manually_managed %}
|
||||
<div><a href="{{ url('problem_data', problem.code) }}">{{ _('Edit test data') }}</a></div>
|
||||
<div class="link-row">
|
||||
<a href="{{ url('ranked_submissions', problem.code) }}">
|
||||
<i class="fa fa-list-check"></i><span> {{ _('Best submissions') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% if editorial and editorial.is_public and not (request.user.is_authenticated and request.in_contest_mode) %}
|
||||
<hr>
|
||||
<div class="link-row">
|
||||
<a href="{{ url('problem_editorial', problem.code) }}">
|
||||
<i class="fa fa-newspaper"></i><span> {{ _('Read editorial') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% elif request.user.is_authenticated and has_tickets %}
|
||||
<hr>
|
||||
<div>
|
||||
<a href="{{ url('problem_ticket_list', problem.code) }}">{{ _('My tickets') }}
|
||||
{% if num_open_tickets %}<span class="badge">{{ num_open_tickets }}</span>{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if problem.is_subs_manageable_by(request.user) %}
|
||||
<div>
|
||||
<a href="{{ url('problem_manage_submissions', problem.code) }}">{{ _('Manage submissions') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.judge.clone_problem %}
|
||||
<div>
|
||||
<a href="{{ url('problem_clone', problem.code) }}">{{ _('Clone problem') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr style="padding-top: 0.3em">
|
||||
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-check fa-fw"></i><span class="pi-name">{{ _('Points:') }}</span>
|
||||
<span class="pi-value">
|
||||
{% if contest_problem %}
|
||||
{{ contest_problem.points }}{% if contest_problem.partial %} {{ _('(partial)') }}{% endif %}
|
||||
{% else %}
|
||||
{{ problem.points|floatformat }}{% if problem.partial %} {{ _('(partial)') }}{% endif %}
|
||||
{% if can_edit_problem %}
|
||||
<hr>
|
||||
<div class="link-row">
|
||||
<a href="{{ url('problem_ticket_list', problem.code) }}">
|
||||
<i class="fa fa-clipboard-list"></i><span> {{ _('Manage tickets') }}
|
||||
{% if num_open_tickets %}<span class="badge">{{ num_open_tickets }}</span>{% endif %}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="link-row">
|
||||
<a href="{{ url('admin:judge_problem_change', problem.id) }}">
|
||||
<i class="fa fa-edit"></i><span> {{ _('Edit problem') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% if not problem.is_manually_managed %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('problem_data', problem.code) }}">
|
||||
<i class="fa fa-database"></i><span> {{ _('Edit test data') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-clock-o fa-fw"></i><span class="pi-name">{{ _('Time limit:') }}</span>
|
||||
<span class="pi-value">{{ problem.time_limit }}s</span>
|
||||
</div>
|
||||
<div class="problem-lang-limits">
|
||||
{% for name, limit in problem.language_time_limit %}
|
||||
<div class="lang-limit">
|
||||
<span class="lang-name">{{ name }}</span>
|
||||
<span class="lang-tl">{{ limit }}s</span>
|
||||
{% elif request.user.is_authenticated and has_tickets %}
|
||||
<hr>
|
||||
<div class="link-row">
|
||||
<a href="{{ url('problem_ticket_list', problem.code) }}">
|
||||
<i class="fa fa-inbox"></i><span> {{ _('My tickets') }}
|
||||
{% if num_open_tickets %}<span class="badge">{{ num_open_tickets }}</span>{% endif %}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-server fa-fw"></i><span class="pi-name">{{ _('Memory limit:') }}</span>
|
||||
<span class="pi-value">{{ problem.memory_limit|kbsimpleformat }}</span>
|
||||
</div>
|
||||
<div class="problem-lang-limits">
|
||||
{% for name, limit in problem.language_memory_limit %}
|
||||
<div class="lang-limit">
|
||||
<span class="lang-name">{{ name }}</span>
|
||||
<span class="lang-ml">{{ limit|kbsimpleformat }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if problem.is_subs_manageable_by(request.user) %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('problem_manage_submissions', problem.code) }}">
|
||||
<i class="fas fa-table"></i><span> {{ _('Manage submissions') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-file-o fa-fw"></i><span class="pi-name">{{ _('Input:') }}</span>
|
||||
<span class="pi-value">
|
||||
{{ fileio_input or _('stdin') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-file fa-fw"></i><span class="pi-name">{{ _('Output:') }}</span>
|
||||
<span class="pi-value">{{ fileio_output or _('stdout') }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr style="padding-top: 0.7em">
|
||||
{% if perms.judge.clone_problem %}
|
||||
<div class="link-row">
|
||||
<a href="{{ url('problem_clone', problem.code) }}">
|
||||
<i class="fas fa-clone"></i><span> {{ _('Clone problem') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% cache 86400 'problem_authors' problem.id LANGUAGE_CODE %}
|
||||
{% with authors=problem.authors.all() %}
|
||||
{% if problem.language_time_limit or problem.language_memory_limit %}
|
||||
<hr style="padding-top: 0.3em">
|
||||
{% endif %}
|
||||
{% if problem.language_time_limit %}
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-clock"></i><span class="pi-name"> {{ _('Time limit:') }}</span>
|
||||
</div>
|
||||
<div class="problem-lang-limits">
|
||||
{% for name, limit in problem.language_time_limit %}
|
||||
<div class="lang-limit">
|
||||
<span class="lang-name">{{ name }}</span>
|
||||
<span class="lang-tl">{{ limit }}s</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if problem.language_memory_limit %}
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-server"></i><span class="pi-name"> {{ _('Memory limit:') }}</span>
|
||||
</div>
|
||||
<div class="problem-lang-limits">
|
||||
{% for name, limit in problem.language_memory_limit %}
|
||||
<div class="lang-limit">
|
||||
<span class="lang-name">{{ name }}</span>
|
||||
<span class="lang-ml">{{ limit|kbsimpleformat }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif%}
|
||||
|
||||
<hr style="padding-top: 0.7em">
|
||||
|
||||
{% with authors=problem.get_authors() %}
|
||||
{% if authors %}
|
||||
<div class="problem-info-entry">
|
||||
<i class="fa fa-pencil-square-o fa-fw"></i><span
|
||||
class="pi-name">{% trans trimmed count=authors|length %}
|
||||
<i class="far fa-pen-to-square"></i><span
|
||||
class="pi-name"> {% trans trimmed count=authors|length %}
|
||||
Author:
|
||||
{% pluralize count %}
|
||||
Authors:
|
||||
|
@ -267,68 +299,67 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endcache %}
|
||||
|
||||
{% if not contest_problem or not contest_problem.contest.hide_problem_tags %}
|
||||
<div id="problem-types">
|
||||
{% with types=problem.types_list %}
|
||||
<div class="toggle closed unselectable">
|
||||
<i class="fa fa-chevron-right fa-fw"></i>{% trans trimmed count=problem.types_list|length %}
|
||||
Problem type
|
||||
{% pluralize count %}
|
||||
Problem types
|
||||
{% endtrans %}
|
||||
</div>
|
||||
<div style="display:none" class="toggled">{{ problem.types_list|join(", ") }}</div>
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if show_languages %}
|
||||
<div id="allowed-langs">
|
||||
<div class="toggle open unselectable">
|
||||
<i class="fa fa-chevron-right fa-fw"></i>{{ _('Allowed languages') }}
|
||||
</div>
|
||||
<div class="toggled">
|
||||
{% with usable=problem.usable_common_names, langs=problem.languages_list() %}
|
||||
{% for lang in langs %}
|
||||
{%- if lang in usable -%}
|
||||
{{ lang }}
|
||||
{%- else -%}
|
||||
<s title="{{ _('No %(lang)s judge online', lang=lang) }}">{{ lang }}</s>
|
||||
{%- endif -%}
|
||||
{% if not loop.last %}, {% endif -%}
|
||||
{% endfor %}
|
||||
{% if not contest_problem or not contest_problem.contest.hide_problem_tags %}
|
||||
<div id="problem-types">
|
||||
{% with types=problem.types_list %}
|
||||
<div class="toggle closed unselectable">
|
||||
<i class="fa fa-chevron-right"></i> {% trans trimmed count=problem.types_list|length %}
|
||||
Problem type
|
||||
{% pluralize count %}
|
||||
Problem types
|
||||
{% endtrans %}
|
||||
</div>
|
||||
<div style="display:none" class="toggled">{{ problem.types_list|join(", ") }}</div>
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if problem.is_editable_by(request.user) %}
|
||||
<div id="available-judges">
|
||||
<div class="toggle closed" id="judge-toggle">
|
||||
<i class="fa fa-chevron-right fa-fw"></i><span
|
||||
class="pi-name">{% trans trimmed count=available_judges|length %}
|
||||
Judge
|
||||
{% pluralize count %}
|
||||
Judges
|
||||
{% endtrans %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="pi-value judges-value toggled" style="display: none;">
|
||||
{% if available_judges %}
|
||||
{% if perms.judge.change_judge %}
|
||||
{% for judge in available_judges %}
|
||||
<a href="{{ url('admin:judge_judge_change', judge.id) }}">{{ judge.name }}</a>
|
||||
{%- if not loop.last %}, {% endif %}
|
||||
{% endif %}
|
||||
{% if show_languages %}
|
||||
<div id="allowed-langs">
|
||||
<div class="toggle open unselectable">
|
||||
<i class="fa fa-chevron-right"></i> {{ _('Allowed languages') }}
|
||||
</div>
|
||||
<div class="toggled">
|
||||
{% with usable=problem.usable_common_names, langs=problem.languages_list() %}
|
||||
{% for lang in langs %}
|
||||
{%- if lang in usable -%}
|
||||
{{ lang }}
|
||||
{%- else -%}
|
||||
<s title="{{ _('No %(lang)s judge online', lang=lang) }}">{{ lang }}</s>
|
||||
{%- endif -%}
|
||||
{% if not loop.last %}, {% endif -%}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ available_judges|join(", ") }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i class="red">{{ _('none available') }}</i>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if problem.is_editable_by(request.user) %}
|
||||
<div id="available-judges">
|
||||
<div class="toggle closed" id="judge-toggle">
|
||||
<i class="fa fa-chevron-right"></i><span
|
||||
class="pi-name"> {% trans trimmed count=available_judges|length %}
|
||||
Judge
|
||||
{% pluralize count %}
|
||||
Judges
|
||||
{% endtrans %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="pi-value judges-value toggled" style="display: none;">
|
||||
{% if available_judges %}
|
||||
{% if perms.judge.change_judge %}
|
||||
{% for judge in available_judges %}
|
||||
<a href="{{ url('admin:judge_judge_change', judge.id) }}">{{ judge.name }}</a>
|
||||
{%- if not loop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ available_judges|join(", ") }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i class="red">{{ _('none available') }}</i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block description %}
|
||||
|
@ -342,8 +373,42 @@
|
|||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class = "new-problem-info d-flex-problem">
|
||||
<span class="info-block">
|
||||
<i class="fa fa-check"></i><span class="pi-name"> {{ _('Points:') }}</span>
|
||||
<span class="new-pi-value">
|
||||
{% if contest_problem %}
|
||||
{{ contest_problem.points }} {% if contest_problem.partial %}(p){% endif %}
|
||||
{% else %}
|
||||
{{ problem.points|floatformat }} {% if problem.partial %}(p){% endif %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{% cache 86400 'problem_html' problem.id MATH_ENGINE LANGUAGE_CODE %}
|
||||
<span class="info-block">
|
||||
<i class="fa fa-clock"></i><span class="pi-name"> {{ _('Time limit:') }}</span>
|
||||
<span class="new-pi-value">{{ problem.time_limit }}s</span>
|
||||
</span>
|
||||
|
||||
<span class="info-block">
|
||||
<i class="fa fa-server"></i><span class="pi-name"> {{ _('Memory limit:') }}</span>
|
||||
<span class="new-pi-value">{{ problem.memory_limit|kbsimpleformat }}</span>
|
||||
</span>
|
||||
|
||||
<span class="info-block">
|
||||
<i class="fa fa-file"></i><span class="pi-name"> {{ _('Input:') }}</span>
|
||||
<span class="new-pi-value">
|
||||
{{ fileio_input or _('stdin') }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<i class="fa fa-file"></i><span class="pi-name"> {{ _('Output:') }}</span>
|
||||
<span class="new-pi-value">{{ fileio_output or _('stdout') }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% cache 86400 'problem_html' problem.id LANGUAGE_CODE %}
|
||||
{{ description|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% endcache %}
|
||||
|
||||
|
|
|
@ -92,16 +92,7 @@
|
|||
<div class="content-description printing">
|
||||
{{ description|markdown|reference|absolutify(url)|str|safe }}
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="{{ static('mathjax3_config.js') }}"></script>
|
||||
<script type="text/javascript" src="mathjax3_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">
|
||||
MathJax.Hub.Register.StartupHook("End", function () {
|
||||
if (typeof window.callPhantom === 'function')
|
||||
window.callPhantom({'action': 'snapshot'});
|
||||
document.body.classList.add('math-loaded');
|
||||
});
|
||||
</script>
|
||||
<script src="{{ static('katex_config.js') }}"></script>
|
||||
{% include "katex-load.html" %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
<div class="filter-form-group">
|
||||
<label class="bold-text margin-label" for="type"><i class="non-italics">{{ _('Author') }}</i></label>
|
||||
<label class="bold-text margin-label" for="search-author"><i class="non-italics">{{ _('Author') }}</i></label>
|
||||
<select id="search-author" name="authors" multiple>
|
||||
{% for author in all_authors %}
|
||||
<option value="{{ author.id }}"{% if author.id in author_query %} selected{% endif %}>
|
||||
{{ author.user__username }}
|
||||
{% for author in author_query %}
|
||||
<option value="{{ author.id }}" selected>
|
||||
{{ author.username }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
@ -84,8 +84,10 @@
|
|||
</select>
|
||||
</div>
|
||||
{% if point_values %}
|
||||
<div style="margin-top: 5px;" class="bold-text margin-label" class="form-label">{{ _('Point range') }}</div>
|
||||
<div id="point-slider"></div>
|
||||
<div class="filter-form-group">
|
||||
<div class="bold-text margin-label" class="form-label">{{ _('Point range') }}</div>
|
||||
<div id="point-slider"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<input id="point-start" type="hidden" name="point_start" {% if point_start and point_start != point_values.min %}value="{{ point_start }}"{% else %}disabled{% endif %}>
|
||||
<input id="point-end" type="hidden" name="point_end" {% if point_end and point_end != point_values.max %}value="{{ point_end }}"{% else %}disabled{% endif %}>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
});
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -32,7 +32,31 @@
|
|||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% if request.in_contest and next_valid_submit_time and not (submission_limit and submissions_left <= 0) %}
|
||||
$(function () {
|
||||
const $submitButton = $("#submit-button");
|
||||
$submitButton.prop('disabled', true);
|
||||
const nextValidDate = new Date("{{next_valid_submit_time}}");
|
||||
|
||||
function updateCountdown() {
|
||||
var now = new Date();
|
||||
var timeUntilNextValid = nextValidDate - now;
|
||||
|
||||
if (timeUntilNextValid > 0) {
|
||||
var seconds = Math.floor(timeUntilNextValid / 1000);
|
||||
$("#countdown-timer").text("{{_("Wait")}} " + seconds + "s");
|
||||
setTimeout(updateCountdown, 1000);
|
||||
} else {
|
||||
$("#countdown-timer").text("");
|
||||
$submitButton.prop('disabled', false);
|
||||
}
|
||||
}
|
||||
updateCountdown();
|
||||
});
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
{% compress js %}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
|
@ -228,8 +252,9 @@
|
|||
{{ form.source_file }}
|
||||
<div class="submit-bar">
|
||||
{{ form.judge }}
|
||||
<input type="submit" value="{{ _('Submit!') }}" class="button small"
|
||||
{% if request.in_contest and submission_limit and not submissions_left %}disabled{% endif %}>
|
||||
<input id="submit-button" type="submit" value="{{ _('Submit!') }}" class="button small"
|
||||
{% if request.in_contest and submission_limit and submissions_left <= 0 %}disabled{% endif %}>
|
||||
<span id="countdown-timer"></span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<div class="source-wrap">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="source-ln">
|
||||
<div>
|
||||
{% for line in raw_source.split('\n') %}
|
||||
<a href="#line-{{ loop.index }}" name="line-{{ loop.index }}">
|
||||
<pre>{{ loop.index }}</pre>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="source-code">{{ highlighted_source }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{{ highlighted_source }}</td>
|
||||
{% endblock %}
|
77
templates/profile-table.html
Normal file
77
templates/profile-table.html
Normal file
|
@ -0,0 +1,77 @@
|
|||
{% if request.profile %}
|
||||
<div class="blog-sidebox sidebox">
|
||||
<h3 class="bold-text colored-text"><i class="fa fa-user"></i>{{ _('Profile') }}</h3>
|
||||
<div class="toggled sidebox-content">
|
||||
<div class="profile-card">
|
||||
<div class="card-header">
|
||||
<a href="{{url('user_page')}}">
|
||||
<img class="avatar" src="{{ gravatar(request.profile) }}" alt="User Avatar">
|
||||
</a>
|
||||
<h4>{{ link_user(request.profile) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="user-info">
|
||||
<div><i class="fa fa-star {{request.profile.css_class}}"></i> {{_('Rating')}}</div>
|
||||
<div class="{{ request.profile.css_class }}">{{ request.profile.rating if request.profile.rating else '-' }}</div>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div
|
||||
title="
|
||||
{%- trans trimmed counter=request.profile.problem_count %}
|
||||
{{ counter }} problem solved
|
||||
{% pluralize %}
|
||||
{{ counter }} problems solved
|
||||
{% endtrans -%}"
|
||||
><i class="green icofont-tick-mark"></i> {{_('Problems')}}</div>
|
||||
<span class="user-info-body">{{ request.profile.problem_count }}</span>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div
|
||||
title="{{_('Total points')}}"
|
||||
><i class="fa fa-trophy darkcyan"></i> {{_('Points')}}</div>
|
||||
<div class="user-info-body"><span title="{{ request.profile.performance_points|floatformat(2) }}">
|
||||
{{ request.profile.performance_points|floatformat(0) }}
|
||||
</span></div>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div title="{{_('Rank by rating')}}"><i class="fa fa-globe peru" ></i> {{_('Rating')}} #</div>
|
||||
<div class="user-info-body">{{rating_rank if rating_rank else '-'}}</div>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div title="{{_('Rank by points')}}"><i class="fa fa-globe blue" ></i> {{_('Points')}} #</div>
|
||||
<div class="user-info-body">{{points_rank if points_rank else '-'}}</div>
|
||||
</div>
|
||||
|
||||
{% if awards.medals %}
|
||||
<div class="user-info">
|
||||
<div title="{{ _('Awards') }}"><i class="fa fa-medal"></i> {{ _('Awards') }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if awards %}
|
||||
<div class="medals-container">
|
||||
{% if awards.gold_count > 0 %}
|
||||
<div class="medal-item">
|
||||
<img src="{{ static('awards/gold-medal.png') }}" alt="Gold Medal">
|
||||
<span class="medal-count">{{ awards.gold_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if awards.silver_count > 0 %}
|
||||
<div class="medal-item">
|
||||
<img src="{{ static('awards/silver-medal.png') }}" alt="Silver Medal">
|
||||
<span class="medal-count">{{ awards.silver_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if awards.bronze_count > 0 %}
|
||||
<div class="medal-item">
|
||||
<img src="{{ static('awards/bronze-medal.png') }}" alt="Bronze Medal">
|
||||
<span class="medal-count">{{ awards.bronze_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
|
@ -1,29 +1,15 @@
|
|||
{% block two_col_media %}
|
||||
<style>
|
||||
.org-logo {
|
||||
vertical-align: middle;
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
display: inline-block;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.toggle {
|
||||
cursor: pointer;
|
||||
}
|
||||
.organization-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% if recent_organizations %}
|
||||
<div class="blog-sidebox sidebox">
|
||||
<h3 class="bold-text colored-text"><i class="fa fa-users"></i>{{ _('Recent groups') }}</h3>
|
||||
<h3 class="bold-text colored-text"><i class="fa fa-building-columns"></i>{{ _('Recent groups') }}</h3>
|
||||
<div class="toggled sidebox-content">
|
||||
{% for organization in recent_organizations %}
|
||||
<a href="{{ url('organization_home', organization.organization.pk, organization.organization.slug) }}" class="organization-row" title="{{organization.organization.about}}">
|
||||
<img class="org-logo" data-src="{{ organization.organization.logo_override_image or static('icons/icon.png') }}">
|
||||
<span style="word-break: break-word;">{{ organization.organization }}</span>
|
||||
<a href="{{ url('organization_home', organization.pk, organization.slug) }}" class="organization-row">
|
||||
{% if organization.logo_override_image %}
|
||||
<img class="org-logo user-img" loading="lazy" src="{{ organization.logo_override_image }}">
|
||||
{% else %}
|
||||
<img class="org-logo" loading="lazy" src="{{ static('icons/icon.svg') }}" onerror="{{static('icons/logo.svg')}}">
|
||||
{% endif %}
|
||||
<span style="word-break: break-word;">{{ organization.name }}</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{% set username = user.get_username() %}
|
||||
{% set button_text = _("Activate") %}
|
||||
{% set domain = site.domain %}
|
||||
{% set protocol = "http" %}
|
||||
{% set protocol = "https" if request.is_secure() else "http" %}
|
||||
{% include "general_email.html" %}
|
||||
<br>
|
||||
{{_("Alternatively, you can reply to this message to activate your account. Your reply must keep the following text intact for this to work:")}}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% csrf_token %}
|
||||
{% if form.errors %}
|
||||
<div id="form-errors">
|
||||
<p class="error">{{ _('Invalid username or password.') }}</p>
|
||||
<p class="error">{{ _('Invalid username/email or password.') }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<table border="0" style="text-align:left">
|
||||
|
@ -33,17 +33,17 @@
|
|||
<h4>{{ _('Or log in with...') }}</h4>
|
||||
{% if form.has_google_auth %}
|
||||
<a href="{{ url('social:begin', "google-oauth2") }}?next={{ next }}" class="social google-icon">
|
||||
<i class="fa fa-google-plus-square"></i>
|
||||
<i class="fab fa-square-google-plus"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if form.has_facebook_auth %}
|
||||
<a href="{{ url('social:begin', "facebook") }}?next={{ next }}" class="social facebook-icon">
|
||||
<i class="fa fa-facebook-square"></i>
|
||||
<i class="fab fa-facebook-square"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if form.has_github_auth %}
|
||||
<a href="{{ url('social:begin', "github-secure") }}?next={{ next }}" class="social github-icon">
|
||||
<i class="fa fa-github-square"></i>
|
||||
<i class="fab fa-github-square"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
|
@ -30,11 +30,13 @@
|
|||
{% block js_media %}{{ form.media.js }}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form action="" method="post" class="form-area">
|
||||
{% csrf_token %}
|
||||
<table border="0" style="text-align:left">{{ form.as_table() }}</table>
|
||||
<input type="submit" style="float:right;" value="{{ _('Continue >') }}">
|
||||
</form>
|
||||
<div id="center-float" class="registration-form">
|
||||
<form action="" method="post" class="form-area">
|
||||
{% csrf_token %}
|
||||
<table border="0" style="text-align:left">{{ form.as_table() }}</table>
|
||||
<input type="submit" style="float:right;" value="{{ _('Continue >') }}">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="map-wrap">
|
||||
<div class="map-inset">
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
{% elif logo_override_image is defined and logo_override_image %}
|
||||
<img src="{{ logo_override_image|camo }}" alt="{{ SITE_NAME }}" height="44" style="border: none">
|
||||
{% else %}
|
||||
<img src="{{ static('icons/logo.png') }}" alt="{{ SITE_NAME }}" height="44"
|
||||
<img src="{{ static('icons/logo.svg') }}" alt="{{ SITE_NAME }}" height="44"
|
||||
onerror="this.src="{{ static('icons/logo.png') }}"; this.onerror=null" style="border: none">
|
||||
{% endif %}
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
{{ preview_data|markdown|reference|str|safe }}
|
||||
{% if REQUIRE_JAX %}
|
||||
<div data-config="{{ static('mathjax3_config.js') }}" class="require-mathjax-support"></div>
|
||||
{% endif %}
|
|
@ -13,6 +13,6 @@
|
|||
{% if request.profile.id in submission.problem.editor_ids or perms.judge.edit_all_problem %}
|
||||
<hr style="float:left;width:30%"><br>
|
||||
<h4>{{ _('Error information') }}</h4>
|
||||
<code>{{ submission.error|highlight('pytb', linenos=False) }}</code>
|
||||
<code>{{ submission.error|highlight('pytb', linenos=True) }}</code>
|
||||
{% endif %}
|
||||
{% endif %}
|
|
@ -1,4 +1,7 @@
|
|||
{% extends "three-column-content.html" %}
|
||||
|
||||
{% set has_hidden_subtasks = request.in_contest_mode and request.participation.contest.format.has_hidden_subtasks %}
|
||||
|
||||
{% block three_col_js %}
|
||||
<script type="text/javascript">
|
||||
{% if dynamic_update and last_msg %}
|
||||
|
@ -249,7 +252,7 @@
|
|||
</script>
|
||||
{% endcompress %}
|
||||
|
||||
{% if dynamic_update and last_msg %}
|
||||
{% if dynamic_update and last_msg and not has_hidden_subtasks %}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
load_dynamic_update({{last_msg}});
|
||||
|
@ -272,10 +275,6 @@
|
|||
col.sub-info, td.sub-info {
|
||||
width: 78%
|
||||
}
|
||||
|
||||
#status, #language {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
|
||||
|
@ -392,7 +391,7 @@
|
|||
{{ make_tab_item('friend_tab', 'fa fa-users', friend_submissions_link, _('Friends')) }}
|
||||
{% endif %}
|
||||
{% if perms.judge.change_submission %}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_submission_changelist'), _('Admin')) }}
|
||||
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_submission_changelist'), _('Admin'), force_new_page=True) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,82 +1,69 @@
|
|||
{% set can_view = submission.is_accessible_by(profile) %}
|
||||
<div class="sub-result {{ submission._result_class if in_hidden_subtasks_contest else submission.result_class }}">
|
||||
<div class="score">
|
||||
{%- if submission.is_graded -%}
|
||||
{%- if submission.status in ('IE', 'CE', 'AB') -%}
|
||||
---
|
||||
{%- else -%}
|
||||
{{ submission.case_points|floatformat(0) }} / {{ submission.case_total|floatformat(0) }}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
<i class="fa fa-spinner fa-pulse"></i>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
<div class="state">
|
||||
{% if in_hidden_subtasks_contest and submission.is_graded %}
|
||||
<span>
|
||||
{% set ns = namespace(is_first=False) %}
|
||||
{% for batch in submission.batches %}
|
||||
{% if batch.id %}
|
||||
{{ '+' if ns.is_first else '' }}
|
||||
{% set ns.is_first = True %}
|
||||
<span class={{'green' if batch.AC else 'red'}}>
|
||||
{{ batch.points|floatformat(0) }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</span>
|
||||
{% else %}
|
||||
{% if not in_hidden_subtasks_contest or submission.status in ('IE', 'CE', 'AB') %}
|
||||
<span title="{{ submission.long_status }}" class="status">{{ submission.short_status }}</span> |
|
||||
{% endif %}
|
||||
<span class="language">{{ submission.language.short_display_name }}</span>
|
||||
{% set can_view = submission.is_accessible_by(profile, check_contest=False) or is_in_editable_contest %}
|
||||
<div class="sub-user-img user-img">
|
||||
<img loading="lazy" src="{{gravatar(submission.user)}}">
|
||||
</div>
|
||||
<div class="sub-details">
|
||||
<div class="sub-info{% if submission.status == 'G' %} sub-info-grading{% endif %}">
|
||||
<div class="sub-user" style="max-width: {{50 if show_problem else 100}}%">
|
||||
{{ link_user(submission.user) }}
|
||||
</div>
|
||||
{% if show_problem %}
|
||||
<span>—</span>
|
||||
<div class="sub-problem"><a href="{{ url('problem_detail', submission.problem.code) }}">{{ problem_name }}</a></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="sub-info{% if submission.status == 'G' %} sub-info-grading{% endif %}">
|
||||
{% if show_problem %}
|
||||
<div class="name"><a href="{{ url('problem_detail', submission.problem.code) }}">{{ problem_name }}</a></div>
|
||||
{% endif %}
|
||||
<div>
|
||||
{{ link_user(submission.user) }}
|
||||
<span class="time">{{ relative_time(submission.date) }}</span>
|
||||
{% if not request.in_contest_mode and submission.contest_object_id %}
|
||||
<div class="sub-result">
|
||||
<div class="state {{ submission._result_class if in_hidden_subtasks_contest else submission.result_class }}">
|
||||
{% if in_hidden_subtasks_contest and submission.is_graded %}
|
||||
<span>
|
||||
{% set ns = namespace(is_first=False) %}
|
||||
{% for batch in submission.batches %}
|
||||
{% if batch.id %}
|
||||
{{ '+' if ns.is_first else '' }}
|
||||
{% set ns.is_first = True %}
|
||||
<span class={{'green' if batch.AC else 'red'}}>
|
||||
{{ batch.points|floatformat(0) }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</span>
|
||||
{% else %}
|
||||
{% if not in_hidden_subtasks_contest or submission.status in ('IE', 'CE', 'AB') %}
|
||||
<span title="{{ submission.long_status }}" class="status">{{ submission.short_status }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="score">
|
||||
{%- if submission.is_graded -%}
|
||||
{%- if submission.status in ('IE', 'CE', 'AB') -%}
|
||||
---
|
||||
{%- else -%}
|
||||
{{ submission.case_points|floatformat(0) }} / {{ submission.case_total|floatformat(0) }}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
<i class="fa fa-spinner fa-pulse"></i>
|
||||
{% if submission.status == 'G' and not in_hidden_subtasks_contest %}
|
||||
<span class="sub-testcase">
|
||||
{%- if submission.current_testcase > 0 -%}
|
||||
{{ _('%(point)s / #%(case)s', point=submission.points|floatformat(1), case=submission.current_testcase-1) }}
|
||||
{%- endif -%}
|
||||
</span>
|
||||
{% endif %}
|
||||
{%- endif -%}
|
||||
</div>
|
||||
<div class="language">
|
||||
{{ submission.language.short_display_name }}
|
||||
</div>
|
||||
<span class="time">{{ relative_time(submission.date, format=_("d/m/Y"))}}</span>
|
||||
{% if not hide_contest_in_row and submission.contest_object_id %}
|
||||
<a href="{{ url('contest_view', submission.contest_object.key) }}"
|
||||
class="submission-contest">
|
||||
<i title="{{ submission.contest_object.name }}" class="fa fa-dot-circle-o"></i>
|
||||
<i title="{{ submission.contest_object.name }}" class="far fa-dot-circle"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if submission.status == 'G' and not in_hidden_subtasks_contest %}
|
||||
<div class="sub-testcase">
|
||||
{%- if submission.current_testcase > 0 -%}
|
||||
{{ _('Point %(point)s / Case #%(case)s', point=submission.points|floatformat(1), case=submission.current_testcase) }}
|
||||
{%- else -%}
|
||||
...
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if can_view %}
|
||||
<div class="sub-prop"><div>
|
||||
<a href="{{ url('submission_status', submission.id) }}">
|
||||
<i class="fa fa-eye fa-fw"></i><span class="label">{{ _('view') }}</span>
|
||||
</a>
|
||||
{% if perms.judge.rejudge_submission %} ·
|
||||
<a href="#" onclick="rejudge_submission({{ submission.id }}, event);return false">
|
||||
<i class="fa fa-refresh fa-fw"></i><span class="label">{{ _('rejudge') }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.judge.change_submission %} ·
|
||||
<a href="{{ url('admin:judge_submission_change', submission.id) }}">
|
||||
<i class="fa fa-cog fa-fw"></i><span class="label">{{ _('admin') }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div></div>
|
||||
{% endif %}
|
||||
|
||||
<div class="sub-usage">
|
||||
{% if submission.status in ('QU', 'P', 'G', 'CE', 'IE', 'AB') or in_hidden_subtasks_contest %}
|
||||
<div class="time">---</div>
|
||||
|
@ -91,4 +78,21 @@
|
|||
{% endif %}
|
||||
<div class="memory">{{ (submission.memory_bytes|filesizeformat(True)).replace('i', '') }}</div>
|
||||
{% endif %}
|
||||
{% if can_view %}
|
||||
<div class="sub-prop"><div>
|
||||
<a href="{{ url('submission_status', submission.id) }}">
|
||||
<i class="fa fa-eye fa-fw"></i><span class="label">{{ _('view') }}</span>
|
||||
</a>
|
||||
{% if perms.judge.rejudge_submission %} ·
|
||||
<a href="#" onclick="rejudge_submission({{ submission.id }}, event);return false">
|
||||
<i class="fa fa-refresh fa-fw"></i><span class="label">{{ _('rejudge') }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.judge.change_submission %} ·
|
||||
<a href="{{ url('admin:judge_submission_change', submission.id) }}">
|
||||
<i class="fa fa-cog fa-fw"></i><span class="label">{{ _('admin') }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div></div>
|
||||
{% endif %}
|
||||
</div>
|
|
@ -1,64 +0,0 @@
|
|||
{% extends "submission/info-base.html" %}
|
||||
{% block media %}
|
||||
<style>
|
||||
.line {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.highlighter {
|
||||
position: absolute;
|
||||
width: 9999px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
a:active .line .highlighter {
|
||||
background: rgba(255, 212, 0, 0.48);
|
||||
}
|
||||
|
||||
.copy-clipboard {
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div style="clear: both"></div>
|
||||
<br>
|
||||
<div><a href="{{ url('submission_status', submission.id) }}">{{ _('View status') }}</a></div>
|
||||
<div><a href="{{ url('submission_source_raw', submission.id) }}">{{ _('View raw source') }}</a></div>
|
||||
{% if request.user == submission.user.user or perms.judge.resubmit_other %}
|
||||
<div><a href="{{ url('problem_submit', submission.problem.code, submission.id) }}">{{ _('Resubmit') }}</a></div>
|
||||
{% endif %}
|
||||
{% if perms.judge.rejudge_submission %}
|
||||
<div>
|
||||
<form action="{{ url('submission_rejudge') }}" method="post">
|
||||
{% csrf_token %}
|
||||
<a href="#" onclick="parentNode.submit()">{{ _('Rejudge') }}</a>
|
||||
<input type="hidden" name="id" value="{{ submission.id }}">
|
||||
<input type="hidden" name="path" value="{{ url('submission_status', submission.id) }}">
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
<div class="source-wrap">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td class="source-ln" style="width: 0">
|
||||
<div>
|
||||
{% for line in raw_source.split('\n') %}
|
||||
<a href="#line-{{ loop.index }}" name="line-{{ loop.index }}">
|
||||
<pre class="line">{{ loop.index }}</pre>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="source-code">{{ highlighted_source }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -10,14 +10,14 @@
|
|||
<pre>{{ submission.error|ansi2html }}</pre>
|
||||
{% else %}
|
||||
{% if submission.error %}
|
||||
<h3><i class="fa fa-exclamation-triangle fa-fw"></i>{{ _('Compilation Warnings') }}</h3>
|
||||
<h3><i class="fa fa-exclamation-triangle"></i>{{ _('Compilation Warnings') }}</h3>
|
||||
<pre>{{ submission.error|ansi2html }}</pre>
|
||||
<hr><br>
|
||||
{% endif %}
|
||||
{% if is_pretest %}
|
||||
<h3><i class="fa fa-check-square-o fa-fw"></i>{{ _('Pretest Execution Results') }}</h3>
|
||||
<h3><i class="far fa-check-square"></i> {{ _('Pretest Execution Results') }}</h3>
|
||||
{% else %}
|
||||
<h3><i class="fa fa-check-square-o fa-fw"></i>{{ _('Execution Results') }}</h3>
|
||||
<h3><i class="far fa-check-square"></i> {{ _('Execution Results') }}</h3>
|
||||
{% endif %}
|
||||
|
||||
{% for batch in batches %}
|
||||
|
|
|
@ -135,37 +135,28 @@
|
|||
{% block body %}
|
||||
<div style="clear: both"></div>
|
||||
<br>
|
||||
{% if request.user == submission.user.user or perms.judge.resubmit_other %}
|
||||
<div><a href="{{ url('problem_submit', submission.problem.code, submission.id) }}">{{ _('Resubmit') }}</a></div>
|
||||
{% endif %}
|
||||
{% if perms.judge.rejudge_submission %}
|
||||
<div>
|
||||
<form action="{{ url('submission_rejudge') }}" method="post">
|
||||
{% csrf_token %}
|
||||
<a href="#" onclick="parentNode.submit()">{{ _('Rejudge') }}</a>
|
||||
<input type="hidden" name="id" value="{{ submission.id }}">
|
||||
<input type="hidden" name="path" value="{{ url('submission_status', submission.id) }}">
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div style="width: fit-content;">
|
||||
{% if request.profile == submission.user or perms.judge.resubmit_other %}
|
||||
<div class="link-row"><a href="{{ url('problem_submit', submission.problem.code, submission.id) }}">
|
||||
<i class="fa fa-upload"></i>{{ _('Resubmit') }}</a></div>
|
||||
{% endif %}
|
||||
{% if perms.judge.rejudge_submission %}
|
||||
<div class="link-row">
|
||||
<form action="{{ url('submission_rejudge') }}" method="post">
|
||||
{% csrf_token %}
|
||||
<a href="#" onclick="parentNode.submit()">
|
||||
<i class="fa fa-rotate-right"></i>{{ _('Rejudge') }}</a>
|
||||
<input type="hidden" name="id" value="{{ submission.id }}">
|
||||
<input type="hidden" name="path" value="{{ url('submission_status', submission.id) }}">
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h3 id="source-header" class="toggle closed"><i class="fa fa-chevron-right fa-fw"></i>{{_('Source code')}}</h3>
|
||||
<div class="source-wrap toggled" style="display: none; margin-bottom: 1em">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td class="source-ln" style="width: 0">
|
||||
<div>
|
||||
{% for line in raw_source.split('\n') %}
|
||||
<a href="#line-{{ loop.index }}" name="line-{{ loop.index }}">
|
||||
<pre class="line">{{ loop.index }}</pre>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="source-code">{{ highlighted_source }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="toggled" style="display: none; margin-bottom: 1em">
|
||||
{{ highlighted_source }}
|
||||
</div>
|
||||
|
||||
<div id="test-cases">{% include "submission/status-testcases.html" %}</div>
|
||||
|
|
91
templates/test_formatter/download_test_formatter.html
Normal file
91
templates/test_formatter/download_test_formatter.html
Normal file
|
@ -0,0 +1,91 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block media %}
|
||||
<style>
|
||||
.container {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
.preview-container {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
#preview {
|
||||
background-color: rgb(220, 220, 220);
|
||||
border: solid 2px rgb(180, 180, 180);
|
||||
padding: 8px;
|
||||
max-height: 134px;
|
||||
height: 20%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.button-container {
|
||||
text-align:left;
|
||||
}
|
||||
.button {
|
||||
display:inline-block;
|
||||
}
|
||||
.copyright {
|
||||
position: absolute;
|
||||
bottom: 48px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_media %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("#download").on("click", function(event) {
|
||||
event.preventDefault()
|
||||
var file_path = document.getElementById('file_path').value;
|
||||
$.ajax({
|
||||
url: "{{url('test_formatter_download')}}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
file_path: file_path
|
||||
},
|
||||
xhrFields: {
|
||||
responseType: 'blob'
|
||||
},
|
||||
success: function(data) {
|
||||
var url = window.URL.createObjectURL(data);
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = file_path.split('/').pop();
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
},
|
||||
error: function(error) {
|
||||
alert(error);
|
||||
console.log(error.message)
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<input type="hidden" id="file_path" value={{file_path}}>
|
||||
<input type="hidden" id="file_path_getnames" value={{file_path_getnames}}>
|
||||
|
||||
<div class="preview-container">
|
||||
<h2>{{_('Download')}}</h2><br>
|
||||
<h4>{{file_name}}</h4><br>
|
||||
<div id="preview">
|
||||
{{ response|safe }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button type="submit" id="download" class="button">{{_('Download')}}</button>
|
||||
<a href="{{url('test_formatter_edit')}}?file_path={{file_path_getnames}}" id="edit" class="button">{{_('Edit')}}</a>
|
||||
</div>
|
||||
<div class="copyright">
|
||||
<p >{{_('Copyright')}} Nguyễn Tiến Trung Kiên</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
140
templates/test_formatter/edit_test_formatter.html
Normal file
140
templates/test_formatter/edit_test_formatter.html
Normal file
|
@ -0,0 +1,140 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block media %}
|
||||
<style>
|
||||
.container {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
.column {
|
||||
flex: 50%;
|
||||
}
|
||||
.left {
|
||||
padding-right: 16px;
|
||||
}
|
||||
.right {
|
||||
padding-left: 16px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
.preview-container {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.copyright {
|
||||
position: absolute;
|
||||
bottom: 48px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
#preview {
|
||||
background-color: rgb(220, 220, 220);
|
||||
border: solid 2px rgb(180, 180, 180);
|
||||
padding: 8px;
|
||||
max-height: 134px;
|
||||
height: 20%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.button-container {
|
||||
text-align:left;
|
||||
}
|
||||
.button {
|
||||
display:inline-block;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block js_media %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("#convert").on("click", function(event) {
|
||||
event.preventDefault()
|
||||
$.ajax({
|
||||
url: "{{url('test_formatter_edit')}}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'convert',
|
||||
bef_inp_format: $("#bef_inp_format").val(),
|
||||
bef_out_format: $("#bef_out_format").val(),
|
||||
aft_inp_format: $("#aft_inp_format").val(),
|
||||
aft_out_format: $("#aft_out_format").val(),
|
||||
file_name: $('#file_name').val()
|
||||
},
|
||||
success: function(data) {
|
||||
console.log(data)
|
||||
$('#preview').html(data);
|
||||
},
|
||||
error: function(error) {
|
||||
alert(error);
|
||||
console.log(error.message)
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#download").on("click", function(event) {
|
||||
event.preventDefault()
|
||||
$.ajax({
|
||||
url: "{{url('test_formatter_edit')}}",
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'download'
|
||||
},
|
||||
success: function(data) {
|
||||
var file_path = data;
|
||||
window.location.href = "{{url('test_formatter_download')}}" + "?file_path="+file_path;
|
||||
},
|
||||
error: function(error) {
|
||||
alert(error);
|
||||
console.log(error.message)
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{% csrf_token %}
|
||||
<div class="column left">
|
||||
<h3>{{_('Before')}}</h3><br>
|
||||
<label for="fname">{{_('Input format')}}</label><br>
|
||||
<input type="text" id="bef_inp_format" value="{{files_list[0]}}" readonly><br>
|
||||
<label for="lname">{{_('Output format')}}</label><br>
|
||||
<input type="text" id="bef_out_format" value="{{files_list[1]}}" readonly><br><br>
|
||||
|
||||
</div>
|
||||
<div class="column right">
|
||||
<h3>{{_('After')}}</h3><br>
|
||||
<label for="fname">{{_('Input format')}}</label><br>
|
||||
<input type="text" id="aft_inp_format" value="input.000"><br>
|
||||
<label for="lname">{{_('Output format')}}</label><br>
|
||||
<input type="text" id="aft_out_format" value="output.000"><br><br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-container">
|
||||
<h3>{{_('Preview')}}</h3><br>
|
||||
<div id="preview">
|
||||
{{ res|safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filename-container">
|
||||
<h3>{{_('File name')}}</h3><br>
|
||||
<input type="text" id="file_name" value="{{file_name}}"><br><br>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button type="submit" id="convert" class="button">{{_('Convert')}}</button>
|
||||
<button type="submit" id="download" class="button">{{_('Download')}}</button>
|
||||
</div>
|
||||
<div class="copyright">
|
||||
<p >{{_('Copyright')}} Nguyễn Tiến Trung Kiên</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
23
templates/test_formatter/test_formatter.html
Normal file
23
templates/test_formatter/test_formatter.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block media %}
|
||||
<style>
|
||||
.copyright {
|
||||
position: absolute;
|
||||
bottom: 48px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<center>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<button type="submit" style="margin-top: 2em">{{_('Upload')}}</button>
|
||||
</form>
|
||||
<div class="copyright">
|
||||
<p >{{_('Copyright')}} Nguyễn Tiến Trung Kiên</p>
|
||||
</div>
|
||||
</center>
|
||||
{% endblock %}
|
|
@ -30,37 +30,17 @@
|
|||
<script type="text/javascript">
|
||||
let loadingPage;
|
||||
|
||||
function activateBlogBoxOnClick() {
|
||||
$('.blog-box').on('click', function () {
|
||||
var $description = $(this).children('.blog-description');
|
||||
var max_height = $description.css('max-height');
|
||||
if (max_height !== 'fit-content') {
|
||||
$description.css('max-height', 'fit-content');
|
||||
$(this).css('cursor', 'auto');
|
||||
$(this).removeClass('pre-expand-blog');
|
||||
$(this).children().children('.show-more').hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('.blog-box').each(function () {
|
||||
var $precontent = $(this).children('.blog-description').height();
|
||||
var $content = $(this).children().children('.content-description').height();
|
||||
if ($content == undefined) {
|
||||
$content = $(this).children().children('.md-typeset').height()
|
||||
}
|
||||
if ($content > $precontent - 30) {
|
||||
$(this).addClass('pre-expand-blog');
|
||||
$(this).css('cursor', 'pointer');
|
||||
} else {
|
||||
$(this).children().children('.show-more').hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function navigateTo($elem, update_sidebar = false) {
|
||||
var url = $elem.attr('href');
|
||||
var force_new_page = $elem.data('force_new_page');
|
||||
|
||||
if (url === '#') return;
|
||||
|
||||
if (force_new_page) {
|
||||
window.location.href = url;
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_sidebar) {
|
||||
$('.left-sidebar-item').removeClass('active');
|
||||
$elem.addClass('active');
|
||||
|
@ -75,6 +55,7 @@
|
|||
$('html, body').animate({scrollTop: 0}, 'fast');
|
||||
$('.middle-right-content').html(reload_content.first().html());
|
||||
$('#extra_js').html(bodyend_script.first().html());
|
||||
$("#loading-bar").stop(true, true);
|
||||
$("#loading-bar").hide().css({ width: 0});
|
||||
if (reload_content.hasClass("wrapper")) {
|
||||
$('.middle-right-content').addClass("wrapper");
|
||||
|
@ -83,9 +64,8 @@
|
|||
$('.middle-right-content').removeClass("wrapper");
|
||||
}
|
||||
$(document).prop('title', $(data).filter('title').text());
|
||||
MathJax.typeset($('.middle-right-content')[0]);
|
||||
renderKatex($('.middle-right-content')[0]);
|
||||
onWindowReady();
|
||||
activateBlogBoxOnClick();
|
||||
$('.xdsoft_datetimepicker').hide();
|
||||
registerNavigation();
|
||||
}
|
||||
|
@ -96,12 +76,16 @@
|
|||
}
|
||||
|
||||
function registerNavigation() {
|
||||
const links = ['.pagination a', '.tabs li a'];
|
||||
for (link of links) {
|
||||
$(link).on('click', function (e) {
|
||||
e.preventDefault();
|
||||
navigateTo($(this));
|
||||
})
|
||||
const links = ['.pagination a', '.tabs li a', '#control-panel a'];
|
||||
for (let linkSelector of links) {
|
||||
$(linkSelector).each(function() {
|
||||
if ($(this).attr('target') !== '_blank') {
|
||||
$(this).on('click', function(e) {
|
||||
e.preventDefault();
|
||||
navigateTo($(this));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +93,6 @@
|
|||
window.addEventListener('popstate', (e) => {
|
||||
window.location.href = e.currentTarget.location.href;
|
||||
});
|
||||
activateBlogBoxOnClick();
|
||||
|
||||
$('.left-sidebar-item').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
@ -123,8 +106,8 @@
|
|||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% macro make_tab_item(name, fa, url, text) %}
|
||||
<a class="left-sidebar-item {% if page_type == name %}active{% endif %}" href="{{ url }}" id="{{ name }}-tab">
|
||||
{% macro make_tab_item(name, fa, url, text, force_new_page=False) %}
|
||||
<a class="left-sidebar-item {% if page_type == name %}active{% endif %}" href="{{ url }}" id="{{ name }}-tab" {% if force_new_page%}data-force_new_page="1"{% endif %}>
|
||||
<span class="sidebar-icon"><i class="{{ fa }}"></i></span>
|
||||
<span class="sidebar-text">{{ text }}</span>
|
||||
</a>
|
||||
|
@ -152,8 +135,5 @@
|
|||
|
||||
{% block bodyend %}
|
||||
{{ super() }}
|
||||
{% if REQUIRE_JAX %}
|
||||
{% include "mathjax-load.html" %}
|
||||
{% endif %}
|
||||
{% include "comments/math.html" %}
|
||||
{% endblock %}
|
|
@ -8,20 +8,21 @@
|
|||
{{ ticket.title }}
|
||||
</a>
|
||||
</h3>
|
||||
{% with author=ticket.user %}
|
||||
{% if author %}
|
||||
{% with author_id = ticket.user_id %}
|
||||
{% if author_id %}
|
||||
<div class="problem-feed-info-entry">
|
||||
<i class="fa fa-pencil-square-o fa-fw"></i>
|
||||
<span class="pi-value">{{ link_user(author) }}</span>
|
||||
<i class="far fa-pen-to-square"></i>
|
||||
<span class="pi-value">{{ link_user(author_id) }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% set last_message = ticket.messages.last() %}
|
||||
<div class="problem-feed-types">
|
||||
<i class="fa fa-tag"></i>
|
||||
{{link_user(ticket.messages.last().user)}} {{_(' replied')}}
|
||||
{{link_user(last_message.user_id)}} {{_('replied')}}
|
||||
</div>
|
||||
<div class='blog-description content-description'>
|
||||
{{ ticket.messages.last().body|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{{ last_message.body|markdown(lazy_load=True)|reference|str|safe }}
|
||||
<div class="show-more"> {{_("...More")}} </div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
{% block media %}
|
||||
<style>
|
||||
#ticket-list .fa-check-circle-o {
|
||||
#ticket-list .fa-check-circle {
|
||||
color: #00a900;
|
||||
}
|
||||
|
||||
|
@ -131,10 +131,10 @@
|
|||
if ($row.length) {
|
||||
var $status = $row.find('td').first().find('i');
|
||||
if (ticket.open) {
|
||||
$status.removeClass('fa-check-circle-o').addClass('fa-exclamation-circle');
|
||||
$status.removeClass('fa-check-circle').addClass('fa-exclamation-circle');
|
||||
notify('ticket', '{{ _('Reopened: ') }}' + ticket.title);
|
||||
} else {
|
||||
$status.removeClass('fa-exclamation-circle').addClass('fa-check-circle-o');
|
||||
$status.removeClass('fa-exclamation-circle').addClass('fa-check-circle');
|
||||
notify('ticket', '{{ _('Closed: ') }}' + ticket.title);
|
||||
}
|
||||
}
|
||||
|
@ -193,6 +193,8 @@
|
|||
}
|
||||
};
|
||||
},
|
||||
delay: 250,
|
||||
cache: true,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div class="header">
|
||||
<div class="info">
|
||||
<a class="user-container" href="{{ url('user_page', message.user.user.username) }}" class="user">
|
||||
<img src="{{ gravatar(message.user, 135) }}" class="gravatar">
|
||||
<img loading="lazy" src="{{ gravatar(message.user, 135) }}" class="gravatar">
|
||||
<span class="username {{ message.user.css_class }}">{{ message.user.user.username }}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
{{ preview_data|markdown|reference|str|safe }}
|
||||
{% if REQUIRE_JAX %}
|
||||
<div data-config="{{ static('mathjax3_config.js') }}" class="require-mathjax-support"></div>
|
||||
{% endif %}
|
||||
{{ preview_data|markdown|reference|str|safe }}
|
|
@ -1,5 +1,5 @@
|
|||
<tr id="ticket-{{ ticket.id }}">
|
||||
<td><i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle-o{% endif %}"></i></td>
|
||||
<td><i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle{% endif %}"></i></td>
|
||||
<td>{{ ticket.id }}</td>
|
||||
<td><a href="{{ url('ticket', ticket.id) }}">{{ ticket.title }}</a></td>
|
||||
<td>{{ link_user(ticket.user) }}</td>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
{% block js_media %}
|
||||
{{ form.media.js }}
|
||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
||||
<script type="text/javascript" src="{{ static('event.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
|
@ -14,9 +13,9 @@
|
|||
|
||||
function update_ticket_state(open) {
|
||||
if (open)
|
||||
$status.removeClass('fa-check-circle-o').addClass('fa-exclamation-circle');
|
||||
$status.removeClass('fa-check-circle').addClass('fa-exclamation-circle');
|
||||
else
|
||||
$status.removeClass('fa-exclamation-circle').addClass('fa-check-circle-o');
|
||||
$status.removeClass('fa-exclamation-circle').addClass('fa-check-circle');
|
||||
$('.close-ticket').toggle(open);
|
||||
$('.open-ticket').toggle(!open);
|
||||
}
|
||||
|
@ -145,7 +144,7 @@
|
|||
|
||||
{% block content_title %}
|
||||
<span class="status">
|
||||
<i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle-o{% endif %}"></i>
|
||||
<i class="fa {% if ticket.is_open %}fa-exclamation-circle{% else %}fa-check-circle{% endif %}"></i>
|
||||
</span>
|
||||
<span class="title">{{ ticket.title }}</span><small>#{{ ticket.id }}</small>
|
||||
{% endblock %}
|
||||
|
@ -162,7 +161,7 @@
|
|||
<section class="message new-message">
|
||||
<div class="info">
|
||||
<a href="{{ url('user_page', request.user.username) }}" class="user">
|
||||
<img src="{{ gravatar(request.profile, 135) }}" class="gravatar">
|
||||
<img loading="lazy" src="{{ gravatar(request.profile, 135) }}" class="gravatar">
|
||||
<div class="username {{ request.profile.css_class }}">{{ request.user.username }}</div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -227,8 +226,5 @@
|
|||
|
||||
{% block bodyend %}
|
||||
{{ super() }}
|
||||
{% if REQUIRE_JAX %}
|
||||
{% include "mathjax-load.html" %}
|
||||
{% endif %}
|
||||
{% include "comments/math.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{% compress js %}
|
||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
||||
<script type="text/javascript" src="{{ static('libs/timezone-map/timezone-picker.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
<style>
|
||||
@media (min-width: 800px) {
|
||||
.middle-content {
|
||||
max-width: none;
|
||||
padding-left: 1em;
|
||||
min-width: 96%;
|
||||
max-width: 96%;
|
||||
margin-left: 2%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue