Rewrite org page

This commit is contained in:
cuom1999 2022-05-27 23:28:22 -05:00
parent 05ff359f89
commit 82ec9e098d
22 changed files with 1190 additions and 777 deletions

View file

@ -587,6 +587,16 @@ urlpatterns = [
organization.OrganizationUsers.as_view(), organization.OrganizationUsers.as_view(),
name="organization_users", name="organization_users",
), ),
url(
r"^/problems$",
organization.OrganizationProblems.as_view(),
name="organization_problems",
),
url(
r"^/contests$",
organization.OrganizationContests.as_view(),
name="organization_contests",
),
url( url(
r"^/join$", r"^/join$",
organization.JoinOrganization.as_view(), organization.JoinOrganization.as_view(),

View file

@ -106,6 +106,12 @@ class Organization(models.Model):
def get_users_url(self): def get_users_url(self):
return reverse("organization_users", args=(self.id, self.slug)) return reverse("organization_users", args=(self.id, self.slug))
def get_problems_url(self):
return reverse("organization_problems", args=(self.id, self.slug))
def get_contests_url(self):
return reverse("organization_contests", args=(self.id, self.slug))
class Meta: class Meta:
ordering = ["name"] ordering = ["name"]
permissions = ( permissions = (

View file

@ -69,31 +69,15 @@ class FeedView(ListView):
now = timezone.now() now = timezone.now()
# Dashboard stuff
# if self.request.user.is_authenticated:
# user = self.request.profile
# context['recently_attempted_problems'] = (Submission.objects.filter(user=user)
# .exclude(problem__in=user_completed_ids(user))
# .values_list('problem__code', 'problem__name', 'problem__points')
# .annotate(points=Max('points'), latest=Max('date'))
# .order_by('-latest')
# [:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT])
visible_contests = ( visible_contests = (
Contest.get_visible_contests(self.request.user) Contest.get_visible_contests(self.request.user)
.filter(is_visible=True) .filter(is_visible=True)
.order_by("start_time") .order_by("start_time")
) )
context["current_contests"] = visible_contests.filter( context["current_contests"] = visible_contests.filter(
start_time__lte=now, end_time__gt=now start_time__lte=now, end_time__gt=now
) )
context["future_contests"] = visible_contests.filter(start_time__gt=now) context["future_contests"] = visible_contests.filter(start_time__gt=now)
visible_contests = Contest.get_visible_contests(self.request.user).filter(
is_visible=True
)
context["top_rated"] = Profile.objects.filter(is_unlisted=False).order_by( context["top_rated"] = Profile.objects.filter(is_unlisted=False).order_by(
"-rating" "-rating"
)[:10] )[:10]

View file

@ -146,9 +146,15 @@ class ContestList(
self.contest_query = None self.contest_query = None
self.org_query = [] self.org_query = []
if "orgs" in self.request.GET: if "orgs" in self.request.GET and self.request.profile:
try: try:
self.org_query = list(map(int, request.GET.getlist("orgs"))) self.org_query = list(map(int, request.GET.getlist("orgs")))
self.org_query = [
i
for i in self.org_query
if i
in self.request.profile.organizations.values_list("id", flat=True)
]
except ValueError: except ValueError:
pass pass
@ -215,7 +221,9 @@ class ContestList(
context["first_page_href"] = "." context["first_page_href"] = "."
context["contest_query"] = self.contest_query context["contest_query"] = self.contest_query
context["org_query"] = self.org_query context["org_query"] = self.org_query
context["organizations"] = Organization.objects.all() if self.request.profile:
context["organizations"] = self.request.profile.organizations.all()
context["page_type"] = "list"
context.update(self.get_sort_context()) context.update(self.get_sort_context())
context.update(self.get_sort_paginate_context()) context.update(self.get_sort_paginate_context())
return context return context

View file

@ -7,8 +7,14 @@ from django.core.cache.utils import make_template_fragment_key
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db import transaction from django.db import transaction
from django.db.models import Count, Q, Value, BooleanField from django.db.models import Count, Q, Value, BooleanField
from django.db.utils import ProgrammingError
from django.forms import Form, modelformset_factory from django.forms import Form, modelformset_factory
from django.http import Http404, HttpResponsePermanentRedirect, HttpResponseRedirect from django.http import (
Http404,
HttpResponsePermanentRedirect,
HttpResponseRedirect,
HttpResponseBadRequest,
)
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -18,6 +24,7 @@ from django.views.generic.detail import (
SingleObjectMixin, SingleObjectMixin,
SingleObjectTemplateResponseMixin, SingleObjectTemplateResponseMixin,
) )
from django.core.paginator import Paginator
from reversion import revisions from reversion import revisions
from judge.forms import EditOrganizationForm from judge.forms import EditOrganizationForm
@ -37,11 +44,15 @@ from judge.utils.views import (
QueryStringSortMixin, QueryStringSortMixin,
DiggPaginatorMixin, DiggPaginatorMixin,
) )
from judge.views.problem import ProblemList
from judge.views.contests import ContestList
__all__ = [ __all__ = [
"OrganizationList", "OrganizationList",
"OrganizationHome", "OrganizationHome",
"OrganizationUsers", "OrganizationUsers",
"OrganizationProblems",
"OrganizationContests",
"OrganizationMembershipChange", "OrganizationMembershipChange",
"JoinOrganization", "JoinOrganization",
"LeaveOrganization", "LeaveOrganization",
@ -111,6 +122,12 @@ class OrganizationDetailView(OrganizationMixin, DetailView):
context = self.get_context_data(object=self.object) context = self.get_context_data(object=self.object)
return self.render_to_response(context) return self.render_to_response(context)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["can_edit"] = self.can_edit_organization()
context["is_member"] = self.is_member()
return context
class OrganizationList(TitleMixin, ListView, OrganizationBase): class OrganizationList(TitleMixin, ListView, OrganizationBase):
model = Organization model = Organization
@ -139,19 +156,8 @@ class OrganizationList(TitleMixin, ListView, OrganizationBase):
class OrganizationHome(OrganizationDetailView): class OrganizationHome(OrganizationDetailView):
template_name = "organization/home.html" template_name = "organization/home.html"
def get_context_data(self, **kwargs): def get_posts(self):
context = super(OrganizationHome, self).get_context_data(**kwargs) posts = (
context["title"] = self.object.name
context["can_edit"] = self.can_edit_organization()
context["is_member"] = self.is_member()
context["new_problems"] = Problem.objects.filter(
is_public=True, is_organization_private=True, organizations=self.object
).order_by("-date", "-id")[: settings.DMOJ_BLOG_NEW_PROBLEM_COUNT]
context["new_contests"] = Contest.objects.filter(
is_visible=True, is_organization_private=True, organizations=self.object
).order_by("-end_time", "-id")[: settings.DMOJ_BLOG_NEW_CONTEST_COUNT]
context["posts"] = (
BlogPost.objects.filter( BlogPost.objects.filter(
visible=True, visible=True,
publish_on__lte=timezone.now(), publish_on__lte=timezone.now(),
@ -161,6 +167,21 @@ class OrganizationHome(OrganizationDetailView):
.order_by("-sticky", "-publish_on") .order_by("-sticky", "-publish_on")
.prefetch_related("authors__user", "organizations") .prefetch_related("authors__user", "organizations")
) )
paginator = Paginator(posts, 10)
page_number = self.request.GET.get("page", 1)
posts = paginator.get_page(page_number)
return posts
def get_context_data(self, **kwargs):
context = super(OrganizationHome, self).get_context_data(**kwargs)
context["title"] = self.object.name
context["new_problems"] = Problem.objects.filter(
is_public=True, is_organization_private=True, organizations=self.object
).order_by("-date", "-id")[: settings.DMOJ_BLOG_NEW_PROBLEM_COUNT]
context["new_contests"] = Contest.objects.filter(
is_visible=True, is_organization_private=True, organizations=self.object
).order_by("-end_time", "-id")[: settings.DMOJ_BLOG_NEW_CONTEST_COUNT]
context["posts"] = self.get_posts()
context["post_comment_counts"] = { context["post_comment_counts"] = {
int(page[2:]): count int(page[2:]): count
for page, count in Comment.objects.filter( for page, count in Comment.objects.filter(
@ -173,6 +194,26 @@ class OrganizationHome(OrganizationDetailView):
context["pending_count"] = OrganizationRequest.objects.filter( context["pending_count"] = OrganizationRequest.objects.filter(
state="P", organization=self.object state="P", organization=self.object
).count() ).count()
now = timezone.now()
visible_contests = (
Contest.get_visible_contests(self.request.user)
.filter(
is_visible=True, is_organization_private=True, organizations=self.object
)
.order_by("start_time")
)
context["current_contests"] = visible_contests.filter(
start_time__lte=now, end_time__gt=now
)
context["future_contests"] = visible_contests.filter(start_time__gt=now)
context["top_rated"] = self.object.members.filter(is_unlisted=False).order_by(
"-rating"
)[:10]
context["top_scorer"] = self.object.members.filter(is_unlisted=False).order_by(
"-performance_points"
)[:10]
context["page_type"] = "home"
return context return context
@ -186,7 +227,7 @@ class OrganizationUsers(QueryStringSortMixin, OrganizationDetailView):
context = super(OrganizationUsers, self).get_context_data(**kwargs) context = super(OrganizationUsers, self).get_context_data(**kwargs)
context["title"] = _("%s Members") % self.object.name context["title"] = _("%s Members") % self.object.name
context["partial"] = True context["partial"] = True
context["is_admin"] = self.can_edit_organization() context["can_edit"] = self.can_edit_organization()
context["kick_url"] = reverse( context["kick_url"] = reverse(
"organization_user_kick", args=[self.object.id, self.object.slug] "organization_user_kick", args=[self.object.id, self.object.slug]
) )
@ -206,10 +247,76 @@ class OrganizationUsers(QueryStringSortMixin, OrganizationDetailView):
) )
) )
context["first_page_href"] = "." context["first_page_href"] = "."
context["page_type"] = "users"
context.update(self.get_sort_context()) context.update(self.get_sort_context())
return context return context
class OrganizationExternalMixin(OrganizationBase):
organization_id = None
organization = None
def get_organization_from_url(self, request, *args, **kwargs):
try:
self.organization_id = int(kwargs["pk"])
self.organization = Organization.objects.get(id=self.organization_id)
except:
return HttpResponseBadRequest()
if self.organization.slug != kwargs["slug"]:
return HttpResponsePermanentRedirect(
request.get_full_path().replace(kwargs["slug"], self.object.slug)
)
return None
def edit_context_data(self, context):
context["is_member"] = self.is_member(self.organization)
context["can_edit"] = self.can_edit_organization(self.organization)
context["organization"] = self.organization
context["logo_override_image"] = self.organization.logo_override_image
context.pop("organizations")
class OrganizationProblems(ProblemList, OrganizationExternalMixin):
template_name = "organization/problems.html"
def get_queryset(self):
self.org_query = [self.organization_id]
return super().get_normal_queryset()
def get(self, request, *args, **kwargs):
ret = super().get_organization_from_url(request, *args, **kwargs)
if ret:
return ret
self.setup_problem_list(request)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(OrganizationProblems, self).get_context_data(**kwargs)
self.edit_context_data(context)
context["page_type"] = "problems"
return context
class OrganizationContests(ContestList, OrganizationExternalMixin):
template_name = "organization/contests.html"
def get_queryset(self):
self.org_query = [self.organization_id]
return super().get_queryset()
def get(self, request, *args, **kwargs):
ret = super().get_organization_from_url(request, *args, **kwargs)
if ret:
return ret
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(OrganizationContests, self).get_context_data(**kwargs)
self.edit_context_data(context)
context["page_type"] = "contests"
return context
class OrganizationMembershipChange( class OrganizationMembershipChange(
LoginRequiredMixin, OrganizationMixin, SingleObjectMixin, View LoginRequiredMixin, OrganizationMixin, SingleObjectMixin, View
): ):

View file

@ -567,6 +567,13 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
) )
] ]
def get_org_query(self, query):
return [
i
for i in query
if i in self.profile.organizations.values_list("id", flat=True)
]
def get_normal_queryset(self): def get_normal_queryset(self):
filter = Q(is_public=True) filter = Q(is_public=True)
if self.profile is not None: if self.profile is not None:
@ -588,6 +595,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
).values_list("problem__id", flat=True) ).values_list("problem__id", flat=True)
) )
if self.org_query: if self.org_query:
self.org_query = self.get_org_query(self.org_query)
queryset = queryset.filter( queryset = queryset.filter(
Q(organizations__in=self.org_query) Q(organizations__in=self.org_query)
| Q(contests__contest__organizations__in=self.org_query) | Q(contests__contest__organizations__in=self.org_query)
@ -650,7 +658,8 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
context["show_editorial"] = 0 if self.in_contest else int(self.show_editorial) context["show_editorial"] = 0 if self.in_contest else int(self.show_editorial)
context["have_editorial"] = 0 if self.in_contest else int(self.have_editorial) context["have_editorial"] = 0 if self.in_contest else int(self.have_editorial)
context["organizations"] = Organization.objects.all() if self.request.profile:
context["organizations"] = self.request.profile.organizations.all()
all_authors_ids = set(Problem.objects.values_list("authors", flat=True)) all_authors_ids = set(Problem.objects.values_list("authors", flat=True))
context["all_authors"] = Profile.objects.filter(id__in=all_authors_ids) context["all_authors"] = Profile.objects.filter(id__in=all_authors_ids)
context["category"] = self.category context["category"] = self.category
@ -702,7 +711,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
("?" + self.request.GET.urlencode()) if self.request.GET else "" ("?" + self.request.GET.urlencode()) if self.request.GET else ""
) )
context["first_page_href"] = (self.first_page_href or ".") + suffix context["first_page_href"] = (self.first_page_href or ".") + suffix
context["has_show_editorial_option"] = True
return context return context
def get_noui_slider_points(self): def get_noui_slider_points(self):
@ -811,6 +820,7 @@ cf_logger = logging.getLogger("judge.ml.collab_filter")
class ProblemFeed(ProblemList): class ProblemFeed(ProblemList):
model = Problem model = Problem
context_object_name = "problems" context_object_name = "problems"
template_name = "problem/feed.html"
paginate_by = 20 paginate_by = 20
title = _("Problem feed") title = _("Problem feed")
feed_type = None feed_type = None
@ -926,7 +936,8 @@ class ProblemFeed(ProblemList):
context["page_type"] = "feed" context["page_type"] = "feed"
context["title"] = self.title context["title"] = self.title
context["feed_type"] = self.feed_type context["feed_type"] = self.feed_type
context["has_show_editorial_option"] = False
context["has_have_editorial_option"] = False
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):

