#52: Added countdown on projector view with control unit (agenda overview) and time variable (general settings).
This commit is contained in:
parent
52c24d6a48
commit
076699ff45
@ -12,7 +12,6 @@
|
|||||||
<script type="text/javascript" src="/static/javascript/tabledrag.js"></script>
|
<script type="text/javascript" src="/static/javascript/tabledrag.js"></script>
|
||||||
<script type="text/javascript" src="/static/javascript/knockout-1.2.1.js"></script>
|
<script type="text/javascript" src="/static/javascript/knockout-1.2.1.js"></script>
|
||||||
<script type="text/javascript" src="/static/javascript/agenda.js"></script>
|
<script type="text/javascript" src="/static/javascript/agenda.js"></script>
|
||||||
<script type="text/html" src="/static/javascript/agenda.slideTemplate.js"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
<!--//--><![CDATA[//><!--
|
<!--//--><![CDATA[//><!--
|
||||||
@ -48,13 +47,27 @@
|
|||||||
<input type="button" onclick="window.location.href='{% url item_overview %}';" value="{%trans 'No' %}">
|
<input type="button" onclick="window.location.href='{% url item_overview %}';" value="{%trans 'No' %}">
|
||||||
</em>
|
</em>
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align:right; padding-bottom:3px;">
|
|
||||||
|
<div style="text-align: right; padding: 0 5px 5px 0; margin-top:-20px;">
|
||||||
|
<!-- countdown -->
|
||||||
|
<input type="checkbox" name="countdown" onchange="document.location='{% if countdown_visible == "True" %}{% url countdown_close %}{% else %}{% url countdown_open %}{% endif %}'"
|
||||||
|
{% if countdown_visible == "True" %}checked{% endif %}>
|
||||||
|
{% trans "Countdown" %} ({{countdown_time}} {% trans "sec" %}){% if countdown_visible == "True" %}:
|
||||||
|
<a class="beamer_countdown" href="{% url countdown_reset countdown_time %}" title="{% trans 'Reset countdown' %}"><img src="/static/images/icons/media-skip-backward.png"></a>
|
||||||
|
<a class="beamer_countdown" href="{% url countdown_start %}" title="{% trans 'Start countdown' %}"><img src="/static/images/icons/media-playback-start.png"></a>
|
||||||
|
<a class="beamer_countdown" href="{% url countdown_stop %}" title="{% trans 'Stop countdown' %}"><img src="/static/images/icons/media-playback-pause.png"></a>
|
||||||
|
{% endif %}
|
||||||
|
<p></p>
|
||||||
|
<!-- beamer control -->
|
||||||
{% trans "Adjust projector view" %}:
|
{% trans "Adjust projector view" %}:
|
||||||
<a class="beamer_edit" href="{% url beamer_bigger %}"><img src="/static/images/icons/zoom-in.png"></a> <a class="beamer_edit" href="{% url beamer_smaller %}"><img src="/static/images/icons/zoom-out.png"></a>
|
<a class="beamer_edit" href="{% url beamer_bigger %}" title="{% trans 'Zoom in' %}"><img src="/static/images/icons/zoom-in.png"></a>
|
||||||
<a class="beamer_edit" href="{% url beamer_up %}"><img src="/static/images/icons/go-up.png"></a> <a class="beamer_edit" href="{% url beamer_down %}"><img src="/static/images/icons/go-down.png"></a>
|
<a class="beamer_edit" href="{% url beamer_smaller %}" title="{% trans 'Zoom out' %}"><img src="/static/images/icons/zoom-out.png"></a>
|
||||||
<a class="beamer_edit" href="{% url beamer_clean %}"><img src="/static/images/icons/view-restore.png"></a>
|
<a class="beamer_edit" href="{% url beamer_up %}" title="{% trans 'Scroll text up' %}"><img src="/static/images/icons/go-up.png"></a>
|
||||||
|
<a class="beamer_edit" href="{% url beamer_down %}" title="{% trans 'Scroll text down' %}"><img src="/static/images/icons/go-down.png"></a>
|
||||||
|
<a class="beamer_edit" href="{% url beamer_clean %}" title="{% trans 'Reset projector view' %}"><img src="/static/images/icons/view-restore.png"></a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<table id="menu-overview" class="agendatable">
|
<table id="menu-overview" class="agendatable">
|
||||||
<tr>
|
<tr>
|
||||||
{% if perms.agenda.can_manage_agenda %}
|
{% if perms.agenda.can_manage_agenda %}
|
||||||
@ -153,7 +166,7 @@
|
|||||||
<td style="width: 1px;white-space: nowrap;">
|
<td style="width: 1px;white-space: nowrap;">
|
||||||
<a href="{{ item.get_absolute_url }}"><img src="/static/images/icons/document-preview.png" title="{% trans 'Show projector preview' %}"></a>
|
<a href="{{ item.get_absolute_url }}"><img src="/static/images/icons/document-preview.png" title="{% trans 'Show projector preview' %}"></a>
|
||||||
|
|
||||||
{% if perms.agenda.can_manage_agenda %}
|
{% if perms.agenda.can_manage_agenda %}
|
||||||
<a href="{% url item_edit item.id %}"><img src="/static/images/icons/document-edit.png" title="{% trans 'Edit item' %}"></a>
|
<a href="{% url item_edit item.id %}"><img src="/static/images/icons/document-edit.png" title="{% trans 'Edit item' %}"></a>
|
||||||
<a href="{% url item_delete item.id %}"><img src="/static/images/icons/edit-delete.png" title="{% trans 'Delete item' %}"></a>
|
<a href="{% url item_delete item.id %}"><img src="/static/images/icons/edit-delete.png" title="{% trans 'Delete item' %}"></a>
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
{% now "H:i" %}
|
{% now "H:i" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="countdown">0:00</div>
|
||||||
|
|
||||||
<div id="content">
|
<div id="content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -66,4 +66,14 @@ urlpatterns = patterns('agenda.views',
|
|||||||
url(r'^beamer/down$', 'beamer_edit', {'direction': 'down'}, name='beamer_down'),
|
url(r'^beamer/down$', 'beamer_edit', {'direction': 'down'}, name='beamer_down'),
|
||||||
|
|
||||||
url(r'^beamer/clean$', 'beamer_edit', {'direction': 'clean'}, name='beamer_clean'),
|
url(r'^beamer/clean$', 'beamer_edit', {'direction': 'clean'}, name='beamer_clean'),
|
||||||
|
|
||||||
|
url(r'^beamer/countdown/show$', 'beamer_countdown', {'command': 'show'}, name='countdown_open'),
|
||||||
|
|
||||||
|
url(r'^beamer/countdown/hide$', 'beamer_countdown', {'command': 'hide'}, name='countdown_close'),
|
||||||
|
|
||||||
|
url(r'^beamer/countdown/reset/(?P<time>\d+)$', 'beamer_countdown', {'command': 'reset'}, name='countdown_reset'),
|
||||||
|
|
||||||
|
url(r'^beamer/countdown/start$', 'beamer_countdown', {'command': 'start'}, name='countdown_start'),
|
||||||
|
|
||||||
|
url(r'^beamer/countdown/stop$', 'beamer_countdown', {'command': 'stop'}, name='countdown_stop'),
|
||||||
)
|
)
|
||||||
|
@ -83,7 +83,11 @@ def beamer(request):
|
|||||||
'title': data['title'],
|
'title': data['title'],
|
||||||
'time': datetime.now().strftime('%H:%M'),
|
'time': datetime.now().strftime('%H:%M'),
|
||||||
'bigger': config_get('bigger'),
|
'bigger': config_get('bigger'),
|
||||||
'up': config_get('up')}
|
'up': config_get('up'),
|
||||||
|
'countdown_visible': config_get('countdown_visible'),
|
||||||
|
'countdown_time': config_get('agenda_countdown_time'),
|
||||||
|
'countdown_control': config_get('countdown_control'),
|
||||||
|
}
|
||||||
return ajax_request(jsondata)
|
return ajax_request(jsondata)
|
||||||
else:
|
else:
|
||||||
return render_to_response(template,
|
return render_to_response(template,
|
||||||
@ -108,6 +112,27 @@ def beamer_edit(request, direction):
|
|||||||
return ajax_request({})
|
return ajax_request({})
|
||||||
return redirect(reverse('item_overview'))
|
return redirect(reverse('item_overview'))
|
||||||
|
|
||||||
|
@permission_required('agenda.can_manage_agenda')
|
||||||
|
def beamer_countdown(request, command, time=60):
|
||||||
|
if command == 'show':
|
||||||
|
config_set('countdown_visible', True)
|
||||||
|
elif command == 'hide':
|
||||||
|
config_set('countdown_visible', False)
|
||||||
|
elif command == 'reset':
|
||||||
|
config_set('countdown_control', 'reset')
|
||||||
|
elif command == 'start':
|
||||||
|
config_set('countdown_control', 'start')
|
||||||
|
elif command == 'stop':
|
||||||
|
config_set('countdown_control', 'stop')
|
||||||
|
|
||||||
|
if request.is_ajax():
|
||||||
|
if command == "show":
|
||||||
|
link = reverse('countdown_close')
|
||||||
|
else:
|
||||||
|
link = reverse('countdown_open')
|
||||||
|
return ajax_request({'countdown_visible': config_get('countdown_visible'),
|
||||||
|
'link': link})
|
||||||
|
return redirect(reverse('item_overview'))
|
||||||
|
|
||||||
def assignment_votes(item):
|
def assignment_votes(item):
|
||||||
votes = []
|
votes = []
|
||||||
@ -170,7 +195,9 @@ def overview(request):
|
|||||||
'items': items,
|
'items': items,
|
||||||
'items_hidden': items_hidden,
|
'items_hidden': items_hidden,
|
||||||
'overview': overview,
|
'overview': overview,
|
||||||
'summary': is_summary()
|
'summary': is_summary(),
|
||||||
|
'countdown_visible': config_get('countdown_visible'),
|
||||||
|
'countdown_time': config_get('agenda_countdown_time'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ $(function() {
|
|||||||
hideClosedSlides(true);
|
hideClosedSlides(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// controll beamer
|
// control beamer
|
||||||
$('.beamer_edit').click(function(event) {
|
$('.beamer_edit').click(function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
link = $(this);
|
link = $(this);
|
||||||
@ -117,5 +117,35 @@ $(function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// control countdown
|
||||||
|
$('.beamer_countdown').click(function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
link = $(this);
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: link.attr('href'),
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$('.countdown_visible_link').click(function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
link = $(this);
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: link.attr('href'),
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data) {
|
||||||
|
if (data.countdown_visible == "True") {
|
||||||
|
newclass = 'open';
|
||||||
|
} else {
|
||||||
|
newclass = 'closed';
|
||||||
|
}
|
||||||
|
link.removeClass('closed open').addClass(newclass);
|
||||||
|
link.attr('href', data.link);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
ko.applyBindings(ViewModel);
|
ko.applyBindings(ViewModel);
|
||||||
});
|
});
|
||||||
|
@ -14,6 +14,18 @@ function presentation_reload() {
|
|||||||
$('#content li').css({'font-size': data.bigger + '%'}, 200);
|
$('#content li').css({'font-size': data.bigger + '%'}, 200);
|
||||||
$('#content #sidebar').css({'font-size': '16px'}, 0);
|
$('#content #sidebar').css({'font-size': '16px'}, 0);
|
||||||
$('#content').animate({'margin-top': data.up + 'em'}, 200);
|
$('#content').animate({'margin-top': data.up + 'em'}, 200);
|
||||||
|
if (data.countdown_visible == "True")
|
||||||
|
$('#countdown').slideDown();
|
||||||
|
if (data.countdown_visible == "False")
|
||||||
|
$('#countdown').slideUp();
|
||||||
|
if (data.countdown_control == "reset")
|
||||||
|
resetTimer(data.countdown_time);
|
||||||
|
if (data.countdown_control == 'start') {
|
||||||
|
if (!timer_is_running)
|
||||||
|
startTimer();
|
||||||
|
}
|
||||||
|
if (data.countdown_control == 'stop')
|
||||||
|
stopTimer();
|
||||||
setTimeout("presentation_reload()", 500);
|
setTimeout("presentation_reload()", 500);
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
@ -38,3 +50,47 @@ $(document).ready(function() {
|
|||||||
switchajax();
|
switchajax();
|
||||||
presentation_reload();
|
presentation_reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// *** Countdown variables and functions ***
|
||||||
|
var timer_value;
|
||||||
|
var timer_is_running=false;
|
||||||
|
var timer_is_visible=false;
|
||||||
|
var timerIntervalId;
|
||||||
|
|
||||||
|
function resetTimer(value) {
|
||||||
|
stopTimer()
|
||||||
|
timer_value = value;
|
||||||
|
updateTimer();
|
||||||
|
}
|
||||||
|
function stopTimer() {
|
||||||
|
timer_is_running = false;
|
||||||
|
clearInterval(timerIntervalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTimer() {
|
||||||
|
timer_is_running = true;
|
||||||
|
if (timer_value > 0) {
|
||||||
|
timerIntervalId = setInterval("decrementTimer()", 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function decrementTimer() {
|
||||||
|
timer_value--;
|
||||||
|
if (timer_value <= 0) {
|
||||||
|
timer_value = 0;
|
||||||
|
stopTimer();
|
||||||
|
}
|
||||||
|
updateTimer();
|
||||||
|
}
|
||||||
|
function convertSeconds(s) {
|
||||||
|
var m = Math.floor(s / 60);
|
||||||
|
s %= 60;
|
||||||
|
var h = Math.floor(m / 60);
|
||||||
|
m %= 60;
|
||||||
|
return (h>0?h+':':'') + (h>0&&m<10?'0':'') + m + ':' + (s<10?'0':'') + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTimer() {
|
||||||
|
if (timer_value >= 0) {
|
||||||
|
$("#countdown").html(convertSeconds(timer_value));
|
||||||
|
}
|
||||||
|
}
|
@ -47,3 +47,19 @@ a.hidelink.show div {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.countdown_visible_link.closed div {
|
||||||
|
background-image: url(/static/images/icons/user-offline.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
a.countdown_visible_link.open div {
|
||||||
|
background-image: url(/static/images/icons/user-online.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
@ -56,10 +56,22 @@ body{
|
|||||||
padding-left:30px;
|
padding-left:30px;
|
||||||
background: url(../images/icons/clock.png) no-repeat scroll 0px 4px;
|
background: url(../images/icons/clock.png) no-repeat scroll 0px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#currentTime.ajax_error {
|
#currentTime.ajax_error {
|
||||||
border-bottom: 4px solid red;
|
border-bottom: 4px solid red;
|
||||||
}
|
}
|
||||||
|
#countdown {
|
||||||
|
display: none;
|
||||||
|
font-size: 4em;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 1em;
|
||||||
|
position: fixed;
|
||||||
|
right: 40px;
|
||||||
|
top: 0;
|
||||||
|
background: #DDD9D9;
|
||||||
|
border-bottom-left-radius: 0.75em;
|
||||||
|
border-bottom-right-radius: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*** CONTENT ***/
|
/*** CONTENT ***/
|
||||||
#content {
|
#content {
|
||||||
|
@ -32,6 +32,12 @@ class EventConfigForm(Form):
|
|||||||
event_location = CharField(widget=TextInput(), required=False, label=_("Event location"))
|
event_location = CharField(widget=TextInput(), required=False, label=_("Event location"))
|
||||||
event_organizer = CharField(widget=TextInput(), required=False, label=_("Event organizer"))
|
event_organizer = CharField(widget=TextInput(), required=False, label=_("Event organizer"))
|
||||||
|
|
||||||
|
class AgendaConfigForm(Form):
|
||||||
|
error_css_class = 'error'
|
||||||
|
required_css_class = 'required'
|
||||||
|
|
||||||
|
agenda_countdown_time = IntegerField(widget=TextInput(attrs={'class':'small-input'}),label=_("Countdown (in seconds)"),initial=60, min_value=0)
|
||||||
|
|
||||||
class ApplicationConfigForm(Form):
|
class ApplicationConfigForm(Form):
|
||||||
error_css_class = 'error'
|
error_css_class = 'error'
|
||||||
required_css_class = 'required'
|
required_css_class = 'required'
|
||||||
|
@ -16,6 +16,7 @@ from django.utils.translation import ugettext as _
|
|||||||
DEFAULT_DATA = {
|
DEFAULT_DATA = {
|
||||||
'event_name': 'OpenSlides',
|
'event_name': 'OpenSlides',
|
||||||
'event_description': 'Presentation and voting system',
|
'event_description': 'Presentation and voting system',
|
||||||
|
'agenda_countdown_time': 60,
|
||||||
'application_min_supporters': 4,
|
'application_min_supporters': 4,
|
||||||
'application_preamble': 'Die Versammlung möge beschließen,',
|
'application_preamble': 'Die Versammlung möge beschließen,',
|
||||||
'application_pdf_title': _('Applications'),
|
'application_pdf_title': _('Applications'),
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
{{ form_event.as_p }}
|
{{ form_event.as_p }}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<p></p>
|
<p></p>
|
||||||
|
<fieldset>
|
||||||
|
<legend>{%trans "Agenda" %}</legend>
|
||||||
|
{{ form_agenda.as_p }}
|
||||||
|
</fieldset>
|
||||||
|
<p></p>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{%trans "Application" %}</legend>
|
<legend>{%trans "Application" %}</legend>
|
||||||
{{ form_application.as_p }}
|
{{ form_application.as_p }}
|
||||||
|
@ -16,7 +16,7 @@ from django.contrib import messages
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from utils.utils import template
|
from utils.utils import template
|
||||||
from utils.utils import template, permission_required
|
from utils.utils import template, permission_required
|
||||||
from system.forms import SystemConfigForm, EventConfigForm, ApplicationConfigForm, AssignmentConfigForm
|
from system.forms import SystemConfigForm, EventConfigForm, AgendaConfigForm, ApplicationConfigForm, AssignmentConfigForm
|
||||||
from system.api import config_get, config_set
|
from system.api import config_get, config_set
|
||||||
|
|
||||||
@permission_required('system.can_manage_system')
|
@permission_required('system.can_manage_system')
|
||||||
@ -45,15 +45,18 @@ def get_system_config(request):
|
|||||||
def get_general_config(request):
|
def get_general_config(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form_event = EventConfigForm(request.POST, prefix='event')
|
form_event = EventConfigForm(request.POST, prefix='event')
|
||||||
|
form_agenda = AgendaConfigForm(request.POST, prefix='agenda')
|
||||||
form_application = ApplicationConfigForm(request.POST, prefix='application')
|
form_application = ApplicationConfigForm(request.POST, prefix='application')
|
||||||
form_assignment = AssignmentConfigForm(request.POST, prefix='assignment')
|
form_assignment = AssignmentConfigForm(request.POST, prefix='assignment')
|
||||||
if form_event.is_valid() and form_application.is_valid() and form_assignment.is_valid():
|
if form_event.is_valid() and form_agenda.is_valid() and form_application.is_valid() and form_assignment.is_valid():
|
||||||
# event form
|
# event form
|
||||||
config_set('event_name', form_event.cleaned_data['event_name'])
|
config_set('event_name', form_event.cleaned_data['event_name'])
|
||||||
config_set('event_description', form_event.cleaned_data['event_description'])
|
config_set('event_description', form_event.cleaned_data['event_description'])
|
||||||
config_set('event_date', form_event.cleaned_data['event_date'])
|
config_set('event_date', form_event.cleaned_data['event_date'])
|
||||||
config_set('event_location', form_event.cleaned_data['event_location'])
|
config_set('event_location', form_event.cleaned_data['event_location'])
|
||||||
config_set('event_organizer', form_event.cleaned_data['event_organizer'])
|
config_set('event_organizer', form_event.cleaned_data['event_organizer'])
|
||||||
|
# agenda form
|
||||||
|
config_set('agenda_countdown_time', form_agenda.cleaned_data['agenda_countdown_time'])
|
||||||
# application form
|
# application form
|
||||||
config_set('application_min_supporters', form_application.cleaned_data['application_min_supporters'])
|
config_set('application_min_supporters', form_application.cleaned_data['application_min_supporters'])
|
||||||
config_set('application_preamble', form_application.cleaned_data['application_preamble'])
|
config_set('application_preamble', form_application.cleaned_data['application_preamble'])
|
||||||
@ -78,6 +81,9 @@ def get_general_config(request):
|
|||||||
'event_location': config_get('event_location'),
|
'event_location': config_get('event_location'),
|
||||||
'event_organizer': config_get('event_organizer'),
|
'event_organizer': config_get('event_organizer'),
|
||||||
}, prefix='event')
|
}, prefix='event')
|
||||||
|
form_agenda = AgendaConfigForm(initial={
|
||||||
|
'agenda_countdown_time': config_get('agenda_countdown_time'),
|
||||||
|
}, prefix='agenda')
|
||||||
form_application = ApplicationConfigForm(initial={
|
form_application = ApplicationConfigForm(initial={
|
||||||
'application_min_supporters': config_get('application_min_supporters'),
|
'application_min_supporters': config_get('application_min_supporters'),
|
||||||
'application_preamble': config_get('application_preamble'),
|
'application_preamble': config_get('application_preamble'),
|
||||||
@ -94,6 +100,7 @@ def get_general_config(request):
|
|||||||
}, prefix='assignment')
|
}, prefix='assignment')
|
||||||
return {
|
return {
|
||||||
'form_event': form_event,
|
'form_event': form_event,
|
||||||
|
'form_agenda': form_agenda,
|
||||||
'form_application': form_application,
|
'form_application': form_application,
|
||||||
'form_assignment': form_assignment,
|
'form_assignment': form_assignment,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user