diff --git a/project/dateutils.py b/project/dateutils.py
index bdd7ef4..4df0afc 100644
--- a/project/dateutils.py
+++ b/project/dateutils.py
@@ -42,6 +42,16 @@ def date_set_end_of_day(date):
return date_add_time(date, hour=23, minute=59, second=59)
+def round_to_next_full_hour(date):
+ new_date = date + timedelta(hours=1)
+ return date_add_time(date, new_date.hour, tzinfo=date.tzinfo)
+
+
+def get_next_full_hour():
+ now = get_now()
+ return round_to_next_full_hour(now)
+
+
def form_input_to_date(date_str, hour=0, minute=0, second=0):
date = datetime.strptime(date_str, "%Y-%m-%d")
date_time = date_add_time(date, hour=hour, minute=minute, second=second)
diff --git a/project/forms/widgets.py b/project/forms/widgets.py
index 707af62..8cf791d 100644
--- a/project/forms/widgets.py
+++ b/project/forms/widgets.py
@@ -19,7 +19,7 @@ def create_option_string(count, value):
result = ""
for i in range(count):
selected = " selected" if i == value else ""
- result = result + '' % (i, selected, i)
+ result = result + '' % (i, selected, i)
return result
@@ -51,12 +51,10 @@ class CustomDateTimeWidget:
time_minute_params = html_params(
name=field.name, id=id + "-minute", class_=kwargs_class, **kwargs
)
- clear_button_id = id + "-clear-button"
return Markup(
- '
:
'.format(
+ ':
'.format(
date_params,
- clear_button_id,
time_hour_params,
create_option_string(24, hour),
time_minute_params,
diff --git a/project/static/site.js b/project/static/site.js
index aca58fd..405d5b1 100644
--- a/project/static/site.js
+++ b/project/static/site.js
@@ -98,13 +98,24 @@ jQuery.tools.recurrenceinput.localize('de', {
}
});
+function get_moment_with_time(field_id) {
+ return moment($(field_id).val()).add($(field_id + "-hour").val(), "hour").add($(field_id + "-minute").val(), "minute");
+}
+
function set_date_bounds(picker) {
var data_range_to_attr = picker.attr('data-range-to');
-
if (data_range_to_attr) {
- from_date = picker.datepicker("getDate");
- from_moment = moment(from_date);
- $(data_range_to_attr + '-user').datepicker("option", "minDate", from_date);
+ var hidden_field_id = picker.attr('id').replace('-user', '');
+ var from_moment = get_moment_with_time('#'+hidden_field_id);
+ $(data_range_to_attr + '-user').datepicker("option", "minDate", from_moment.toDate());
+
+ var end_val = $(data_range_to_attr).val();
+ if (end_val != '') {
+ var end_moment = get_moment_with_time(data_range_to_attr);
+ if (end_moment < from_moment) {
+ set_picker_date($(data_range_to_attr), from_moment.toDate());
+ }
+ }
var data_range_max_attr = picker.attr('data-range-max-days');
if (data_range_max_attr) {
@@ -112,11 +123,31 @@ function set_date_bounds(picker) {
$(data_range_to_attr + '-user').datepicker("option", "maxDate", from_moment.toDate());
}
}
+
+ var data_range_from_attr = picker.attr('data-range-from');
+ if (data_range_from_attr) {
+ var hidden_field_id = picker.attr('id').replace('-user', '');
+ var to_moment = get_moment_with_time('#'+hidden_field_id);
+
+ var start_val = $(data_range_from_attr).val();
+ if (start_val != '') {
+ var start_moment = get_moment_with_time(data_range_from_attr);
+ if (start_moment > to_moment) {
+ set_picker_date($(data_range_from_attr), to_moment.toDate());
+ }
+ }
+ }
}
function set_picker_date(picker, date, timeout = -1) {
picker.datepicker("setDate", date);
+ var hidden_field_id = picker.attr('id').replace('-user', '');
+ var hour = date == null ? 0 : date.getHours();
+ var minute = date == null ? 0 : date.getMinutes();
+ $("#" + hidden_field_id + "-hour").val(hour.toString());
+ $("#" + hidden_field_id + "-minute").val(minute.toString());
+
if (timeout < 0) {
set_date_bounds(picker);
} else {
@@ -150,16 +181,15 @@ function start_datepicker(input) {
var hidden_value = hidden_field.val();
if (hidden_value) {
- set_picker_date(picker, moment(hidden_value).toDate(), 100)
+ set_picker_date(picker, get_moment_with_time('#'+hidden_field_id).toDate(), 100)
}
hidden_field.after(user_field);
- $("#" + hidden_field_id + "-clear-button").click(function() {
- set_picker_date(picker, null)
- $("#" + hidden_field_id + "-hour").val("00");
- $("#" + hidden_field_id + "-minute").val("00");
- });
+ var data_range_to_attr = picker.attr('data-range-to');
+ if (data_range_to_attr) {
+ $(data_range_to_attr).attr('data-range-from', '#'+hidden_field_id);
+ }
hidden_field.change(function() {
var hidden_value = hidden_field.val();
@@ -184,6 +214,14 @@ function start_datepicker(input) {
}
});
+ $("#" + hidden_field_id + "-hour").change(function() {
+ set_date_bounds(picker);
+ });
+
+ $("#" + hidden_field_id + "-minute").change(function() {
+ set_date_bounds(picker);
+ });
+
return picker;
}
@@ -274,6 +312,22 @@ $( function() {
e.stopPropagation();
$(this).removeClass('dragover');
});
+
+ $('.show-link').click(function(e){
+ e.preventDefault();
+ e.stopPropagation();
+ $('#'+$(this).attr('data-show-container')).hide();
+ $('#'+$(this).attr('data-container')).show();
+ $('#'+$(this).attr('data-container')).trigger('shown');
+ });
+
+ $('.hide-link').click(function(e){
+ e.preventDefault();
+ e.stopPropagation();
+ $('#'+$(this).attr('data-show-container')).show();
+ $('#'+$(this).attr('data-container')).hide();
+ $('#'+$(this).attr('data-container')).trigger('hidden');
+ });
});
String.prototype.truncate = String.prototype.truncate ||
diff --git a/project/templates/_macros.html b/project/templates/_macros.html
index 74fc68b..dbe64e4 100644
--- a/project/templates/_macros.html
+++ b/project/templates/_macros.html
@@ -1,79 +1,94 @@
{% macro render_field_with_errors(field) %}
- {% set is_required = kwargs['is_required'] if 'is_required' in kwargs else field.flags.required %}
- {% set label_text = field.label.text + ' *' if is_required else field.label.text %}
-
- {% if 'ri' in kwargs and kwargs['ri'] == 'checkbox' %}
- {% else %}
- {{ field.label(text=label_text, class="mb-0") }}
- {% endif %}
-
- {% if field.description %}
-
- {{ field.description }}
-
- {% endif %}
-
-
-
- {% if field.errors %}
-
- {% for error in field.errors %}
-
{{ error }}
- {% endfor %}
-
- {% endif %}
+ {% set is_collapsible = kwargs['is_collapsible'] if 'is_collapsible' in kwargs else False %}
+ {% if is_collapsible %}
+
+
+ {% endif %}
+
+ {% set is_required = kwargs['is_required'] if 'is_required' in kwargs else field.flags.required %}
+ {% set label_text = field.label.text + ' *' if is_required else field.label.text %}
+
+
+ {% if is_collapsible %}
+
+
+ {% endif %}
{% endmacro %}
{% macro render_field(field) %}
@@ -1151,10 +1166,6 @@ if (URL) {
{% endmacro %}
+{% macro render_end_container_handling() %}
+$('#end-container').on('shown', function() {
+ var end_moment = get_moment_with_time('#start').add(3, 'hours');
+ set_picker_date($('#end-user'), end_moment.toDate());
+});
+
+$('#end-container').on('hidden', function() {
+ set_picker_date($('#end-user'), null);
+});
+{% endmacro %}
+
{% macro render_cropper_header() %}
diff --git a/project/templates/event/create.html b/project/templates/event/create.html
index 9813969..8d833cb 100644
--- a/project/templates/event/create.html
+++ b/project/templates/event/create.html
@@ -1,5 +1,5 @@
{% extends "layout.html" %}
-{% from "_macros.html" import render_jquery_steps_header, render_google_place_autocomplete_field, render_google_place_autocomplete_header, render_cropper_header, render_cropper_code, render_crop_image_form_section, render_radio_buttons, render_field_with_errors, render_field %}
+{% from "_macros.html" import render_end_container_handling, render_jquery_steps_header, render_google_place_autocomplete_field, render_google_place_autocomplete_header, render_cropper_header, render_cropper_code, render_crop_image_form_section, render_radio_buttons, render_field_with_errors, render_field %}
{%- block title -%}
{{ _('Create event') }}
{%- endblock -%}
@@ -60,6 +60,8 @@ $( function() {
});
update_organizer_container($('input[type=radio][name=organizer_choice]:checked').val());
+
+ {{ render_end_container_handling() }}
});
{% endblock %}
@@ -85,8 +87,8 @@ $( function() {
{{ _('Event date') }}
- {{ render_field_with_errors(form.start, **{"data-range-to":"#end", "data-range-max-days": "1"}) }}
- {{ render_field_with_errors(form.end) }}
+ {{ render_field_with_errors(form.start, **{"data-range-to":"#end", "data-range-max-days": "14"}) }}
+ {{ render_field_with_errors(form.end, is_collapsible=1) }}
{{ render_field_with_errors(form.recurrence_rule, ri="rrule") }}
diff --git a/project/templates/event/update.html b/project/templates/event/update.html
index c5eff0f..e970803 100644
--- a/project/templates/event/update.html
+++ b/project/templates/event/update.html
@@ -1,5 +1,5 @@
{% extends "layout.html" %}
-{% from "_macros.html" import render_jquery_steps_header, render_cropper_code, render_crop_image_form_section, render_radio_buttons, render_field_with_errors, render_field %}
+{% from "_macros.html" import render_end_container_handling, render_jquery_steps_header, render_cropper_code, render_crop_image_form_section, render_radio_buttons, render_field_with_errors, render_field %}
{%- block title -%}
{{ _('Update event') }}
{%- endblock -%}
@@ -50,6 +50,8 @@
window.open('{{ url_for("manage_admin_unit_places_create", id=event.admin_unit_id) }}');
return false;
});
+
+ {{ render_end_container_handling() }}
});
{% endblock %}
@@ -75,8 +77,8 @@
{{ _('Event date') }}
- {{ render_field_with_errors(form.start, **{"data-range-to":"#end", "data-range-max-days": "1"}) }}
- {{ render_field_with_errors(form.end) }}
+ {{ render_field_with_errors(form.start, **{"data-range-to":"#end", "data-range-max-days": "14"}) }}
+ {{ render_field_with_errors(form.end, is_collapsible=1) }}
{{ render_field_with_errors(form.recurrence_rule, ri="rrule") }}
diff --git a/project/templates/widget/event_suggestion/create.html b/project/templates/widget/event_suggestion/create.html
index af270ec..2515900 100644
--- a/project/templates/widget/event_suggestion/create.html
+++ b/project/templates/widget/event_suggestion/create.html
@@ -1,5 +1,5 @@
{% extends "layout_widget.html" %}
-{% from "_macros.html" import render_logo, render_cropper_code, render_crop_image_form, render_jquery_steps_header, render_cropper_header, render_radio_buttons, render_field_with_errors, render_field %}
+{% from "_macros.html" import render_end_container_handling, render_logo, render_cropper_code, render_crop_image_form, render_jquery_steps_header, render_cropper_header, render_radio_buttons, render_field_with_errors, render_field %}
{%- block title -%}
{{ _('Create event suggestion') }}
{%- endblock -%}
@@ -114,6 +114,8 @@
}
});
+ {{ render_end_container_handling() }}
+
});
{% endblock %}
@@ -198,8 +200,8 @@
{{ render_field_with_errors(form.name) }}
{{ render_field_with_errors(form.event_place_id, class="w-100") }}
{{ render_field_with_errors(form.organizer_id, class="w-100") }}
- {{ render_field_with_errors(form.start, **{"data-range-to":"#end", "data-range-max-days": "1"}) }}
- {{ render_field_with_errors(form.end) }}
+ {{ render_field_with_errors(form.start, **{"data-range-to":"#end", "data-range-max-days": "14"}) }}
+ {{ render_field_with_errors(form.end, is_collapsible=1) }}
{{ render_field_with_errors(form.recurrence_rule, ri="rrule") }}
diff --git a/project/views/event.py b/project/views/event.py
index 60615b7..1dc267e 100644
--- a/project/views/event.py
+++ b/project/views/event.py
@@ -15,6 +15,7 @@ from project.access import (
has_access,
has_admin_unit_member_permission,
)
+from project.dateutils import get_next_full_hour
from project.forms.event import CreateEventForm, DeleteEventForm, UpdateEventForm
from project.jsonld import DateTimeEncoder, get_sd_for_event_date
from project.models import (
@@ -279,6 +280,9 @@ def prepare_event_form(form, admin_unit):
form.organizer_id.choices.insert(0, (0, ""))
form.event_place_id.choices.insert(0, (0, ""))
+ if not form.start.data:
+ form.start.data = get_next_full_hour()
+
def prepare_event_form_for_suggestion(form, event_suggestion):
form.name.data = event_suggestion.name
diff --git a/project/views/widget.py b/project/views/widget.py
index f035323..83fcee1 100644
--- a/project/views/widget.py
+++ b/project/views/widget.py
@@ -8,6 +8,7 @@ from sqlalchemy.sql import func
from project import app, db
from project.access import has_admin_unit_member_permission
+from project.dateutils import get_next_full_hour
from project.forms.event_date import FindEventDateForm
from project.forms.event_suggestion import CreateEventSuggestionForm
from project.jsonld import DateTimeEncoder, get_sd_for_event_date
@@ -136,6 +137,9 @@ def event_suggestion_create_for_admin_unit(au_short_name):
form.category_ids.choices = get_event_category_choices()
+ if not form.start.data:
+ form.start.data = get_next_full_hour()
+
if form.validate_on_submit():
event_suggestion = EventSuggestion()
form.populate_obj(event_suggestion)