FormFields: remove placeholders duplicating labels (#5135)

This commit is contained in:
Richard Schreiber
2025-07-10 16:06:36 +02:00
committed by GitHub
parent 415bff5c72
commit 14d6013292
17 changed files with 52 additions and 51 deletions

View File

@@ -28,6 +28,9 @@ from dateutil import parser
from django import forms
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.formats import get_format
from django.utils.functional import lazy
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
@@ -206,14 +209,27 @@ class RelativeDateTimeWidget(forms.MultiWidget):
def __init__(self, *args, **kwargs):
self.status_choices = kwargs.pop('status_choices')
base_choices = kwargs.pop('base_choices')
def placeholder_datetime_format():
df = get_format('DATETIME_INPUT_FORMATS')[0]
return now().replace(
year=2000, month=12, day=31, hour=18, minute=0, second=0, microsecond=0
).strftime(df)
def placeholder_time_format():
tf = get_format('TIME_INPUT_FORMATS')[0]
return datetime.time(8, 30, 0).strftime(tf)
widgets = reldatetimeparts(
status=forms.RadioSelect(choices=self.status_choices),
absolute=forms.DateTimeInput(
attrs={'class': 'datetimepicker'}
attrs={'placeholder': lazy(placeholder_datetime_format, str), 'class': 'datetimepicker'}
),
rel_days_number=forms.NumberInput(),
rel_mins_relationto=forms.Select(choices=base_choices),
rel_days_timeofday=forms.TimeInput(attrs={'placeholder': _('Time'), 'class': 'timepickerfield'}),
rel_days_timeofday=forms.TimeInput(
attrs={'placeholder': lazy(placeholder_time_format, str), 'class': 'timepickerfield'}
),
rel_mins_number=forms.NumberInput(),
rel_days_relationto=forms.Select(choices=base_choices),
rel_mins_relation=forms.Select(choices=BEFORE_AFTER_CHOICE),

View File

@@ -113,7 +113,6 @@ class EventWizardFoundationForm(forms.Form):
attrs={
'data-model-select2': 'generic',
'data-select2-url': reverse('control:organizers.select2') + '?can_create=1',
'data-placeholder': _('Organizer')
}
),
empty_label=None,

View File

@@ -1246,9 +1246,7 @@ class SubEventFilterForm(FilterForm):
)
query = forms.CharField(
label=_('Event name'),
widget=forms.TextInput(attrs={
'placeholder': _('Event name'),
}),
widget=forms.TextInput(),
required=False
)
@@ -1693,9 +1691,7 @@ class EventFilterForm(FilterForm):
)
query = forms.CharField(
label=_('Event name'),
widget=forms.TextInput(attrs={
'placeholder': _('Event name'),
}),
widget=forms.TextInput(),
required=False
)
date_from = forms.DateField(
@@ -2448,7 +2444,7 @@ class CheckinFilterForm(FilterForm):
'event': self.event.slug,
'organizer': self.event.organizer.slug,
}),
'data-placeholder': _('Check-in list'),
'data-placeholder': _('All check-in lists'),
}
)
self.fields['checkin_list'].widget.choices = self.fields['checkin_list'].choices

View File

@@ -47,9 +47,7 @@ from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe
from django.utils.translation import (
gettext as __, gettext_lazy as _, pgettext_lazy,
)
from django.utils.translation import gettext as __, gettext_lazy as _
from django_scopes.forms import (
SafeModelChoiceField, SafeModelMultipleChoiceField,
)
@@ -330,7 +328,6 @@ class QuotaForm(I18nModelForm):
'event': self.event.slug,
'organizer': self.event.organizer.slug,
}),
'data-placeholder': pgettext_lazy('subevent', 'Date')
}
)
self.fields['subevent'].widget.choices = self.fields['subevent'].choices
@@ -352,6 +349,9 @@ class QuotaForm(I18nModelForm):
field_classes = {
'subevent': SafeModelChoiceField,
}
widgets = {
'size': forms.NumberInput(attrs={'placeholder': _('Unlimited')})
}
def save(self, *args, **kwargs):
creating = not self.instance.pk

View File

@@ -409,7 +409,6 @@ class OrderPositionAddForm(forms.Form):
'event': order.event.slug,
'organizer': order.event.organizer.slug,
}),
'data-placeholder': pgettext_lazy('subevent', 'Date')
}
)
self.fields['subevent'].widget.choices = self.fields['subevent'].choices
@@ -705,7 +704,6 @@ class OrderContactForm(forms.ModelForm):
'data-select2-url': reverse('control:organizer.customers.select2', kwargs={
'organizer': self.instance.event.organizer.slug,
}),
'data-placeholder': _('Customer')
}
)
self.fields['customer'].widget.choices = self.fields['customer'].choices

View File

