mirror of
https://github.com/lucaspalomodevelop/eventcally.git
synced 2026-03-13 00:07:22 +00:00
531 lines
24 KiB
HTML
531 lines
24 KiB
HTML
{% extends "layout.html" %}
|
|
{% from "_macros.html" import render_date_field_range, render_field, render_event_dates_location_field, render_event_dates_date_field, render_field_with_errors, render_form_styles, render_form_scripts, render_jquery_steps_header, render_google_filter_autocomplete_header, render_pagination, render_place, render_events_sub_menu %}
|
|
{% set user_can_reference_event = current_admin_unit and has_access(current_admin_unit, "event:reference") %}
|
|
|
|
{%- block title -%}
|
|
{{ _('Event Dates') }}
|
|
{%- endblock -%}
|
|
|
|
{% block styles %}
|
|
{{ render_form_styles() }}
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='ext/leaflet.1.5.1.css')}}" />
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='ext/MarkerCluster@1.4.1.Default.css')}}" />
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='ext/MarkerCluster.1.4.1.css')}}" />
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='ext/L.Control.Locate.0.68.0.min.css')}}" />
|
|
{% endblock %}
|
|
|
|
{% block header_before_site_js %}
|
|
{{ render_form_scripts() }}
|
|
<script src="{{ url_for('static', filename='ext/leaflet.1.5.1.js')}}"></script>
|
|
<script src="{{ url_for('static', filename='ext/leaflet.markercluster.1.4.1.js')}}"></script>
|
|
<script src="{{ url_for('static', filename='ext/L.Control.Locate.0.68.0.min.js')}}" charset="utf-8"></script>
|
|
{%- endblock -%}
|
|
|
|
{% block header %}
|
|
<script src="{{ url_for('static', filename='svg-icon.js')}}"></script>
|
|
{{ render_jquery_steps_header() }}
|
|
{{ render_google_filter_autocomplete_header() }}
|
|
<script>
|
|
|
|
var page = 1;
|
|
var per_page = 50;
|
|
|
|
var leaflet_map = null;
|
|
var map_cluster_group = null;
|
|
var event_dates = null;
|
|
var current_data = null;
|
|
var arrayOfMarkers = [];
|
|
|
|
function init_leaflet_map() {
|
|
if (leaflet_map != null) {
|
|
return;
|
|
}
|
|
|
|
leaflet_map = L.map('map').fitWorld();
|
|
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
}).addTo(leaflet_map);
|
|
|
|
L.control.locate({
|
|
keepCurrentZoomLevel: true,
|
|
icon: 'fa fa-location-arrow'
|
|
}).addTo(leaflet_map);
|
|
}
|
|
|
|
function clear_events_from_map() {
|
|
if (leaflet_map == null) {
|
|
return;
|
|
}
|
|
|
|
if (map_cluster_group != null) {
|
|
map_cluster_group.clearLayers();
|
|
}
|
|
|
|
arrayOfMarkers = [];
|
|
}
|
|
|
|
function show_event_in_list(event_id) {
|
|
var card = $('#event_card_' + event_id);
|
|
scroll_to_element(
|
|
card,
|
|
function () {
|
|
card.effect("highlight", {}, 500);
|
|
});
|
|
}
|
|
|
|
function fly_to_event(latitude, longitude) {
|
|
$('#map').show();
|
|
|
|
if (arrayOfMarkers.length == 0) {
|
|
add_events_to_map();
|
|
}
|
|
|
|
scroll_to_element(
|
|
$('#map'),
|
|
function () {
|
|
leaflet_map.flyTo([latitude, longitude], 16);
|
|
});
|
|
}
|
|
|
|
function format_event_date_instance(instance, allday) {
|
|
if (allday) {
|
|
return instance.format("dd. DD.MM.YYYY");
|
|
}
|
|
|
|
return instance.format("dd. DD.MM.YYYY LT")
|
|
}
|
|
|
|
function add_events_to_map() {
|
|
init_leaflet_map();
|
|
clear_events_from_map();
|
|
|
|
$.each(event_dates, function(index, event_date) {
|
|
event = event_date.event;
|
|
if (event.place != null && event.place.location != null && event.place.location.latitude != null) {
|
|
var location = event.place.location;
|
|
var start = moment(event_date.start);
|
|
var title = format_event_date_instance(start, event_date.allday) + ' ' + '<a href="#" onclick="show_event_in_list(\'' + event_date.id + '\'); return false;">' + event.name + '</a>';
|
|
|
|
var icon = new L.DivIcon.SVGIcon({
|
|
color: "#000",
|
|
fillColor: 'blue',
|
|
fillOpacity: 1.0,
|
|
iconSize: [28,41],
|
|
circleRatio: 0.35
|
|
});
|
|
|
|
var marker = L.marker([location.latitude, location.longitude], { icon: icon }).bindPopup(title);
|
|
arrayOfMarkers.push(marker);
|
|
}
|
|
});
|
|
|
|
if (arrayOfMarkers.length == 0) {
|
|
return;
|
|
}
|
|
|
|
var group_was_created = false;
|
|
|
|
if (map_cluster_group == null) {
|
|
map_cluster_group = L.markerClusterGroup({ disableClusteringAtZoom: 16});
|
|
group_was_created = true;
|
|
}
|
|
|
|
map_cluster_group.addLayers(arrayOfMarkers);
|
|
|
|
if (group_was_created) {
|
|
leaflet_map.addLayer(map_cluster_group);
|
|
}
|
|
|
|
leaflet_map.fitBounds(map_cluster_group.getBounds());
|
|
}
|
|
|
|
function toggle_map() {
|
|
if ($('#map').is(":visible")) {
|
|
$('#map').hide();
|
|
} else {
|
|
$('#map').show();
|
|
add_events_to_map();
|
|
}
|
|
}
|
|
|
|
{% if user_can_reference_event %}
|
|
function add_reference(event_id) {
|
|
$.ajax({
|
|
url: "{{ url_for('api_v1_organization_incoming_event_reference_list', id=current_admin_unit.id) }}",
|
|
type: "post",
|
|
dataType: "json",
|
|
contentType: "application/json",
|
|
data: JSON.stringify({
|
|
"event": {"id": event_id},
|
|
}),
|
|
error: function(xhr, status, error) {
|
|
alert_request_error(xhr, status, error);
|
|
},
|
|
success: function (data) {
|
|
start_request(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
function remove_reference(reference_id) {
|
|
$.ajax({
|
|
url: "/api/v1/event-references/" + reference_id,
|
|
type: "delete",
|
|
error: function(xhr, status, error) {
|
|
alert_request_error(xhr, status, error);
|
|
},
|
|
success: function (data) {
|
|
start_request(true);
|
|
}
|
|
});
|
|
}
|
|
{% endif %}
|
|
|
|
var scrollPos;
|
|
|
|
function start_request(remember_scroll_pos = false) {
|
|
if (remember_scroll_pos) {
|
|
scrollPos = $(window).scrollTop();
|
|
}
|
|
|
|
handle_request_start();
|
|
|
|
var result_list = $("#result_list");
|
|
result_list.empty();
|
|
|
|
var req_data = $("#filter_form :input").filter(function () {
|
|
return this.value.length > 0
|
|
}).serialize()
|
|
req_data += '&page=' + page + '&per_page=' + per_page;
|
|
|
|
$.ajax({
|
|
url: "{{ url_for('api_v1_event_date_search') }}",
|
|
type: "get",
|
|
dataType: "json",
|
|
data: req_data,
|
|
{% if user_can_reference_event %}
|
|
headers: {"X-OrganizationId": "{{ current_admin_unit.id }}"},
|
|
{% endif %}
|
|
error: function(xhr, status, error) {
|
|
handle_request_error(xhr, status, error);
|
|
},
|
|
success: function (data) {
|
|
var content = '';
|
|
current_data = data;
|
|
event_dates = data.items;
|
|
var event_date_count = event_dates.length;
|
|
|
|
var inactive_class = "text-primary";
|
|
var disabled_class = "text-secondary";
|
|
var active_class = "text-success";
|
|
var action_button_cls = "btn";
|
|
var action_icon_style = "";
|
|
|
|
$.each(event_dates, function(index, event_date) {
|
|
event = event_date.event;
|
|
|
|
var start = moment(event_date.start);
|
|
var img_tag = '';
|
|
|
|
if (event.photo != null) {
|
|
img_tag = '<img src="' + event.photo.image_url + '" class="card-img-top" style="object-fit: cover; height: 12vh;" alt="Event image" />';
|
|
} else {
|
|
img_tag = '<div class="bg-light d-flex align-items-center justify-content-center" style="height: 12vh;"><i class="fa-calendar far h1 text-muted"></i></div>';
|
|
}
|
|
|
|
var map_link_start = '';
|
|
var map_link_end = '';
|
|
|
|
if (event.place != null && event.place.location != null && event.place.location.latitude != null) {
|
|
var location = event.place.location;
|
|
map_link_start = '<a href="#" onclick="fly_to_event(' + location.latitude + ', ' + location.longitude + '); return false;" class="text-secondary">';
|
|
map_link_end = '</a>';
|
|
}
|
|
|
|
var action_tag = '';
|
|
{% if user_can_reference_event %}
|
|
if (event.organization.id == {{ current_admin_unit.id }}) {
|
|
action_tag += '<button type="button" class="' + action_button_cls + ' px-0" data-toggle="tooltip" title="{{ _('Own events cannot be referenced') }}"><i class="fa fa-fw fa-link ' + disabled_class + '" style="' + action_icon_style + '"></i> <span class="d-none d-sm-inline small ' + disabled_class + '">{{ _('Own event') }}</span></button>';
|
|
} else if (event.reference_id == null) {
|
|
action_tag += '<button type="button" onclick="$(this).tooltip(\'hide\'); add_reference(\'' + event.id + '\');" class="' + action_button_cls + ' px-0" data-toggle="tooltip" title="{{ _('Reference event') }}"><i class="fa fa-fw fa-link ' + inactive_class + '" style="' + action_icon_style + '"></i> <span class="d-none d-sm-inline small ' + inactive_class + '">{{ _('Not referenced') }}</span></button>';
|
|
} else {
|
|
action_tag += '<button type="button" onclick="$(this).tooltip(\'hide\'); remove_reference(\'' + event.reference_id + '\');" class="' + action_button_cls + ' px-0" data-toggle="tooltip" title="{{ _('Delete reference') }}"><i class="fa fa-fw fa-link ' + active_class + '" style="' + action_icon_style + '"></i> <span class="d-none d-sm-inline small ' + active_class + '">{{ _('Referenced') }}</span></button>';
|
|
}
|
|
{% endif %}
|
|
|
|
var action_div = action_tag == '' ? '' : '<div class="col-lg d-flex justify-content-between p-0 w-medium" style="font-size:0.9rem; text-align:right;">' + action_tag + '</div>';
|
|
var organization_name = event.organization.name == event.organizer.name ? '' : event.organization.name;
|
|
|
|
var desktop = '<div class="row mb-3 d-none d-sm-block">' +
|
|
'<div class="col-sm">' +
|
|
'<div class="card">' +
|
|
'<div class="card-body">' +
|
|
'<div class="row">' +
|
|
'<div class="col-sm-8">' +
|
|
'<h5 class="card-title"><a href="eventdate/' + event_date.id + '" class="text-body">' + event.name + '</a> <span class="small" style="vertical-align: middle;">' + render_event_warning_pills(event) + '</span></h5>' +
|
|
'<h6 class="card-subtitle mb-2 text-body"><i class="fa fa-calendar"></i> ' + format_event_date_instance(start, event_date.allday) + '</h6>' +
|
|
(event.description != null ? '<p class="card-text">' + event.description.truncate(200, true) + '</p>' : '') +
|
|
'<small class="text-muted mr-2"><i class="fa fa-server"></i> ' + event.organizer.name + '</small>' +
|
|
(organization_name != '' ? '<small class="text-muted mr-2"><i class="fa fa-database"></i> ' + organization_name + '</small>' : '') +
|
|
'<small class="text-muted"><i class="fa fa-map-marker"></i> ' + map_link_start + event.place.name + map_link_end + '</small>' +
|
|
'</div>' +
|
|
'<div class="col-sm-4 text-right">' +
|
|
(event.photo != null ? '<img src="' + event.photo.image_url + '" style="object-fit: contain; width: 160px; height: 160px;" alt="Event image" />' : '') +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
(action_div != '' ? '<div class="card-footer py-1">' + action_div + '</div>' : '') +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>';
|
|
var mobile = '<div class="row mb-3 d-sm-none">' +
|
|
'<div class="col-sm">' +
|
|
'<div class="card">' +
|
|
'<div>' +
|
|
(event.photo != null ? '<img src="' + event.photo.image_url + '" class="card-img-top" style="object-fit: cover; height: 12vh;" alt="Event image" />' : '') +
|
|
'</div>' +
|
|
'<div class="card-body" style="padding:0.5rem">' +
|
|
'<div class="row">' +
|
|
'<div class="col-sm-12">' +
|
|
'<h5 class="card-title"><a href="eventdate/' + event_date.id + '" class="text-body">' + event.name + '</a> <span class="small" style="vertical-align: middle;">' + render_event_warning_pills(event) + '</span></h5>' +
|
|
'<h6 class="card-subtitle mb-2 text-body"><i class="fa fa-calendar"></i> ' + format_event_date_instance(start, event_date.allday) + '</h6>' +
|
|
(event.description != null ? '<p class="card-text">' + event.description.truncate(100, true) + '</p>' : '') +
|
|
'<small class="text-muted mr-2"><i class="fa fa-server"></i> ' + event.organizer.name + '</small>' +
|
|
(organization_name != '' ? '<small class="text-muted mr-2"><i class="fa fa-database"></i> ' + organization_name + '</small>' : '') +
|
|
'<small class="text-muted"><i class="fa fa-map-marker"></i> ' + map_link_start + event.place.name + map_link_end + '</small>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'<div class="card-footer bg-transparent border-0 p-2">' +
|
|
action_div +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>';
|
|
|
|
content += '<div id="event_card_' + event_date.id + '">' + desktop + mobile + '</div>';
|
|
});
|
|
|
|
result_list.append(content);
|
|
|
|
if (data.has_prev) {
|
|
$('#first_item,#prev_item').removeClass('disabled');
|
|
} else {
|
|
$('#first_item,#prev_item').addClass('disabled');
|
|
}
|
|
|
|
if (data.has_next) {
|
|
$('#last_item,#next_item').removeClass('disabled');
|
|
} else {
|
|
$('#last_item,#next_item').addClass('disabled');
|
|
}
|
|
|
|
if (data.total > 0) {
|
|
$('#page_info_text').text("Seite " + data.page + " von " + data.pages + " (" + data.total + " insgesamt)")
|
|
$('#page_info').removeClass("d-none");
|
|
} else {
|
|
$('#page_info').addClass("d-none");
|
|
}
|
|
|
|
handle_request_success();
|
|
|
|
if (leaflet_map != null) {
|
|
add_events_to_map();
|
|
}
|
|
|
|
$('[data-toggle="tooltip"]').tooltip();
|
|
|
|
if (remember_scroll_pos) {
|
|
$(window).scrollTop(scrollPos);
|
|
} else {
|
|
scroll_to_element($('#result_container'));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function update_organizer_filter_enabled() {
|
|
if ($('#admin_unit_id').val() == null) {
|
|
$('#organizer_id').attr('disabled', 'disabled');
|
|
$('#organizer_id').val(null).trigger('change');
|
|
} else {
|
|
$('#organizer_id').removeAttr('disabled');
|
|
}
|
|
}
|
|
|
|
$( function() {
|
|
$("#filter_form").submit(function(e) {
|
|
e.stopPropagation();
|
|
page = 1;
|
|
start_request();
|
|
return false;
|
|
});
|
|
|
|
$("#first_link").click(function(){
|
|
page = 1;
|
|
start_request();
|
|
return false;
|
|
});
|
|
|
|
$("#prev_link").click(function(){
|
|
if (page > 1) {
|
|
page--;
|
|
start_request();
|
|
}
|
|
return false;
|
|
});
|
|
|
|
$("#next_link").click(function(){
|
|
page++;
|
|
start_request();
|
|
return false;
|
|
});
|
|
|
|
$("#last_link").click(function(){
|
|
page = current_data.pages;
|
|
start_request();
|
|
return false;
|
|
});
|
|
|
|
$('#map').hide();
|
|
$("#filter_form").submit();
|
|
|
|
$('#admin_unit_id').select2({
|
|
width: '100%',
|
|
theme: 'bootstrap4',
|
|
ajax: {
|
|
url: "{{ url_for('api_v1_organization_list') }}",
|
|
dataType: 'json',
|
|
delay: 250,
|
|
cache: true,
|
|
data: function (params) {
|
|
return {
|
|
keyword: params.term,
|
|
per_page: 5,
|
|
page: params.page || 1
|
|
};
|
|
},
|
|
processResults: function (data) {
|
|
return {
|
|
results: data.items.map(p => ({"id": p.id, "text": p.name})),
|
|
pagination: {
|
|
more: data.has_next
|
|
}
|
|
};
|
|
}
|
|
},
|
|
placeholder: "{{ _('Enter organization') }}",
|
|
allowClear: true
|
|
});
|
|
|
|
$('#organizer_id').select2({
|
|
width: '100%',
|
|
theme: 'bootstrap4',
|
|
ajax: {
|
|
url: function (params) {
|
|
return '/api/v1/organizations/' + $('#admin_unit_id').val() + '/organizers';
|
|
},
|
|
dataType: 'json',
|
|
delay: 250,
|
|
cache: true,
|
|
data: function (params) {
|
|
return {
|
|
name: params.term,
|
|
per_page: 5,
|
|
page: params.page || 1
|
|
};
|
|
},
|
|
processResults: function (data) {
|
|
return {
|
|
results: data.items.map(p => ({"id": p.id, "text": p.name})),
|
|
pagination: {
|
|
more: data.has_next
|
|
}
|
|
};
|
|
}
|
|
},
|
|
placeholder: "{{ _('Enter organizer') }}",
|
|
allowClear: true
|
|
});
|
|
|
|
$('#admin_unit_id').on('change', function (e) {
|
|
update_organizer_filter_enabled();
|
|
});
|
|
|
|
update_organizer_filter_enabled();
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
|
|
<h1 class="mb-0">{{ _('Event Dates') }}</h1>
|
|
|
|
<div class="my-4 w-normal" id="search_form">
|
|
<form action="" id="filter_form" class="form" method="GET" autocomplete="off">
|
|
{{ form.hidden_tag() }}
|
|
|
|
{{ render_event_dates_date_field(form.date_from, form.date_to) }}
|
|
{{ render_field_with_errors(form.keyword, formrow="1") }}
|
|
|
|
{% set form_collapsed = not form.category_id.data and not form.admin_unit_id.data and not form.organizer_id.data and not form.coordinate.data and not form.created_at_from.data and not form.created_at_to.data and form.sort.data == "start" %}
|
|
<div id="extended_search_form" class="{% if form_collapsed %}collapse{% else %}show{% endif %}">
|
|
|
|
{{ render_field_with_errors(form.category_id, formrow="1") }}
|
|
|
|
{{ render_field_with_errors(form.admin_unit_id, class="w-100", formrow="1") }}
|
|
|
|
{{ render_field_with_errors(form.organizer_id, class="w-100", formrow="1") }}
|
|
|
|
{{ render_field_with_errors(form.postal_code, formrow="1") }}
|
|
|
|
{{ render_event_dates_location_field(form.location, form.distance) }}
|
|
|
|
{{ render_date_field_range(form.created_at_from, form.created_at_to, _('Created at')) }}
|
|
|
|
{{ render_field_with_errors(form.sort, formrow="1") }}
|
|
|
|
{{ render_field_with_errors(form.exclude_recurring, ri="checkbox", formrow="1") }}
|
|
|
|
{% if user_can_reference_event %}
|
|
{{ render_field_with_errors(form.not_referenced, ri="checkbox", formrow="1") }}
|
|
{% endif %}
|
|
</div>
|
|
|
|
<p>
|
|
{{ form.submit(class="btn btn-primary mt-1 mr-1")|safe }}
|
|
<button id="toggle-search-btn" type="button" class="btn btn-secondary mt-1 mr-1" data-toggle="collapse" data-target="#extended_search_form" aria-expanded="{% if form_collapsed %}false{% else %}true{% endif %}">{{ _('More filters') }}</button>
|
|
<button type="button" id="toggle-map-btn" class="btn btn-outline-secondary mt-1 mr-1" onclick="toggle_map()"><i class="fa fa-map"></i> {{ _('Map view') }}</button>
|
|
</p>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md mx-3 mb-3" id="map" style="height: 400px;">
|
|
</div>
|
|
<div class="col-md">
|
|
<div id="result_container" class="w-normal">
|
|
<div class="m-1 small text-center text-secondary" id="result_info"></div>
|
|
<div style="min-height: 300px;">
|
|
<div id="result_list">
|
|
</div>
|
|
</div>
|
|
<nav aria-label="Page navigation">
|
|
<ul class="pagination">
|
|
<li class="page-item disabled" id="first_item"><a class="page-link" id="first_link" href="#" title="{{ _('First') }}"><i class="fa fa-angle-double-left"></i></a></li>
|
|
<li class="page-item disabled" id="prev_item"><a class="page-link" id="prev_link" href="#" title="{{ _('Previous') }}"><i class="fa fa-angle-left"></i></a></li>
|
|
<li class="page-item disabled d-none" id="page_info"><span class="page-link" id="page_info_text"></span></li>
|
|
<li class="page-item disabled" id="next_item"><a class="page-link" id="next_link" href="#" title="{{ _('Next') }}"><i class="fa fa-angle-right"></i></a></li>
|
|
<li class="page-item disabled" id="last_item"><a class="page-link" id="last_link" href="#" title="{{ _('Last') }}"><i class="fa fa-angle-double-right"></i></a></li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<div class="spinner-border m-3" role="status" id="spinner" style="display: none;">
|
|
<span class="sr-only">Loading…</span>
|
|
</div>
|
|
<div class="alert alert-danger m-3" role="alert" id="error_alert" style="display: none;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %} |