View file

@ -4199,11 +4199,11 @@ msgstr "Quản lý"
#: templates/organization/home.html:135 #: templates/organization/home.html:135
msgid "Edit organization" msgid "Edit organization"
msgstr "Chỉnh sửa tổ chức" msgstr "Chỉnh sửa"
#: templates/organization/home.html:141 #: templates/organization/home.html:141
msgid "View requests" msgid "View requests"
msgstr "Xem các đơn đăng ký" msgstr "Đơn đăng ký"
#: templates/organization/home.html:154 #: templates/organization/home.html:154
msgid "Admin organization" msgid "Admin organization"

View file

@ -122,72 +122,7 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% if current_contests %} {% include 'contests-countdown.html' %}
<div class="blog-sidebox sidebox"> {% include 'top-users.html' %}
<h3>{{ _('Ongoing contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in current_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Ends in') }} {{ _('%(countdown)s.', countdown=contest.end_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if future_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Upcoming contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in future_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Starting in %(countdown)s.', countdown=contest.start_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Rating') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_rated %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{user.rating}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Score') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_scorer %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{ user.performance_points|floatformat(0) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,9 +1,9 @@
{% extends "common-content.html" %} {% extends "three-column-content.html" %}
{% block meta %} {% block meta %}
<meta name="description" content="The {{ SITE_NAME }}'s contest list - past, present, and future."> <meta name="description" content="The {{ SITE_NAME }}'s contest list - past, present, and future.">
{% endblock %} {% endblock %}
{% block media %} {% block three_col_media %}
<style> <style>
.time-left { .time-left {
text-align: left; text-align: left;
@ -66,10 +66,17 @@
margin-left: 0.5em; margin-left: 0.5em;
} }
} }
@media (min-width: 800px) {
.middle-content {
max-width: none;
padding-left: 1em;
}
}
</style> </style>
{% endblock %} {% endblock %}
{% block js_media %} {% block three_col_js %}
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script> <script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function () { $(document).ready(function () {
@ -116,12 +123,12 @@
</script> </script>
{% endblock %} {% endblock %}
{% block title_ruler %}{% endblock %} {% block left_sidebar %}
<div class="left-sidebar">
{% block title_row %} {{ make_tab_item('list', 'fa fa-list', url('contest_list'), _('List')) }}
{% set tab = 'list' %} {{ make_tab_item('calendar', 'fa fa-calendar', url('contest_calendar', now.year, now.month), _('Calendar')) }}
{% set title = 'Contests' %} {{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_contest_changelist'), _('Admin')) }}
{% include "contest/contest-list-tabs.html" %} </div>
{% endblock %} {% endblock %}
{% macro contest_head(contest) %} {% macro contest_head(contest) %}
@ -212,12 +219,12 @@
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% block body %} {% block middle_content %}
<div class="content-description"> <div class="content-description">
<form id="filter-form"> <form id="filter-form">
<input id="search-contest" type="text" name="contest" value="{{ contest_query or '' }}" <input id="search-contest" type="text" name="contest" value="{{ contest_query or '' }}"
placeholder="{{ _('Search contests...') }}"> placeholder="{{ _('Search contests...') }}">
{% if organizations %}
<select id="search-org" name="orgs" multiple> <select id="search-org" name="orgs" multiple>
{% for org in organizations %} {% for org in organizations %}
<option value="{{ org.id }}"{% if org.id in org_query %} selected{% endif %}> <option value="{{ org.id }}"{% if org.id in org_query %} selected{% endif %}>
@ -225,6 +232,7 @@
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
{% endif %}
<button id="search-btn"> {{ _('Search')}} </button> <button id="search-btn"> {{ _('Search')}} </button>
</form> </form>
{% if active_participations %} {% if active_participations %}

View file

@ -0,0 +1,35 @@
{% if current_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Ongoing contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in current_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Ends in') }} {{ _('%(countdown)s.', countdown=contest.end_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if future_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Upcoming contests') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content">
{% for contest in future_contests %}
<div class="contest">
<div class="contest-list-title">
<a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a>
</div>
<div class="time">
{{ _('Starting in %(countdown)s.', countdown=contest.start_time|as_countdown) }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}

View file

@ -0,0 +1,4 @@
{% extends "contest/list.html" %}
{% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}

View file

@ -1,12 +1,6 @@
{% extends "base.html" %} {% extends "three-column-content.html" %}
{% block three_col_media %}
{% block media %}
<style> <style>
{% if request.user.is_authenticated and is_member %}
#control-panel {
display: none;
}
{% endif %}
.leave-organization, .leave-organization:hover { .leave-organization, .leave-organization:hover {
color: red; color: red;
} }
@ -25,9 +19,12 @@
</style> </style>
{% endblock %} {% endblock %}
{% block js_media %} {% block three_col_js %}
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {
$('.time-remaining').each(function () {
count_down($(this));
});
$('.leave-organization').click(function () { $('.leave-organization').click(function () {
if (confirm('{{ _('Are you sure you want to leave this organization?') }}\n' + if (confirm('{{ _('Are you sure you want to leave this organization?') }}\n' +
{% if organization.is_open %} {% if organization.is_open %}
@ -41,32 +38,22 @@
}); });
$(document).ready(function () { $(document).ready(function () {
$('.blog-sidebar').hide();
$('#info-tab').find('a').click(function (e) {
e.preventDefault();
$('#info-tab').addClass('active');
$('#detail-tab').removeClass('active');
$('.blog-content').show();
$('.blog-sidebar').hide();
});
$('#detail-tab').find('a').click(function (e) {
e.preventDefault();
$('#detail-tab').addClass('active');
$('#info-tab').removeClass('active');
$('.blog-content').hide();
$('.blog-sidebar').show();
});
$('.control-button').click(function(e) { $('.control-button').click(function(e) {
e.preventDefault(); e.preventDefault();
$('#control-panel').toggle("fast"); $('#control-panel').toggle("fast");
}) })
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}
{% block title_row %} {% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block middle_content %}
{% block before_posts %}{% endblock %}
<div class="page-title"> <div class="page-title">
<div class="tabs"> <div class="tabs">
<h2>{{title}}</h2> <h2>{{title}}</h2>
@ -85,51 +72,51 @@
class="unselectable button">{{ _('Request membership') }}</a> class="unselectable button">{{ _('Request membership') }}</a>
{% endif %} {% endif %}
{% endif %} {% endif %}
<button class="control-button"><i class="fa fa-ellipsis-h"></i></button>
</div> </div>
</div> </div>
{% endblock %} {% if is_member or can_edit %}
{% block title_ruler %} {% endblock %} {% for post in posts %}
{% block body %} {% include "blog/content.html" %}
{% block before_posts %}{% endblock %} {% if posts.paginator.num_pages > 1 %}
<div id="mobile" class="tabs"> <div style="margin-bottom:10px;margin-top:10px">{% include "list-pages.html" %}</div>
<ul> {% endif %}
<li id="info-tab" class="tab active"><a href="#"> {% endfor %}
<i class="tab-icon fa fa-info-circle"></i> {{ _('Info') }} {% else %}
</a></li> <div class="blog-sidebox sidebox">
<li id="detail-tab" class="tab"><a href="#"><i class="tab-icon fa fa-rss"></i> {{ _('Details') }}</a></li>
</ul>
</div>
<div id="blog-container">
<div class="blog-content sidebox">
<h3>{{ _('About') }}<i class="fa fa-info-circle"></i></h3> <h3>{{ _('About') }}<i class="fa fa-info-circle"></i></h3>
<div class="sidebox-content"> <div class="sidebox-content">
<div style="margin: 1.4em;"> <div style="margin: 0.3em;">
{% cache 3600 'organization_html' organization.id MATH_ENGINE %} {% cache 3600 'organization_html' organization.id MATH_ENGINE %}
{{ organization.about|markdown('organization-about', MATH_ENGINE)|reference|str|safe }} {{ organization.about|markdown('organization-about', MATH_ENGINE)|reference|str|safe }}
{% endcache %} {% endcache %}
</div> </div>
</div> </div>
{% if is_member or can_edit %}
<br>
<h3>{{ _('Organization news') }} <i class="fa fa-terminal"></i></h3>
<div class="sidebox-content">
{% for post in posts %}
{% include "blog/content.html" %}
{% else %}
<div style="margin: 1.4em;">
<i>{{ _('There is no news at this time.') }}</i>
</div>
{% endfor %}
</div> </div>
{% endif %} {% endif %}
</div> {% block after_posts %}{% endblock %}
{% endblock %}
<div class="blog-sidebar"> {% block right_sidebar %}
<div class="right-sidebar">
{% if (is_member or can_edit) %}
{% include 'contests-countdown.html' %}
{% endif %}
{% if is_member or can_edit %}
<div class="blog-sidebox sidebox">
<h3>{{ _('About') }}<i class="fa fa-info-circle"></i></h3>
<div class="sidebox-content">
<div style="margin: 0.3em;">
{% cache 3600 'organization_html' organization.id MATH_ENGINE %}
{{ organization.about|markdown('organization-about', MATH_ENGINE)|reference|str|safe }}
{% endcache %}
</div>
</div>
</div>
{% endif %}
{% if can_edit %}
<div id="control-panel" class="blog-sidebox sidebox"> <div id="control-panel" class="blog-sidebox sidebox">
<h3>{{ _('Controls') }} <i class="fa fa-cog"></i></h3> <h3>{{ _('Controls') }} <i class="fa fa-cog"></i></h3>
<ul id="control-list" class="sidebox-content" style="padding: 1em;"> <ul id="control-list" class="sidebox-content" style="padding: 1em;">
{% if can_edit %}
<li> <li>
<div> <div>
<a href="{{ url('edit_organization', organization.id, organization.slug) }}">{{ _('Edit organization') }}</a> <a href="{{ url('edit_organization', organization.id, organization.slug) }}">{{ _('Edit organization') }}</a>
@ -147,19 +134,6 @@
</div> </div>
</li> </li>
{% endif %} {% endif %}
{% endif %}
{% if perms.judge.change_organization %}
<li>
<div>
<a href="{{ url('admin:judge_organization_change', organization.id) }}">{{ _('Admin organization') }}</a>
</div>
</li>
{% endif %}
<li>
<div>
<a href="{{ organization.get_users_url() }}">{{ _('View members') }}</a>
</div>
</li>
{% if is_member and not can_edit %} {% if is_member and not can_edit %}
<li> <li>
<form method="post" action="{{ url('leave_organization', organization.id, organization.slug) }}"> <form method="post" action="{{ url('leave_organization', organization.id, organization.slug) }}">
@ -170,40 +144,7 @@
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
{% if (is_member or can_edit) %}
{% if new_contests %}
<div class="blog-sidebox sidebox">
<h3>{{ _('New private contests') }} <i class="fa fa-trophy"></i>
</h3>
<div class="sidebox-content">
<ul class="problem-list">
{% for contest in new_contests %}
<li><a href="{{ url('contest_view', contest.key) }}">{{ contest.name }}</a></li>
{% endfor %}
</ul>
<hr>
<center><a target="_blank" href="{{url('contest_list')+'?orgs='+str(organization.id)}}">{{_('View all')}} <i class="fa fa-chevron-right"></i></a></center>
</div>
</div>
{% endif %} {% endif %}
{% if new_problems %} {% include 'top-users.html' %}
<div class="blog-sidebox sidebox">
<h3>{{ _('New private problems') }} <i class="fa fa-puzzle-piece"></i>
</h3>
<div class="sidebox-content">
<ul class="problem-list">
{% for problem in new_problems %}
<li><a href="{{ url('problem_detail', problem.code) }}">{{ problem.name }}</a></li>
{% endfor %}
</ul>
<hr>
<center><a target="_blank" href="{{url('problem_list')+'?orgs='+str(organization.id)}}">{{_('View all')}} <i class="fa fa-chevron-right"></i></a></center>
</div> </div>
</div>
{% endif %}
{% endif %}
</div>
</div>
{% block after_posts %}{% endblock %}
{% endblock %} {% endblock %}

View file

@ -0,0 +1,11 @@
<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')) }}
{% endif %}
{{ make_tab_item('users', 'fa fa-user', organization.get_users_url(), _('Members')) }}
{% if perms.judge.change_organization %}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_organization_change', organization.id), _('Admin')) }}
{% endif %}
</div>

View file

@ -0,0 +1,4 @@
{% extends "problem/list.html" %}
{% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}

View file

@ -1,4 +1,4 @@
{% extends "user/base-users.html" %} {% extends "user/base-users-three-col.html" %}
{% block users_media %} {% block users_media %}
<style> <style>
.kick-form .button { .kick-form .button {
@ -36,4 +36,8 @@
</script> </script>
{% endblock %} {% endblock %}
{% block left_sidebar %}
{% include "organization/org-left-sidebar.html" %}
{% endblock %}
{% block users_table %}{% include "organization/users-table.html" %}{% endblock %} {% block users_table %}{% include "organization/users-table.html" %}{% endblock %}

View file

@ -1,4 +1,24 @@
<div class="blog-box"> {% extends "problem/list-base.html" %}
{% block left_sidebar %}
{% include "problem/left-sidebar.html" %}
{% endblock %}
{% block middle_content %}
<div class="problem-feed-option">
<a href="{{url('problem_feed')}}" class="problem-feed-option-item {{'active' if feed_type=='for_you'}}">
{{_('FOR YOU')}}
</a>
<a href="{{url('problem_feed_new')}}" class="problem-feed-option-item {{'active' if feed_type=='new'}}">
{{_('NEW')}}
</a>
{% if request.user.has_perm('judge.suggest_problem_changes') %}
<a href="{{url('problem_feed_volunteer')}}" class="problem-feed-option-item {{'active' if feed_type=='volunteer'}}">
{{_('VOLUNTEER')}}
</a>
{% endif %}
</div>
{% for problem in problems %}
<div class="blog-box">
<h3 class="problem-feed-name"> <h3 class="problem-feed-name">
<a href="{{ url('problem_detail', problem.code) }}"> <a href="{{ url('problem_detail', problem.code) }}">
{{ problem.name }} {{ problem.name }}
@ -93,5 +113,9 @@
<center id="thank-{{problem.id}}" style="display: none; margin-top: 3em"></center> <center id="thank-{{problem.id}}" style="display: none; margin-top: 3em"></center>
{% endif %} {% endif %}
</div> </div>
</div>
</div> {% endfor %}
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,7 @@
{% if not request.in_contest_mode %}
<div class="left-sidebar">
{{ make_tab_item('feed', 'fa fa-pagelines', url('problem_feed'), _('Feed')) }}
{{ make_tab_item('list', 'fa fa-list', url('problem_list'), _('List')) }}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
</div>
{% endif %}

View file

@ -0,0 +1,450 @@
{% extends "three-column-content.html" %}
{% block three_col_media %}
<link rel="stylesheet" href="{{ static('libs/nouislider.min.css') }}">
<noscript>
<style>
#category, #types {
visibility: visible;
}
</style>
</noscript>
{% if not request.in_contest_mode %}
<style>
#search-org, #search-author {
width: 100%;
}
#problem-table th {
padding: 0;
}
a.hot-problem-link:hover > .hot-problem-count {
visibility: visible;
}
span.hot-problem-count {
color: #555;
font-size: 0.75em;
vertical-align: super;
visibility: hidden;
padding-left: 0.25em;
position: relative;
}
ul.problem-list {
padding: 0 !important;
}
#content {
width: 99%;
margin-left: 0;
}
.volunteer-types {
width: 100%;
}
.point-input {
height: 2em;
padding-top: 4px;
}
</style>
{% endif %}
{% endblock %}
{% block three_col_js %}
<script>
window.point_start = {{point_start}};
window.point_end = {{point_end}};
window.point_values = {{point_values|json|safe}};
</script>
{% compress js %}
<script src="{{ static('libs/nouislider.min.js') }}" type="text/javascript"></script>
<script>
$(function () {
{% if not request.in_contest_mode %}
// wrap middle and write column
if (window.matchMedia('(max-width: 799px)').matches) {
$('.middle-content').next().addBack().wrapAll('<div class="problem-middle-right"/>');
}
{% endif %}
var $form = $('form#filter-form');
var $search = $('#search');
var $category = $('#category');
function prep_form() {
$search.prop('disabled', !$search.val());
$category.prop('disabled', !$category.val());
}
function clear_point_interval() {
if ($('#search').val() !== "{{ search_query or '' }}") {
$('#point-start').remove();
$('#point-end').remove();
}
}
function clean_submit() {
prep_form();
clear_point_interval();
$form.submit();
}
function form_serialize() {
clear_point_interval();
return $form.serialize();
}
$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: '{{ _('Organizations...') }}'})
.css({'visibility': 'visible'});
$('#search-author').select2({multiple: 1, placeholder: '{{ _('Authors') }}...'})
.css({'visibility': 'visible'});
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
$search.keypress(function (e) {
if (e.keyCode == 13)
$('#go').click();
});
$('#random').click(function (e) {
var action = $form.attr('action');
$form.attr('action', '{{ url('problem_random') }}').attr('target', '_blank').submit();
$form.attr('action', action).attr('target', '');
e.preventDefault();
});
$('#go').click(clean_submit);
$('input#full_text, input#hide_solved, input#show_types, input#show_editorial, input#have_editorial').click(function () {
prep_form();
($('<form>').attr('action', window.location.pathname + '?' + form_serialize())
.append($('<input>').attr('type', 'hidden').attr('name', 'csrfmiddlewaretoken')
.attr('value', $.cookie('csrftoken')))
.attr('method', 'POST').appendTo($('body')).submit());
});
var intFormatter = {
to: function (value) {
return value;
},
from: function (value) {
return +value;
}
};
var $slider = $('#point-slider');
if ($slider.length) {
var $start = $('#point-start');
var $end = $('#point-end');
noUiSlider.create($slider[0], {
start: [point_start, point_end],
connect: true,
snap: true,
tooltips: [intFormatter, intFormatter],
range: point_values
}).on('change', function (values) {
var start = +values[0], end = +values[1];
$start.prop('disabled', start === point_values.min).val(start);
$end.prop('disabled', end === point_values.max).val(end);
});
}
{% if feed_type=='volunteer' and request.user.has_perm('judge.suggest_problem_changes') %}
$(".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'});
$('#form-' + pid).show();
$('#submit-' + pid).show();
$(this).hide();
});
let isChecking = false;
$(".volunteer-submit-btn").on('click', function(e) {
var pid = $(this).attr('pid');
var pcode = $(this).attr('pcode');
var $form = $('#form-' + pid);
if (!$form[0].checkValidity()) {
if (isChecking) return;
isChecking = true;
// The form won't actually submit;
$(this).click();
}
else {
isChecking = false;
}
if (isChecking) return;
e.preventDefault();
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'})
.css({'visibility': 'visible'});
$('#form-' + pid).hide();
$('#edit-' + pid).show();
$('#thank-' + pid).show();
$(this).hide();
var data = {
problem: pcode,
types: $('#volunteer-types-' + pid).val(),
knowledge_points: $('#knowledge_point-' + pid).val(),
thinking_points: $('#thinking_point-' + pid).val(),
feedback: $('#feedback-' + pid).val(),
};
$.post("{{url('volunteer_problem_vote')}}", data)
.fail(function() {
$('#thank-' + pid).html("{{_('Fail to vote!')}}");
})
.done(function() {
$('#thank-' + pid).html("{{_('Successful vote! Thank you!')}}");
});
});
{% endif %}
});
</script>
{% endcompress %}
{% if request.in_contest_mode %}
{% compress js %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$.tablesorter.addParser({
id: 'solvedsort',
is: function (s) {
return false;
},
format: function (s, table, cell, cellIndex) {
return $(cell).attr('solved');
},
type: 'numeric'
});
$('#problem-table').tablesorter({
headers: {
0: {
sorter: 'solvedsort'
}
},
textExtraction: function (node) {
node = $(node);
var text = node.text().replace(/^\s+|\s+$/g, '');
return (node.hasClass('p') ? text.replace(/p$/, '') : text);
}
});
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
{% if request.in_contest_mode %}
$('.left-sidebar').hide();
$('.middle-content').css('max-width', '80%');
{% endif %}
});
</script>
{% endcompress %}
{% endif %}
{% endblock %}
{% block left_sidebar %}
{% if not request.in_contest_mode %}
<div class="left-sidebar">
{{ make_tab_item('feed', 'fa fa-pagelines', url('problem_feed'), _('Feed')) }}
{{ make_tab_item('list', 'fa fa-list', url('problem_list'), _('List')) }}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
</div>
{% endif %}
{% endblock %}
{% block middle_content %}
{% if in_contest_mode or page_type == 'list' %}
<div id="content-left" class="problems">
<table id="problem-table" class="table striped">
<thead>
<tr>
{% if request.in_contest_mode %}
{% if request.user.is_authenticated %}
<th class="solved"><i class="fa fa-check"></i></th>
{% endif %}
<th class="problem">{{ _('Problem') }}</th>
<th class="pcode">{{ _('Problem code') }}</th>
{% if show_types %}
<th>{{ _('Types') }}</th>
{% endif %}
<th class="points">{{ _('Points') }}</th>
<th class="users">{{ _('Users') }}</th>
{% else %}
{% if request.user.is_authenticated %}
<th class="solved">
<a href="{{ sort_links.solved }}"><i class="fa fa-check"></i>{{ sort_order.solved }}
</a>
</th>
{% endif %}
<th class="problem">
<a href="{{ sort_links.name }}">{{ _('Problem') }}{{ sort_order.name }}</a>
</th>
<th class="pcode">
<a href="{{ sort_links.code }}">{{ _('Problem code') }}</a>
</th>
<th class="category">
<a href="{{ sort_links.group }}">{{ _('Category') }}{{ sort_order.group }}</a>
</th>
{% if show_types %}
<th>
<a href="{{ sort_links.type }}">{{ _('Types') }}{{ sort_order.type }}</a>
</th>
{% endif %}
<th class="points">
<a href="{{ sort_links.points }}">{{ _('Points') }}{{ sort_order.points }}</a>
</th>
<th class="ac-rate">
<a href="{{ sort_links.ac_rate }}">{{ _('AC %%') }}{{ sort_order.ac_rate }}</a>
</th>
<th class="users">
<a href="{{ sort_links.user_count }}">{{ _('Users') }}{{ sort_order.user_count }}</a>
</th>
{% if show_editorial %}
<th class="editorial">
{{_('Editorial')}}
</th>
{% endif %}
{% endif %}
</tr>
</thead>
<tbody>
{% for problem in object_list %}
<tr>
{% if request.user.is_authenticated %}
{% if problem.id in completed_problem_ids %}
<td solved="1">
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest_mode %}
<i class="solved-problem-color fa fa-check-circle"></i>
{% else %}
<i class="solved-problem-color fa fa-lock"></i>
{% endif %}
</a>
</td>
{% elif problem.id in attempted_problems %}
<td solved="0">
<a href="{{ url('user_submissions', problem.code, request.user.username) }}">
{% if problem.is_public or request.in_contest_mode %}
<i class="attempted-problem-color fa fa-minus-circle"></i>
{% else %}
<i class="attempted-problem-color fa fa-lock"></i>
{% endif %}
</a>
</td>
{% else %}
<td solved="-1">
{% if problem.is_public or request.in_contest_mode %}
<i class="unsolved-problem-color fa fa-minus-circle"></i>
{% else %}
<i class="unsolved-problem-color fa fa-lock"></i>
{% endif %}
</td>
{% endif %}
{% endif %}
<td class="problem">
<a href="{{ url('problem_detail', problem.code) }}">{{ problem.i18n_name }}</a>
</td>
<td class="pcode">
<a class="pcodecell" href="{{ url('problem_detail', problem.code) }}">{{ problem.code }}</a>
</td>
{% if not request.in_contest_mode %}
<td class="category">{{ problem.group.full_name }}</td>
{% endif %}
{% if show_types %}
<td class="types">
{% for type in problem.types_list %}
<span class="type-tag">{{ type }}</span>{% if not loop.last %}, {% endif %}
{% endfor %}
</td>
{% endif %}
<td class="p">{{ problem.points|floatformat }}{% if problem.partial %}p{% endif %}</td>
{% if not request.in_contest_mode %}
<td class="ac-rate">{{ problem.ac_rate|floatformat(1) }}%</td>
{% endif %}
<td class="users">
<a href="{{ url('ranked_submissions', problem.code) }}">
{% if not request.in_contest_mode or not hide_contest_scoreboard %}
{{ problem.user_count }}
{% else %}
???
{% endif %}
</a>
</td>
{% if show_editorial%}
<td class="editorial">
{% if problem.has_public_editorial %}
<a href="{{ url('problem_editorial', problem.code) }}">{{ _('Editorial') }}</a>
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% if request.in_contest_mode and request.participation.contest.use_clarifications %}
<br><br>
{% if can_edit_contest %}
<div style="float: right; font-size: 1.2em">
<a href="{{url('new_contest_clarification', request.participation.contest.key)}}"><i class="fa fa-plus-circle" style="color:green"></i> <u>{{_('Add clarifications')}}</u></a>
</div>
{% endif %}
{% if has_clarifications %}
<div style="font-size: 1.2em; font-style: bold">
<i class="fa fa-question-circle"></i> {{_('Clarifications')}}</div>
<table class="table">
<tr>
<th>{{_('Problem')}}</th>
<th>{{_('Time')}}</th>
<th>{{_('Description')}}</th>
</tr>
{% for clarification in clarifications %}
<tr>
<td>
<a href="{{ url('problem_detail', clarification.problem.code) }}"
class="problem">
{{ clarification.problem.name }}
</a>
</td>
<td class="time">{{ relative_time(clarification.date) }}</td>
<td><p style="overflow-wrap: break-word; word-break: break-word">{{clarification.description}}</p></td>
</tr>
{% endfor %}
</table>
{% else %}
<p style="font-style: italic; text-align: center">
{{ _('No clarifications have been made at this time.') }}</center>
</p>
{% endif %}
{% endif %}
</div>
{% elif page_type == 'feed' %}
<div class="problem-feed-option">
<a href="{{url('problem_feed')}}" class="problem-feed-option-item {{'active' if feed_type=='for_you'}}">
{{_('FOR YOU')}}
</a>
<a href="{{url('problem_feed_new')}}" class="problem-feed-option-item {{'active' if feed_type=='new'}}">
{{_('NEW')}}
</a>
{% if request.user.has_perm('judge.suggest_problem_changes') %}
<a href="{{url('problem_feed_volunteer')}}" class="problem-feed-option-item {{'active' if feed_type=='volunteer'}}">
{{_('VOLUNTEER')}}
</a>
{% endif %}
</div>
{% for problem in problems %}
{% include "problem/feed.html" %}
{% endfor %}
{% endif %}
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
{% endblock %}
{% block right_sidebar %}
{% if not request.in_contest_mode %}
<div id="content-right" class="problems right-sidebar">
{% include "problem/search-form.html" %}
{% include "problem/recent-attempt.html" %}
</div>
{% endif %}
{% endblock %}

View file

@ -1,258 +1,9 @@
{% extends "three-column-content.html" %} {% extends "problem/list-base.html" %}
{% block three_col_media %}
<link rel="stylesheet" href="{{ static('libs/nouislider.min.css') }}">
<noscript>
<style>
#category, #types {
visibility: visible;
}
</style>
</noscript>
{% if not request.in_contest_mode %}
<style>
#search-org, #search-author {
width: 100%;
}
#problem-table th {
padding: 0;
}
a.hot-problem-link:hover > .hot-problem-count {
visibility: visible;
}
span.hot-problem-count {
color: #555;
font-size: 0.75em;
vertical-align: super;
visibility: hidden;
padding-left: 0.25em;
position: relative;
}
ul.problem-list {
padding: 0 !important;
}
#content {
width: 99%;
margin-left: 0;
}
.volunteer-types {
width: 100%;
}
.point-input {
height: 2em;
padding-top: 4px;
}
</style>
{% endif %}
{% endblock %}
{% block three_col_js %}
<script>
window.point_start = {{point_start}};
window.point_end = {{point_end}};
window.point_values = {{point_values|json|safe}};
</script>
{% compress js %}
<script src="{{ static('libs/nouislider.min.js') }}" type="text/javascript"></script>
<script>
$(function () {
{% if not request.in_contest_mode %}
// wrap middle and write column
if (window.matchMedia('(max-width: 799px)').matches) {
$('.middle-content').next().addBack().wrapAll('<div class="problem-middle-right"/>');
}
{% endif %}
var $form = $('form#filter-form');
var $search = $('#search');
var $category = $('#category');
function prep_form() {
$search.prop('disabled', !$search.val());
$category.prop('disabled', !$category.val());
}
function clear_point_interval() {
if ($('#search').val() !== "{{ search_query or '' }}") {
$('#point-start').remove();
$('#point-end').remove();
}
}
function clean_submit() {
prep_form();
clear_point_interval();
$form.submit();
}
function form_serialize() {
clear_point_interval();
return $form.serialize();
}
$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: '{{ _('Organizations...') }}'})
.css({'visibility': 'visible'});
$('#search-author').select2({multiple: 1, placeholder: '{{ _('Authors') }}...'})
.css({'visibility': 'visible'});
// This is incredibly nasty to do but it's needed because otherwise the select2 steals the focus
$search.keypress(function (e) {
if (e.keyCode == 13)
$('#go').click();
});
$('#random').click(function (e) {
var action = $form.attr('action');
$form.attr('action', '{{ url('problem_random') }}').attr('target', '_blank').submit();
$form.attr('action', action).attr('target', '');
e.preventDefault();
});
$('#go').click(clean_submit);
$('input#full_text, input#hide_solved, input#show_types, input#show_editorial, input#have_editorial').click(function () {
prep_form();
($('<form>').attr('action', window.location.pathname + '?' + form_serialize())
.append($('<input>').attr('type', 'hidden').attr('name', 'csrfmiddlewaretoken')
.attr('value', $.cookie('csrftoken')))
.attr('method', 'POST').appendTo($('body')).submit());
});
var intFormatter = {
to: function (value) {
return value;
},
from: function (value) {
return +value;
}
};
var $slider = $('#point-slider');
if ($slider.length) {
var $start = $('#point-start');
var $end = $('#point-end');
noUiSlider.create($slider[0], {
start: [point_start, point_end],
connect: true,
snap: true,
tooltips: [intFormatter, intFormatter],
range: point_values
}).on('change', function (values) {
var start = +values[0], end = +values[1];
$start.prop('disabled', start === point_values.min).val(start);
$end.prop('disabled', end === point_values.max).val(end);
});
}
{% if feed_type=='volunteer' and request.user.has_perm('judge.suggest_problem_changes') %}
$(".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'});
$('#form-' + pid).show();
$('#submit-' + pid).show();
$(this).hide();
});
let isChecking = false;
$(".volunteer-submit-btn").on('click', function(e) {
var pid = $(this).attr('pid');
var pcode = $(this).attr('pcode');
var $form = $('#form-' + pid);
if (!$form[0].checkValidity()) {
if (isChecking) return;
isChecking = true;
// The form won't actually submit;
$(this).click();
}
else {
isChecking = false;
}
if (isChecking) return;
e.preventDefault();
$('#volunteer-types-' + pid).select2({multiple: 1, placeholder: '{{ _('Add types...') }}'})
.css({'visibility': 'visible'});
$('#form-' + pid).hide();
$('#edit-' + pid).show();
$('#thank-' + pid).show();
$(this).hide();
var data = {
problem: pcode,
types: $('#volunteer-types-' + pid).val(),
knowledge_points: $('#knowledge_point-' + pid).val(),
thinking_points: $('#thinking_point-' + pid).val(),
feedback: $('#feedback-' + pid).val(),
};
$.post("{{url('volunteer_problem_vote')}}", data)
.fail(function() {
$('#thank-' + pid).html("{{_('Fail to vote!')}}");
})
.done(function() {
$('#thank-' + pid).html("{{_('Successful vote! Thank you!')}}");
});
});
{% endif %}
});
</script>
{% endcompress %}
{% if request.in_contest_mode %}
{% compress js %}
<script src="{{ static('libs/tablesorter.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$.tablesorter.addParser({
id: 'solvedsort',
is: function (s) {
return false;
},
format: function (s, table, cell, cellIndex) {
return $(cell).attr('solved');
},
type: 'numeric'
});
$('#problem-table').tablesorter({
headers: {
0: {
sorter: 'solvedsort'
}
},
textExtraction: function (node) {
node = $(node);
var text = node.text().replace(/^\s+|\s+$/g, '');
return (node.hasClass('p') ? text.replace(/p$/, '') : text);
}
});
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
{% if request.in_contest_mode %}
$('.left-sidebar').hide();
$('.middle-content').css('max-width', '80%');
{% endif %}
});
</script>
{% endcompress %}
{% endif %}
{% endblock %}
{% block left_sidebar %} {% block left_sidebar %}
{% if not request.in_contest_mode %} {% include "problem/left-sidebar.html" %}
<div class="left-sidebar">
{{ make_tab_item('feed', 'fa fa-pagelines', url('problem_feed'), _('Feed')) }}
{{ make_tab_item('list', 'fa fa-list', url('problem_list'), _('List')) }}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
</div>
{% endif %}
{% endblock %} {% endblock %}
{% block middle_content %} {% block middle_content %}
{% if in_contest_mode or page_type == 'list' %}
<div id="content-left" class="problems"> <div id="content-left" class="problems">
<table id="problem-table" class="table striped"> <table id="problem-table" class="table striped">
<thead> <thead>
@ -415,36 +166,8 @@
</p> </p>
{% endif %} {% endif %}
{% endif %} {% endif %}
</div> </div>
{% elif page_type == 'feed' %}
<div class="problem-feed-option">
<a href="{{url('problem_feed')}}" class="problem-feed-option-item {{'active' if feed_type=='for_you'}}">
{{_('FOR YOU')}}
</a>
<a href="{{url('problem_feed_new')}}" class="problem-feed-option-item {{'active' if feed_type=='new'}}">
{{_('NEW')}}
</a>
{% if request.user.has_perm('judge.suggest_problem_changes') %}
<a href="{{url('problem_feed_volunteer')}}" class="problem-feed-option-item {{'active' if feed_type=='volunteer'}}">
{{_('VOLUNTEER')}}
</a>
{% endif %}
</div>
{% for problem in problems %}
{% include "problem/feed.html" %}
{% endfor %}
{% endif %}
{% if page_obj.num_pages > 1 %} {% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div> <div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block right_sidebar %}
{% if not request.in_contest_mode %}
<div id="content-right" class="problems right-sidebar">
{% include "problem/search-form.html" %}
{% include "problem/recent-attempt.html" %}
</div>
{% endif %}
{% endblock %}