@@ -781,7 +781,6 @@ class GiftCardUpdateForm(forms.ModelForm):
'data-select2-url': reverse('control:organizer.ticket_select2', kwargs={
'organizer': organizer.slug,
}),
'data-placeholder': _('Ticket')
}
)
self.fields['owner_ticket'].widget.choices = self.fields['owner_ticket'].choices
@@ -817,7 +816,6 @@ class ReusableMediumUpdateForm(forms.ModelForm):
'data-select2-url': reverse('control:organizer.ticket_select2', kwargs={
'organizer': organizer.slug,
}),
'data-placeholder': _('Ticket')
}
)
self.fields['linked_orderposition'].widget.choices = self.fields['linked_orderposition'].choices
@@ -830,7 +828,6 @@ class ReusableMediumUpdateForm(forms.ModelForm):
'data-select2-url': reverse('control:organizer.giftcards.select2', kwargs={
'organizer': organizer.slug,
}),
'data-placeholder': _('Gift card')
}
)
self.fields['linked_giftcard'].widget.choices = self.fields['linked_giftcard'].choices
@@ -844,7 +841,6 @@ class ReusableMediumUpdateForm(forms.ModelForm):
'data-select2-url': reverse('control:organizer.customers.select2', kwargs={
'organizer': organizer.slug,
}),
'data-placeholder': _('Customer')
}
)
self.fields['customer'].widget.choices = self.fields['customer'].choices

View File

@@ -133,16 +133,12 @@ class SubEventBulkEditForm(I18nModelForm):
# i18n fields
if k in self.mixed_values:
self.fields[k].widget.attrs['placeholder'] = '[{}]'.format(_('Selection contains various values'))
else:
self.fields[k].widget.attrs['placeholder'] = ''
self.fields[k].one_required = False
for k in ('geo_lat', 'geo_lon', 'comment'):
# scalar fields
if k in self.mixed_values:
self.fields[k].widget.attrs['placeholder'] = '[{}]'.format(_('Selection contains various values'))
else:
self.fields[k].widget.attrs['placeholder'] = ''
self.fields[k].widget.is_required = False
self.fields[k].required = False

View File

@@ -41,7 +41,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.validators import EmailValidator
from django.db.models.functions import Upper
from django.urls import reverse
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django.utils.translation import gettext_lazy as _
from django_scopes.forms import SafeModelChoiceField
from pretix.base.email import get_available_placeholders
@@ -115,7 +115,6 @@ class VoucherForm(I18nModelForm):
'event': instance.event.slug,
'organizer': instance.event.organizer.slug,
}),
'data-placeholder': pgettext_lazy('subevent', 'Date')
}
)
self.fields['subevent'].widget.choices = self.fields['subevent'].choices

View File

@@ -15,7 +15,7 @@
<span class="optional">{% trans "Optional" %}</span>
</label>
<div class="col-md-4">
{% bootstrap_field form.geo_lat layout="inline" %}
{% bootstrap_field form.geo_lat layout="inline" placeholder=_("Latitude") %}
{% if global_settings.opencagedata_apikey %}
<p class="attrib">
<a href="https://openstreetmap.org/" target="_blank">
@@ -25,7 +25,7 @@
{% endif %}
</div>
<div class="col-md-4">
{% bootstrap_field form.geo_lon layout="inline" %}
{% bootstrap_field form.geo_lon layout="inline" placeholder=_("Longitude") %}
</div>
<div class="col-md-1">
</div>

View File

@@ -289,13 +289,13 @@
{% bootstrap_field f.DELETE form_group_class="" layout="inline" %}
</div>
<div class="col-sm-4">
{% bootstrap_field f.time_from layout="inline" %}
{% bootstrap_field f.time_from layout="inline" placeholder=time_begin_sample %}
</div>
<div class="col-sm-4">
{% bootstrap_field f.time_to layout="inline" %}
{% bootstrap_field f.time_to layout="inline" placeholder=time_end_sample %}
</div>
<div class="col-sm-3">
{% bootstrap_field f.time_admission layout="inline" %}
{% bootstrap_field f.time_admission layout="inline" placeholder=time_admission_sample %}
</div>
<div class="col-sm-1 text-right flip">
<button type="button" class="btn btn-danger btn-block"
@@ -315,13 +315,13 @@
{% bootstrap_field time_formset.empty_form.DELETE form_group_class="" layout="inline" %}
</div>
<div class="col-sm-4">
{% bootstrap_field time_formset.empty_form.time_from layout="inline" %}
{% bootstrap_field time_formset.empty_form.time_from layout="inline" placeholder=time_begin_sample %}
</div>
<div class="col-sm-4">
{% bootstrap_field time_formset.empty_form.time_to layout="inline" %}
{% bootstrap_field time_formset.empty_form.time_to layout="inline" placeholder=time_end_sample %}
</div>
<div class="col-sm-3">
{% bootstrap_field time_formset.empty_form.time_admission layout="inline" %}
{% bootstrap_field time_formset.empty_form.time_admission layout="inline" placeholder=time_admission_sample %}
</div>
<div class="col-sm-1 text-right flip">
<button type="button" class="btn btn-danger btn-block"
@@ -338,13 +338,13 @@
<label for="subevent_add_many_slots_first">
<strong>{% trans "Start of first slot" %}</strong>
</label>
<input class="form-control timepickerfield" id="subevent_add_many_slots_first" value="{{ time_begin_sample }}">
<input class="form-control timepickerfield" id="subevent_add_many_slots_first" value="{{ time_begin_sample }}" placeholder="{{ time_begin_sample }}">
</div>
<div class="col-md-2 col-sm-12">
<label for="subevent_add_many_slots_end">
<strong>{% trans "End of time slots" %}</strong>
</label>
<input class="form-control timepickerfield" id="subevent_add_many_slots_end" value="{{ time_end_sample }}">
<input class="form-control timepickerfield" id="subevent_add_many_slots_end" value="{{ time_end_sample }}" placeholder="{{ time_end_sample }}">
</div>
<div class="col-md-3 col-sm-12">
<label for="subevent_add_many_slots_length">
@@ -409,8 +409,8 @@
</fieldset>
<fieldset>
<legend>{% trans "Timeline" %}</legend>
{% bootstrap_field form.rel_presale_start layout="control" %}
{% bootstrap_field form.rel_presale_end layout="control" %}
{% bootstrap_field form.rel_presale_start layout="control" placeholder=datetime_sample %}
{% bootstrap_field form.rel_presale_end layout="control" placeholder=datetime_sample %}
</fieldset>
<fieldset>
<legend>{% trans "Quotas" %}</legend>

