Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/eventyay/base/configurations/default_setting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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': '',
Expand Down
35 changes: 25 additions & 10 deletions app/eventyay/base/forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,42 +165,57 @@ def format_output(self, rendered_widgets, id_) -> str:
)
rendered_widgets.append(f'<div class="i18n-field-markdown-note">{markdown_note}</div>')
return super().format_output(rendered_widgets, id_)



Comment on lines +168 to +169
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected on this line. According to PEP 8 style guidelines, lines should not have trailing whitespace. Remove the trailing spaces from this line.

Suggested change

Copilot uses AI. Check for mistakes.
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: 80px; max-height: 300px; overflow-y: auto; resize: vertical; transition: height 0.2s ease-in-out;'
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default style includes overflow-y: auto which conflicts with the dynamic overflow management in the JavaScript. The JavaScript sets overflowY to either 'auto' or 'hidden' based on content height (line 20 of auto-expanding-textarea.js), but the initial overflow-y: auto means scrollbars will be visible before the JavaScript initializes or when content is below the max height.

Consider changing overflow-y: auto to overflow-y: hidden in the default style:

'style': 'min-height: 80px; max-height: 300px; overflow-y: hidden; resize: vertical; transition: height 0.2s ease-in-out;'

This will prevent unnecessary scrollbars from appearing initially and let the JavaScript control the overflow behavior.

Suggested change
'style': 'min-height: 80px; max-height: 300px; overflow-y: auto; resize: vertical; transition: height 0.2s ease-in-out;'
'style': 'min-height: 80px; max-height: 300px; overflow-y: hidden; resize: vertical; transition: height 0.2s ease-in-out;'

Copilot uses AI. Check for mistakes.
}
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',)


Comment on lines +191 to 192
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected on this line. According to PEP 8 style guidelines, lines should not have trailing whitespace. Remove the trailing spaces from this line.

Suggested change

Copilot uses AI. Check for mistakes.
class I18nURLFormField(i18nfield.forms.I18nFormField):
"""
Custom form field to handle internationalized URL inputs. It extends the I18nFormField
and ensures that all provided URLs are valid.

Methods:
clean(value: LazyI18nString) -> LazyI18nString:
Validates the URL(s) in the provided internationalized input.
"""

def clean(self, value) -> LazyI18nString:
"""
Cleans and validates the internationalized URL input.

Args:
value (LazyI18nString): The input value to clean and validate.

Returns:
LazyI18nString: The cleaned and validated input value.

Raises:
ValidationError: If any of the URLs are invalid.
"""
value = super().clean(value)
if not value:
return value

url_validator = URLValidator()

if isinstance(value.data, dict):
for val in value.data.values():
if val:
url_validator(val)
else:
url_validator(value.data)

return value
return value
Comment on lines 193 to +221
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Blank lines have been removed from the docstring of the I18nURLFormField class. These formatting changes appear to be unintentional as they're unrelated to the auto-expanding textarea feature being added. The removed blank lines served to improve readability by separating sections of the docstring.

Consider restoring the original formatting of this docstring to keep changes focused on the feature being implemented.

Copilot uses AI. Check for mistakes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
(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';
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';
Comment on lines +15 to +20
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The height adjustment logic has a potential race condition. When setting textarea.style.height = 'auto' on line 14, the scrollHeight used on line 18 might not reflect the correct content height if the browser hasn't finished reflow. This could lead to incorrect height calculations, especially on slower devices or with large amounts of text.

Consider using requestAnimationFrame to ensure the DOM has been updated before reading scrollHeight:

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';
    });
}
Suggested change
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';
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';
});

Copilot uses AI. Check for mistakes.
}

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 });
})();
Loading