View file

@ -19,19 +19,21 @@
{% if show_types %} checked{% endif %}> {% if show_types %} checked{% endif %}>
<label for="show_types">{{ _('Show problem types') }}</label> <label for="show_types">{{ _('Show problem types') }}</label>
</div> </div>
{% if page_type == 'list' %} {% if has_show_editorial_option %}
<div> <div>
<input id="show_editorial" type="checkbox" name="show_editorial" value="1" <input id="show_editorial" type="checkbox" name="show_editorial" value="1"
{% if show_editorial %} checked{% endif %}> {% if show_editorial %} checked{% endif %}>
<label for="show_editorial">{{ _('Show editorial') }}</label> <label for="show_editorial">{{ _('Show editorial') }}</label>
</div> </div>
{% elif page_type == 'feed' %} {% endif %}
{% if has_have_editorial_option %}
<div> <div>
<input id="have_editorial" type="checkbox" name="have_editorial" value="1" <input id="have_editorial" type="checkbox" name="have_editorial" value="1"
{% if have_editorial %} checked{% endif %}> {% if have_editorial %} checked{% endif %}>
<label for="have_editorial">{{ _('Have editorial') }}</label> <label for="have_editorial">{{ _('Have editorial') }}</label>
</div> </div>
{% endif %} {% endif %}
{% if organizations %}
<div class="filter-form-group"> <div class="filter-form-group">
<label for="type"><i>{{ _('Organization') }}</i></label> <label for="type"><i>{{ _('Organization') }}</i></label>
<select id="search-org" name="orgs" multiple> <select id="search-org" name="orgs" multiple>
@ -42,6 +44,7 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
{% endif %}
<div class="filter-form-group"> <div class="filter-form-group">
<label for="type"><i>{{ _('Author') }}</i></label> <label for="type"><i>{{ _('Author') }}</i></label>
<select id="search-author" name="authors" multiple> <select id="search-author" name="authors" multiple>
@ -66,7 +69,6 @@
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
{% if show_types %} {% if show_types %}
<div class="filter-form-group"> <div class="filter-form-group">

