diff --git a/src/pretix/base/forms/renderers.py b/src/pretix/base/forms/renderers.py new file mode 100644 index 0000000000..2f5030cc7a --- /dev/null +++ b/src/pretix/base/forms/renderers.py @@ -0,0 +1,112 @@ +from bootstrap3.renderers import FieldRenderer +from bootstrap3.text import text_value +from django.forms import CheckboxInput, CheckboxSelectMultiple, RadioSelect +from django.forms.utils import flatatt +from django.utils.html import format_html +from django.utils.safestring import mark_safe +from django.utils.translation import pgettext + + +def render_label(content, label_for=None, label_class=None, label_title='', label_id='', optional=False, is_valid=None, attrs=None): + """ + Render a label with content + """ + attrs = attrs or {} + if label_for: + attrs['for'] = label_for + if label_class: + attrs['class'] = label_class + if label_title: + attrs['title'] = label_title + if label_id: + attrs['id'] = label_id + + opt = "" + + if is_valid is not None: + if is_valid: + validation_text = pgettext('form', 'is valid') + else: + validation_text = pgettext('form', 'has errors') + opt += ' {}'.format(validation_text) + + if text_value(content) == ' ': + # Empty label, e.g. checkbox + attrs.setdefault('class', '') + attrs['class'] += ' label-empty' + # usually checkboxes have overall empty labels and special labels per checkbox + # => remove for-attribute as well as "required"-text appended to label + if 'for' in attrs: + del attrs['for'] + else: + opt += ', {}'.format(pgettext('form', 'required')) if not optional else '' + + builder = '<{tag}{attrs}>{content}{opt}' + return format_html( + builder, + tag='label', + attrs=mark_safe(flatatt(attrs)) if attrs else '', + opt=mark_safe(opt), + content=text_value(content), + ) + + +class PretixFieldRenderer(FieldRenderer): + def __init__(self, *args, **kwargs): + kwargs['layout'] = 'horizontal' + super().__init__(*args, **kwargs) + self.is_group_widget = isinstance(self.widget, (CheckboxSelectMultiple, RadioSelect, )) or (self.is_multi_widget and len(self.widget.widgets) > 1) + + def add_label(self, html): + attrs = {} + label = self.get_label() + + if hasattr(self.field.field, '_show_required'): + # e.g. payment settings forms where a field is only required if the payment provider is active + required = self.field.field._show_required + elif hasattr(self.field.field, '_required'): + # e.g. payment settings forms where a field is only required if the payment provider is active + required = self.field.field._required + else: + required = self.field.field.required + + if self.field.form.is_bound: + is_valid = len(self.field.errors) == 0 + else: + is_valid = None + + if self.is_group_widget: + label_for = "" + label_id = "legend-{}".format(self.field.html_name) + else: + label_for = self.field.id_for_label + label_id = "" + + if hasattr(self.field.field, 'question') and self.field.field.question.identifier: + attrs["data-identifier"] = self.field.field.question.identifier + + html = render_label( + label, + label_for=label_for, + label_class=self.get_label_class(), + label_id=label_id, + attrs=attrs, + optional=not required and not isinstance(self.widget, CheckboxInput), + is_valid=is_valid + ) + html + return html + + def wrap_label_and_field(self, html): + if self.is_group_widget: + attrs = ' role="group" aria-labelledby="legend-{}"'.format(self.field.html_name) + else: + attrs = '' + return '
{html}
'.format(klass=self.get_form_group_class(), html=html, attrs=attrs) + + def wrap_widget(self, html): + if isinstance(self.widget, CheckboxInput): + css_class = "checkbox" + if self.field.field.disabled: + css_class += " disabled" + html = f'
{html}
' + return html diff --git a/src/pretix/control/forms/renderers.py b/src/pretix/control/forms/renderers.py index 786a060d49..c81ac40e42 100644 --- a/src/pretix/control/forms/renderers.py +++ b/src/pretix/control/forms/renderers.py @@ -21,90 +21,16 @@ # from bootstrap3.renderers import FieldRenderer, InlineFieldRenderer from bootstrap3.text import text_value -from django.forms import CheckboxInput, CheckboxSelectMultiple, RadioSelect from django.forms.utils import flatatt from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import pgettext -from i18nfield.forms import I18nFormField + +from pretix.base.forms.renderers import PretixFieldRenderer -def render_label(content, label_for=None, label_class=None, label_title='', label_id='', optional=False): - """ - Render a label with content - """ - attrs = {} - if label_for: - attrs['for'] = label_for - if label_class: - attrs['class'] = label_class - if label_title: - attrs['title'] = label_title - if label_id: - attrs['id'] = label_id - - if text_value(content) == ' ': - # Empty label, e.g. checkbox - attrs.setdefault('class', '') - attrs['class'] += ' label-empty' - - builder = '<{tag}{attrs}>{content}{opt}' - return format_html( - builder, - tag='label', - attrs=mark_safe(flatatt(attrs)) if attrs else '', - opt=mark_safe('
{}'.format(pgettext('form', 'Optional'))) if optional else '', - content=text_value(content), - ) - - -class ControlFieldRenderer(FieldRenderer): - def __init__(self, *args, **kwargs): - kwargs['layout'] = 'horizontal' - super().__init__(*args, **kwargs) - self.is_group_widget = isinstance(self.widget, (CheckboxSelectMultiple, RadioSelect, )) or (self.is_multi_widget and len(self.widget.widgets) > 1) - - def add_label(self, html): - label = self.get_label() - - if hasattr(self.field.field, '_required'): - # e.g. payment settings forms where a field is only required if the payment provider is active - required = self.field.field._required - elif isinstance(self.field.field, I18nFormField): - required = self.field.field.one_required - else: - required = self.field.field.required - - if self.is_group_widget: - label_for = "" - label_id = "legend-{}".format(self.field.html_name) - else: - label_for = self.field.id_for_label - label_id = "" - - html = render_label( - label, - label_for=label_for, - label_class=self.get_label_class(), - label_id=label_id, - optional=not required and not isinstance(self.widget, CheckboxInput) - ) + html - return html - - def wrap_label_and_field(self, html): - if self.is_group_widget: - attrs = ' role="group" aria-labelledby="legend-{}"'.format(self.field.html_name) - else: - attrs = '' - return '
{html}
'.format(klass=self.get_form_group_class(), html=html, attrs=attrs) - - def wrap_widget(self, html): - if isinstance(self.widget, CheckboxInput): - css_class = "checkbox" - if self.field.field.disabled: - css_class += " disabled" - html = f'
{html}
' - return html +class ControlFieldRenderer(PretixFieldRenderer): + pass class ControlFieldWithVisibilityRenderer(ControlFieldRenderer): diff --git a/src/pretix/presale/forms/renderers.py b/src/pretix/presale/forms/renderers.py index 891f240420..bed20d0242 100644 --- a/src/pretix/presale/forms/renderers.py +++ b/src/pretix/presale/forms/renderers.py @@ -19,66 +19,14 @@ # You should have received a copy of the GNU Affero General Public License along with this program. If not, see # . # -from bootstrap3.renderers import FieldRenderer -from bootstrap3.text import text_value from bootstrap3.utils import add_css_class -from django.forms import CheckboxInput, CheckboxSelectMultiple, RadioSelect -from django.forms.utils import flatatt -from django.utils.html import escape, format_html, strip_tags +from django.utils.html import escape, strip_tags from django.utils.safestring import mark_safe -from django.utils.translation import pgettext + +from pretix.base.forms.renderers import PretixFieldRenderer -def render_label(content, label_for=None, label_class=None, label_title='', label_id='', optional=False, is_valid=None, attrs=None): - """ - Render a label with content - """ - attrs = attrs or {} - if label_for: - attrs['for'] = label_for - if label_class: - attrs['class'] = label_class - if label_title: - attrs['title'] = label_title - if label_id: - attrs['id'] = label_id - - opt = "" - - if is_valid is not None: - if is_valid: - validation_text = pgettext('form', 'is valid') - else: - validation_text = pgettext('form', 'has errors') - opt += ' {}'.format(validation_text) - - if text_value(content) == ' ': - # Empty label, e.g. checkbox - attrs.setdefault('class', '') - attrs['class'] += ' label-empty' - # usually checkboxes have overall empty labels and special labels per checkbox - # => remove for-attribute as well as "required"-text appended to label - if 'for' in attrs: - del attrs['for'] - else: - opt += ', {}'.format(pgettext('form', 'required')) if not optional else '' - - builder = '<{tag}{attrs}>{content}{opt}' - return format_html( - builder, - tag='label', - attrs=mark_safe(flatatt(attrs)) if attrs else '', - opt=mark_safe(opt), - content=text_value(content), - ) - - -class CheckoutFieldRenderer(FieldRenderer): - def __init__(self, *args, **kwargs): - kwargs['layout'] = 'horizontal' - super().__init__(*args, **kwargs) - self.is_group_widget = isinstance(self.widget, (CheckboxSelectMultiple, RadioSelect, )) or (self.is_multi_widget and len(self.widget.widgets) > 1) - +class CheckoutFieldRenderer(PretixFieldRenderer): def get_form_group_class(self): form_group_class = self.form_group_class if self.field.errors: @@ -121,45 +69,6 @@ class CheckoutFieldRenderer(FieldRenderer): help_ids = ["help-for-{id}-{idx}".format(id=self.field.id_for_label, idx=idx) for idx in range(help_cnt)] widget.attrs["aria-describedby"] = " ".join(help_ids) - def add_label(self, html): - attrs = {} - label = self.get_label() - - if hasattr(self.field.field, '_show_required'): - # e.g. payment settings forms where a field is only required if the payment provider is active - required = self.field.field._show_required - elif hasattr(self.field.field, '_required'): - # e.g. payment settings forms where a field is only required if the payment provider is active - required = self.field.field._required - else: - required = self.field.field.required - - if self.field.form.is_bound: - is_valid = len(self.field.errors) == 0 - else: - is_valid = None - - if self.is_group_widget: - label_for = "" - label_id = "legend-{}".format(self.field.html_name) - else: - label_for = self.field.id_for_label - label_id = "" - - if hasattr(self.field.field, 'question') and self.field.field.question.identifier: - attrs["data-identifier"] = self.field.field.question.identifier - - html = render_label( - label, - label_for=label_for, - label_class=self.get_label_class(), - label_id=label_id, - attrs=attrs, - optional=not required and not isinstance(self.widget, CheckboxInput), - is_valid=is_valid - ) + html - return html - def put_inside_label(self, html): content = "{field} {label}".format(field=html, label=self.label) return render_label( @@ -167,18 +76,3 @@ class CheckoutFieldRenderer(FieldRenderer): label_for=self.field.id_for_label, label_title=escape(strip_tags(self.field_help)), ) - - def wrap_label_and_field(self, html): - if self.is_group_widget: - attrs = ' role="group" aria-labelledby="legend-{}"'.format(self.field.html_name) - else: - attrs = '' - return '
{html}
'.format(klass=self.get_form_group_class(), html=html, attrs=attrs) - - def wrap_widget(self, html): - if isinstance(self.widget, CheckboxInput): - css_class = "checkbox" - if self.field.field.disabled: - css_class += " disabled" - html = f'
{html}
' - return html