diff --git a/app/eventyay/base/configurations/default_setting.py b/app/eventyay/base/configurations/default_setting.py index 43c47d0b57..cd69f2da7f 100644 --- a/app/eventyay/base/configurations/default_setting.py +++ b/app/eventyay/base/configurations/default_setting.py @@ -21,6 +21,7 @@ pgettext_lazy, ) from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput +from eventyay.base.forms import I18nAutoExpandingTextarea from i18nfield.strings import LazyI18nString from rest_framework import serializers @@ -2230,7 +2231,7 @@ def primary_font_kwargs(): 'type': LazyI18nString, 'serializer_class': I18nField, 'form_class': I18nFormField, - 'form_kwargs': dict(label=_('Frontpage text'), widget=I18nTextarea), + 'form_kwargs': dict(label=_('Frontpage text'), widget=I18nAutoExpandingTextarea), }, 'event_info_text': { 'default': '', diff --git a/app/eventyay/base/forms/__init__.py b/app/eventyay/base/forms/__init__.py index 0260ab9cd4..e0b20659e1 100644 --- a/app/eventyay/base/forms/__init__.py +++ b/app/eventyay/base/forms/__init__.py @@ -167,6 +167,29 @@ def format_output(self, rendered_widgets, id_) -> str: return super().format_output(rendered_widgets, id_) +class I18nAutoExpandingTextarea(i18nfield.forms.I18nTextarea): + + def __init__(self, attrs=None, **kwargs): + default_attrs = { + 'class': 'form-control auto-expanding-textarea', + 'data-auto-expand': 'true', + 'style': 'min-height: 40vh; max-height: 60vh; overflow-y: hidden; resize: vertical; transition: height 0.2s ease-in-out;' + } + if attrs: + if 'class' in attrs: + default_attrs['class'] = default_attrs['class'] + ' ' + attrs['class'] + if 'style' in attrs: + default_attrs['style'] = default_attrs['style'] + '; ' + attrs['style'] + attrs_copy = attrs.copy() + attrs_copy.pop('class', None) + attrs_copy.pop('style', None) + default_attrs.update(attrs_copy) + super().__init__(attrs=default_attrs, **kwargs) + + class Media: + js = ('eventyay-common/js/auto-expanding-textarea.js',) + + class I18nURLFormField(i18nfield.forms.I18nFormField): """ Custom form field to handle internationalized URL inputs. It extends the I18nFormField @@ -202,5 +225,4 @@ def clean(self, value) -> LazyI18nString: url_validator(val) else: url_validator(value.data) - - return value + return value \ No newline at end of file diff --git a/app/eventyay/eventyay_common/static/eventyay-common/js/auto-expanding-textarea.js b/app/eventyay/eventyay_common/static/eventyay-common/js/auto-expanding-textarea.js new file mode 100644 index 0000000000..0f6981afe7 --- /dev/null +++ b/app/eventyay/eventyay_common/static/eventyay-common/js/auto-expanding-textarea.js @@ -0,0 +1,62 @@ +(function () { + 'use strict'; + + if (window.autoExpandTextareaInitialized) { + return; + } + window.autoExpandTextareaInitialized = true; + + function autoExpandTextarea(textarea) { + if (!textarea || textarea.hasAttribute('data-auto-expand-init')) return; + textarea.setAttribute('data-auto-expand-init', 'true'); + + function adjustHeight() { + textarea.style.height = 'auto'; + requestAnimationFrame(function () { + var computedStyle = window.getComputedStyle(textarea); + var minHeight = parseInt(computedStyle.minHeight, 10) || 80; + var maxHeight = parseInt(computedStyle.maxHeight, 10) || 300; + var newHeight = Math.max(minHeight, Math.min(textarea.scrollHeight, maxHeight)); + textarea.style.height = newHeight + 'px'; + textarea.style.overflowY = (textarea.scrollHeight > maxHeight) ? 'auto' : 'hidden'; + }); + } + + textarea.addEventListener('input', adjustHeight); + textarea.addEventListener('paste', function () { setTimeout(adjustHeight, 10); }); + adjustHeight(); + } + + function initializeAutoExpandTextareas() { + var textareas = document.querySelectorAll('textarea[data-auto-expand="true"]'); + textareas.forEach(function (textarea) { + if (!textarea.hasAttribute('data-auto-expand-init')) { + autoExpandTextarea(textarea); + } + }); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initializeAutoExpandTextareas); + } else { + initializeAutoExpandTextareas(); + } + + var formContainer = document.querySelector('form') || document.body; + var observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + mutation.addedNodes.forEach(function (node) { + if (node.nodeType === 1) { + if (node.matches && node.matches('textarea[data-auto-expand="true"]')) { + autoExpandTextarea(node); + } + if (node.querySelectorAll) { + var textareas = node.querySelectorAll('textarea[data-auto-expand="true"]'); + textareas.forEach(autoExpandTextarea); + } + } + }); + }); + }); + observer.observe(formContainer, { childList: true, subtree: true }); +})(); \ No newline at end of file diff --git a/app/eventyay/eventyay_common/templates/eventyay_common/event/settings.html b/app/eventyay/eventyay_common/templates/eventyay_common/event/settings.html index b1fa5959b9..8aee983690 100644 --- a/app/eventyay/eventyay_common/templates/eventyay_common/event/settings.html +++ b/app/eventyay/eventyay_common/templates/eventyay_common/event/settings.html @@ -6,224 +6,227 @@ {% load formset_tags %} {% block title %}{% trans "General settings" %}{% endblock %} {% block custom_header %} - {{ block.super }} - +{{ block.super }} + +{{ sform.media }} {% endblock %} {% block inside %} - + + {% csrf_token %} + {% bootstrap_form_errors form %} + {% bootstrap_form_errors sform %} {# Added to show sform errors #} +
+
+ {% trans "Basics" %} + {% bootstrap_field form.name layout="control" %} + {% bootstrap_field form.slug layout="control" %} + {% if form.domain %} {# Conditionally show if domain field is added to form #} + {% bootstrap_field form.domain layout="control" %} + {% endif %} + {% bootstrap_field form.date_from layout="control" %} + {% bootstrap_field form.date_to layout="control" %} + {% bootstrap_field form.date_admission layout="control" %} + {% include "pretixcontrol/event/fragment_geodata.html" %} + {% bootstrap_field sform.contact_mail layout="control" %} + {% bootstrap_field sform.imprint_url layout="control" %} + {% bootstrap_field form.is_public layout="control" %} +
+
+ +
+ + + + + + +
-
- -
- {% if is_talk_event_created %} - - - - - - - - {% else %} - - {% endif %} -
+
+
+ +
+ {% if is_talk_event_created %} + + + + + + + + {% else %} + + {% endif %}
-
- -
- {% if is_video_enabled %} - - - - - {% else %} - - {% endif %} -
+
+
+ +
+ {% if is_video_enabled %} + + + + + {% else %} + + {% endif %}
-
-
- {% trans "Localization" %} - {% bootstrap_field sform.locales layout="control" %} - {% if sform.content_locales %}{% bootstrap_field sform.content_locales layout="control" %}{% endif %} - {% bootstrap_field sform.locale layout="control" %} - {% bootstrap_field sform.timezone layout="control" %} - {% bootstrap_field sform.region layout="control" %} -
-
- {{ _('Texts') }} - {% bootstrap_field sform.frontpage_text layout="control" %} -
-
- {{ _('Design') }} - {% bootstrap_field sform.event_logo_image layout="control" %} - {% bootstrap_field sform.logo_show_title layout="control" %} - {% bootstrap_field sform.logo_image layout="control" %} - {% bootstrap_field sform.logo_image_large layout="control" %} - {% bootstrap_field sform.og_image layout="control" %} - {% url "control:organizer.edit" organizer=request.organizer.slug as org_url %} - {% propagated request.event org_url "primary_color" "primary_font" "theme_color_success" "theme_color_danger" %} - {% bootstrap_field sform.primary_color layout="control" %} - {% bootstrap_field sform.theme_color_success layout="control" %} - {% bootstrap_field sform.theme_color_danger layout="control" %} - {% bootstrap_field sform.theme_color_background layout="control" %} - {% bootstrap_field sform.hover_button_color layout="control" %} - {% bootstrap_field sform.theme_round_borders layout="control" %} - {% bootstrap_field sform.primary_font layout="control" %} - {% endpropagated %} -
-
-
- -
- -