37
templates/top-users.html Normal file
View file

@ -0,0 +1,37 @@
{% if top_rated %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Rating') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_rated %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{user.rating}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% if top_scorer %}
<div class="blog-sidebox sidebox">
<h3>{{ _('Top Score') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content" style="padding: 0; border: 0">
<table class="table feed-table">
<tbody>
{% for user in top_scorer %}
<tr>
<td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
<td>{{link_user(user)}}</td>
<td>{{ user.performance_points|floatformat(0) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}

View file

@ -0,0 +1,102 @@
{% extends "three-column-content.html" %}
{% block three_col_js %}
{% block users_js_media %}{% endblock %}
<script>
$(function () {
$('#search-handle').replaceWith($('<select>').attr({
id: 'search-handle',
name: 'handle',
onchange: 'form.submit()'
}));
var in_user_redirect = false;
$('#search-handle').select2({
placeholder: '{{ _('Search by handle...') }}',
ajax: {
url: '{{ url('user_search_select2_ajax') }}'
},
minimumInputLength: 1,
escapeMarkup: function (markup) {
return markup;
},
templateResult: function (data, container) {
return $('<span>')
.append($('<img>', {
'class': 'user-search-image', src: data.gravatar_url,
width: 24, height: 24
}))
.append($('<span>', {'class': data.display_rank + ' user-search-name'}).text(data.text))
.append($('<a>', {href: '/user/' + data.text, 'class': 'user-redirect'})
.append($('<i>', {'class': 'fa fa-mail-forward'}))
.mouseover(function () {
in_user_redirect = true;
}).mouseout(function () {
in_user_redirect = false;
}));
}
}).on('select2:selecting', function () {
return !in_user_redirect;
});
var $last = null;
$(window).on('hashchange', function () {
var hash = window.location.hash;
if (hash.startsWith('#!')) {
var $user = $('#user-' + hash.substring(2)).addClass('highlight');
if ($user) {
$(document).scrollTop($user.position().top - 50);
if ($last !== null) $last.removeClass('highlight');
$last = $user;
}
}
}).trigger('hashchange');
$('.about-td').on('click', function() {
var max_height = $(this).css('max-height');
if (max_height !== 'fit-content') {
$(this).css('max-height', 'fit-content');
}
else {
$(this).css('max-height', '45px');
}
})
});
</script>
{% endblock %}
{% block three_col_media %}
<link href="http://fonts.cdnfonts.com/css/jersey-m54" rel="stylesheet">
<style>
@media (min-width: 800px) {
.middle-content {
max-width: none;
padding-left: 1em;
}
}
</style>
{% block users_media %}{% endblock %}
{% endblock %}
{% block middle_content %}
<div id="common-content">
<div id="content-left" class="users">
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-bottom: 7px; margin-top: 3px;">
{% include "list-pages.html" %}
<form id="search-form" name="form" action="{{ url('user_ranking_redirect') }}" method="get">
<input id="search-handle" type="text" name="search"
placeholder="{{ _('Search by handle...') }}">
</form>
</div>
{% endif %}
<table id="users-table" class="table">
{% block users_table %}{% endblock %}
</table>
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
</div>
</div>
{% endblock %}