mirror of
https://github.com/DMOJ/online-judge.git
synced 2024-11-25 16:32:37 +08:00
eda67c54e2
There should never be that much stuff in MiscConfig, so let's just read it all and deal with it in python instead of trying to run one query for each item of interest and poorly cache it. This PR also moved MiscConfigDict into a middleware so it can be used outside of templates.
313 lines
13 KiB
HTML
313 lines
13 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="{{ LANGUAGE_CODE }}">
|
|
<head>
|
|
<title>{% block title %}{{ title }} - {{ SITE_LONG_NAME }}{% endblock %}</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
{% if misc_config.meta_keywords %}
|
|
<meta name="keywords" content="{{ misc_config.meta_keywords }}">
|
|
{% endif %}
|
|
{% if meta_description %}
|
|
<meta name="description" content="{{ meta_description }}">
|
|
{% endif %}
|
|
<meta id="viewport" name="viewport" content="width=device-width, initial-scale=1">
|
|
<!-- Favicons-->
|
|
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
|
|
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
|
|
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
|
|
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
|
|
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
|
|
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
|
|
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
|
|
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
|
|
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
|
|
<link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
|
|
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
|
|
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
|
|
<link rel="manifest" href="/manifest.json">
|
|
<meta name="msapplication-TileColor" content="#FFBB33">
|
|
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
|
|
{# Chrome 39 for Android colour #}
|
|
<meta name="theme-color" content="#FFBB33">
|
|
{% if og_image %}
|
|
<meta property="og:image" content="{{ request.build_absolute_uri(og_image) }}">
|
|
{% endif %}
|
|
{% block og_title %}{% endblock %}
|
|
<meta property="og:site_name" content="{{ SITE_LONG_NAME }}">
|
|
<meta property="og:url"
|
|
content="{{ DMOJ_SCHEME }}://{{ DMOJ_CANONICAL|default(site.domain) }}{{ request.get_full_path() }}">
|
|
{% if meta_description %}
|
|
<meta property="og:description" content="{{ meta_description }}">
|
|
{% endif %}
|
|
{% block meta %}{% endblock %}
|
|
{% if not INLINE_FONTAWESOME %}
|
|
<link rel="stylesheet" href="{{ FONTAWESOME_CSS }}">
|
|
{% endif %}
|
|
{% compress css %}
|
|
{# TODO: once dark mode support is better, enable for all users by deleting the else branch #}
|
|
{% if perms.judge.test_site %}
|
|
{% if PREFERRED_STYLE_CSS is not none %}
|
|
<link rel="stylesheet" href="{{ static(PREFERRED_STYLE_CSS) }}">
|
|
{% else %}
|
|
<link rel="stylesheet" href="{{ static(LIGHT_STYLE_CSS) }}" media="(prefers-color-scheme: light)">
|
|
<link rel="stylesheet" href="{{ static(DARK_STYLE_CSS) }}" media="(prefers-color-scheme: dark)">
|
|
{% endif %}
|
|
{% else %}
|
|
<link rel="stylesheet" href="{{ static(LIGHT_STYLE_CSS) }}">
|
|
{% endif %}
|
|
{% if INLINE_FONTAWESOME %}<link rel="stylesheet" href="{{ static('libs/fontawesome/font-awesome.css') }}">{% endif %}
|
|
<link rel="stylesheet" type="text/css" href="{{ static('libs/clipboard/tooltip.css') }}">
|
|
<link rel="stylesheet" type="text/css" href="{{ static('libs/select2/select2.css') }}">
|
|
{% endcompress %}
|
|
<link rel="canonical"
|
|
href="{{ DMOJ_SCHEME }}://{{ DMOJ_CANONICAL|default(site.domain) }}{{ request.get_full_path() }}">
|
|
{% if request.user.is_impersonate %}
|
|
<style>
|
|
#nav-container {
|
|
background: #893e89 !important;
|
|
}
|
|
</style>
|
|
{% endif %}
|
|
{% block media %}{% endblock %}
|
|
{% if not INLINE_JQUERY %}
|
|
<script src="{{ JQUERY_JS }}"></script>
|
|
{% endif %}
|
|
|
|
{% compress js %}
|
|
<script>{{ inlinei18n(LANGUAGE_CODE)|safe }}</script>
|
|
{% if INLINE_JQUERY %}
|
|
<script src="{{ static('libs/jquery-3.4.1.min.js') }}"></script>
|
|
{% endif %}
|
|
<script src="{{ static('libs/jquery-cookie.js') }}"></script>
|
|
<script src="{{ static('libs/jquery-taphold.js') }}"></script>
|
|
<script src="{{ static('libs/jquery.unveil.js') }}"></script>
|
|
<script src="{{ static('libs/moment.js') }}"></script>
|
|
<script src="{{ static('libs/select2/select2.js') }}"></script>
|
|
{% include "extra_js.html" %}
|
|
<script src="{{ static('common.js') }}"></script>
|
|
<script>
|
|
moment.locale('{{ LANGUAGE_CODE }}');
|
|
set_date_locale('{{ LANGUAGE_CODE }}');
|
|
$(function () {
|
|
$('img.unveil').unveil(200);
|
|
});
|
|
</script>
|
|
{% endcompress %}
|
|
{% block js_media %}{% endblock %}
|
|
{% if request.in_contest %}
|
|
<script>$(function () {
|
|
count_down($("#contest-time-remaining"));
|
|
|
|
var selected = null,
|
|
x_pos = 0, y_pos = 0,
|
|
x_elem = 0, y_elem = 0;
|
|
|
|
$('#contest-info').mousedown(function () {
|
|
selected = $(this);
|
|
x_elem = x_pos - selected.offset().left;
|
|
y_elem = y_pos - (selected.offset().top - $(window).scrollTop());
|
|
return false;
|
|
});
|
|
|
|
if (localStorage.getItem("contest_timer_pos")) {
|
|
data = localStorage.getItem("contest_timer_pos").split(":");
|
|
$("#contest-info").css({
|
|
left: data[0],
|
|
top: data[1]
|
|
});
|
|
}
|
|
|
|
$("#contest-info").show();
|
|
|
|
$(document).mousemove(function (e) {
|
|
x_pos = e.screenX;
|
|
y_pos = e.screenY;
|
|
x_pos = Math.max(Math.min(x_pos, window.innerWidth), 0);
|
|
y_pos = Math.max(Math.min(y_pos, window.innerHeight), 0);
|
|
|
|
if (selected !== null) {
|
|
left_px = (x_pos - x_elem) + 'px';
|
|
top_px = (y_pos - y_elem) + 'px';
|
|
|
|
localStorage.setItem("contest_timer_pos", left_px + ":" + top_px);
|
|
|
|
selected.css({
|
|
left: left_px,
|
|
top: top_px
|
|
});
|
|
}
|
|
});
|
|
|
|
$(document).mouseup(function () {
|
|
selected = null;
|
|
})
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
|
|
{% if request.user.is_authenticated and not tfa_in_progress %}
|
|
<script>
|
|
window.user = {
|
|
email: '{{ request.user.email|escapejs }}',
|
|
id: '{{ request.user.id|escapejs }}',
|
|
name: '{{ request.user.username|escapejs }}'
|
|
};
|
|
</script>
|
|
{% else %}
|
|
<script>window.user = {};</script>
|
|
{% endif %}
|
|
|
|
{% if misc_config.analytics %}
|
|
{{ misc_config.analytics|safe }}
|
|
{% endif %}
|
|
|
|
{# Don't run userscript since it may be malicious #}
|
|
{% if request.user.is_authenticated and request.profile.user_script and not request.user.is_impersonate and not tfa_in_progress and not ignore_user_script %}
|
|
<script type="text/javascript">{{ request.profile.user_script|safe }}</script>
|
|
{% endif %}
|
|
|
|
<noscript>
|
|
<style>
|
|
#content {
|
|
margin: 80px auto auto;
|
|
}
|
|
|
|
#navigation {
|
|
top: 27px;
|
|
}
|
|
</style>
|
|
</noscript>
|
|
</head>
|
|
<body>
|
|
<svg width="0" height="0" style="display: block">
|
|
<defs>
|
|
<clipPath id="rating-clip"><circle cx="8" cy="8" r="7"/></clipPath>
|
|
</defs>
|
|
</svg>
|
|
<nav id="navigation" class="unselectable">
|
|
<div id="nav-container">
|
|
<a id="navicon" href="javascript:void(0)"><i class="fa fa-bars"></i></a>
|
|
<ul id="nav-list">
|
|
<li class="home-nav-element"><a href="{{ url('home') }}">{% include "site-logo-fragment.html" %}</a></li>
|
|
<li class="home-nav-element"><span class="nav-divider"></span></li>
|
|
<li class="home-menu-item"><a href="{{ url('home') }}" class="nav-home">{{ _('Home') }}</a></li>
|
|
{% for node in mptt_tree(nav_bar) recursive %}
|
|
<li>
|
|
<a href="{{ node.path }}" class="nav-{{ node.key }}{% if node.key in nav_tab %} active{% endif %}">
|
|
{{ user_trans(node.label) }}
|
|
{% if not node.is_leaf_node() %}
|
|
<div class="nav-expand">></div>
|
|
{% endif %}
|
|
</a>
|
|
{% with children=node.get_children() %}
|
|
{% if children %}<ul>{{ loop(children) }}</ul>{% endif %}
|
|
{% endwith %}
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
|
|
<span id="user-links">
|
|
{% if request.user.is_authenticated %}
|
|
<ul>
|
|
<li>
|
|
<a href="{{ url('user_page') }}">
|
|
<span>
|
|
<img src="{{ gravatar(request.user, 32) }}" height="24" width="24">{# -#}
|
|
<span>{{ _('Hello, %(username)s.', username=bold(request.profile.display_name)) }}</span>
|
|
</span>
|
|
</a>
|
|
<ul style="width: 150px">
|
|
{% if request.user.is_staff or request.user.is_superuser %}
|
|
<li><a href="{{ url('admin:index') }}">{{ _('Admin') }}</a></li>
|
|
{% endif %}
|
|
<li><a href="{{ url('user_edit_profile') }}">{{ _('Edit profile') }}</a></li>
|
|
{% if request.user.is_impersonate %}
|
|
<li><a href="{{ url('impersonate-stop') }}">{{ _('Stop impersonating') }}</a></li>
|
|
{% else %}
|
|
<li>
|
|
<form action="{{ url('auth_logout') }}" method="POST">
|
|
{% csrf_token %}
|
|
<button type="submit">{{ _('Log out') }}</button>
|
|
</form>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
{% else %}
|
|
<span class="anon">
|
|
<a href="{{ url('auth_login') }}?next={{ LOGIN_RETURN_PATH|urlencode }}"><b>{{ _('Log in') }}</b></a>
|
|
{{ _('or') }}
|
|
<a href="{{ url('registration_register') }}"><b>{{ _('Sign up') }}</b></a>
|
|
</span>
|
|
{% endif %}
|
|
</span>
|
|
</div>
|
|
<div id="nav-shadow"></div>
|
|
</nav>
|
|
{% if request.in_contest %}
|
|
<div id="contest-info">
|
|
<a href="{{ url('contest_view', request.participation.contest.key) }}" style="vertical-align: middle">
|
|
{{ request.participation.contest.name }} -
|
|
{% if request.participation.spectate %}
|
|
{{ _('spectating') }}
|
|
{% elif request.participation.end_time %}
|
|
<div id="contest-time-remaining" data-secs="{{ request.participation.time_remaining|seconds }}">
|
|
{{ request.participation.time_remaining|timedelta("localized") }}
|
|
</div>
|
|
{% else %}
|
|
{{ _('virtual') }}
|
|
{% endif %}
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
<div id="page-container">
|
|
<noscript>
|
|
<div id="noscript">{{ _('This site works best with JavaScript enabled.') }}</div>
|
|
</noscript>
|
|
<br>
|
|
<main id="content">
|
|
{% block title_row %}
|
|
<h2 style="display:inline">
|
|
{% block content_title %}
|
|
{% if content_title %}{{ content_title }}{% else %}{{ title }}{% endif %}
|
|
{% endblock %}
|
|
</h2>
|
|
{% endblock %}
|
|
{% block header %}{% endblock %}
|
|
{% block title_ruler %}
|
|
<hr>
|
|
{% endblock %}
|
|
<div id="content-body">{% block body %}{% endblock %}</div>
|
|
</main>
|
|
|
|
{% if misc_config.announcement %}
|
|
<div id="announcement">{{ misc_config.announcement|safe }}</div>
|
|
{% endif %}
|
|
|
|
{% block bodyend %}{% endblock %}
|
|
|
|
<footer>
|
|
<span id="footer-content">
|
|
<br>
|
|
<a style="color: #808080" href="https://dmoj.ca">{{ _('proudly powered by **DMOJ**')|markdown('default', strip_paragraphs=True) }}</a> |
|
|
{% if misc_config.footer %}
|
|
{{ misc_config.footer|safe }} |
|
|
{% endif %}
|
|
<form action="{{ url('set_language') }}" method="post" style="display: inline">
|
|
{% csrf_token %}
|
|
<input name="next" type="hidden" value="{{ request.get_full_path() }}">
|
|
<select name="language" onchange="form.submit()" style="height: 1.5em">
|
|
{% for language in language_info_list(LANGUAGES) %}
|
|
<option value="{{ language.code }}" {% if language.code == LANGUAGE_CODE %}selected{% endif %}>
|
|
{{ language.name_local }} ({{ language.code }})
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</form>
|
|
</span>
|
|
</footer>
|
|
</div>
|
|
</body>
|
|
</html>
|