View File

@@ -51,7 +51,7 @@
<div class="field-content">
<div class="row">
<div class="col-md-6">
{% bootstrap_field form.geo_lat layout="inline" %}
{% bootstrap_field form.geo_lat layout="inline" placeholder=_("Latitude") %}
{% if global_settings.opencagedata_apikey %}
<p class="attrib">
<a href="https://openstreetmap.org/" target="_blank" tabindex="-1">
@@ -61,7 +61,7 @@
{% endif %}
</div>
<div class="col-md-6">
{% bootstrap_field form.geo_lon layout="inline" %}
{% bootstrap_field form.geo_lon layout="inline" placeholder=_("Longitude") %}
</div>
</div>
</div>

View File

@@ -49,7 +49,7 @@ from django.shortcuts import redirect, render
from django.urls import reverse
from django.utils.formats import get_format
from django.utils.functional import cached_property
from django.utils.timezone import make_aware
from django.utils.timezone import make_aware, now
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django.views import View
from django.views.generic import CreateView, FormView, ListView, UpdateView
@@ -768,8 +768,15 @@ class SubEventBulkCreate(SubEventEditorMixin, EventPermissionRequiredMixin, Asyn
ctx['time_formset'] = self.time_formset
tf = get_format('TIME_INPUT_FORMATS')[0]
ctx['time_admission_sample'] = time(8, 30, 0).strftime(tf)
ctx['time_begin_sample'] = time(9, 0, 0).strftime(tf)
ctx['time_end_sample'] = time(18, 0, 0).strftime(tf)
df = get_format('DATETIME_INPUT_FORMATS')[0]
ctx['datetime_sample'] = now().replace(
year=2000, month=12, day=31, hour=18, minute=0, second=0, microsecond=0
).strftime(df)
return ctx
@cached_property

View File

@@ -176,7 +176,6 @@ class AutoCheckinRuleForm(forms.ModelForm):
"organizer": self.event.organizer.slug,
},
),
"data-placeholder": _("Check-in list"),
}
)
self.fields["list"].widget.choices = self.fields["list"].choices

View File

@@ -2,7 +2,7 @@
{% load ibanformat %}
{% load bootstrap3 %}
{% bootstrap_field form.payer layout="inline" %}
{% bootstrap_field form.iban layout="inline" %}
{% bootstrap_field form.bic layout="inline" %}
{% bootstrap_field form.payer layout="inline" placeholder=_("Account holder") %}
{% bootstrap_field form.iban layout="inline" placeholder=_("IBAN") %}
{% bootstrap_field form.bic layout="inline" placeholder=_("BIC (optional)") %}
{% bootstrap_form_errors form error_types="all" %}

View File

@@ -279,7 +279,6 @@ class OrderMailForm(BaseMailForm):
'event': event.slug,
'organizer': event.organizer.slug,
}),
'data-placeholder': pgettext_lazy('subevent', 'Date')
}
)
self.fields['subevent'].widget.choices = self.fields['subevent'].choices
@@ -360,7 +359,6 @@ class RuleForm(FormPlaceholderMixin, I18nModelForm):
'event': self.event.slug,
'organizer': self.event.organizer.slug,
}),
'data-placeholder': pgettext_lazy('subevent', 'Date')
}
)
self.fields['subevent'].widget.choices = self.fields['subevent'].choices

View File

@@ -711,6 +711,7 @@ BOOTSTRAP3 = {
'bulkedit_inline': 'pretix.control.forms.renderers.InlineBulkEditFieldRenderer',
'checkout': 'pretix.presale.forms.renderers.CheckoutFieldRenderer',
},
'set_placeholder': False,
}
PASSWORD_HASHERS = [

View File

@@ -34,10 +34,6 @@ footer {
margin: auto;
padding-bottom: 0;
.control-label {
display: none;
}
.buttons {
text-align: right;
}