123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- from django import forms
- from django.db.models import BLANK_CHOICE_DASH
- from django.utils.dateparse import parse_datetime
- from django.utils.text import slugify
- from django.utils.translation import gettext_lazy as _
- from anyascii import anyascii
- from wagtail.blocks import (
- StructBlock,
- TextBlock,
- CharBlock,
- BooleanBlock,
- ListBlock,
- StreamBlock,
- DateBlock,
- TimeBlock,
- DateTimeBlock,
- ChoiceBlock,
- RichTextBlock,
- )
- class FormFieldBlock(StructBlock):
- field_label = CharBlock(label=_("Label"))
- help_text = TextBlock(required=False, label=_("Help text"))
- field_class = forms.CharField
- widget = None
- def get_slug(self, struct_value):
- return slugify(anyascii(struct_value["field_label"]))
- def get_field_class(self, struct_value):
- return self.field_class
- def get_widget(self, struct_value):
- return self.widget
- def get_field_kwargs(self, struct_value):
- kwargs = {
- "label": struct_value["field_label"],
- "help_text": struct_value["help_text"],
- "required": struct_value.get("required", False),
- }
- if "default_value" in struct_value:
- kwargs["initial"] = struct_value["default_value"]
- form_widget = self.get_widget(struct_value)
- if form_widget is not None:
- kwargs["widget"] = form_widget
- return kwargs
- def get_field(self, struct_value):
- return self.get_field_class(struct_value)(
- **self.get_field_kwargs(struct_value)
- )
- class OptionalFormFieldBlock(FormFieldBlock):
- required = BooleanBlock(label=_("Required"), required=False)
- CHARFIELD_FORMATS = [
- ("email", _("Email")),
- ("url", _("URL")),
- ]
- try:
- from phonenumber_field.formfields import PhoneNumberField
- except ImportError:
- pass
- else:
- CHARFIELD_FORMATS.append(("phone", _("Phone")))
- class CharFieldBlock(OptionalFormFieldBlock):
- format = ChoiceBlock(
- choices=CHARFIELD_FORMATS, required=False, label=_("Format")
- )
- default_value = CharBlock(required=False, label=_("Default value"))
- class Meta:
- label = _("Text field (single line)")
- def get_field_class(self, struct_value):
- text_format = struct_value["format"]
- if text_format == "url":
- return forms.URLField
- if text_format == "email":
- return forms.EmailField
- if text_format == "phone":
- return PhoneNumberField
- return super().get_field_class(struct_value)
- class TextFieldBlock(OptionalFormFieldBlock):
- default_value = TextBlock(required=False, label=_("Default value"))
- widget = forms.Textarea(attrs={"rows": 5})
- class Meta:
- label = _("Text field (multi line)")
- class NumberFieldBlock(OptionalFormFieldBlock):
- default_value = CharBlock(required=False, label=_("Default value"))
- widget = forms.NumberInput
- class Meta:
- label = _("Number field")
- class CheckboxFieldBlock(FormFieldBlock):
- default_value = BooleanBlock(required=False)
- field_class = forms.BooleanField
- class Meta:
- label = _("Checkbox field")
- icon = "tick-inverse"
- class RadioButtonsFieldBlock(OptionalFormFieldBlock):
- choices = ListBlock(CharBlock(label=_("Choice")))
- field_class = forms.ChoiceField
- widget = forms.RadioSelect
- class Meta:
- label = _("Radio buttons")
- icon = "radio-empty"
- def get_field_kwargs(self, struct_value):
- kwargs = super().get_field_kwargs(struct_value)
- kwargs["choices"] = [
- (choice, choice) for choice in struct_value["choices"]
- ]
- return kwargs
- class DropdownFieldBlock(RadioButtonsFieldBlock):
- widget = forms.Select
- class Meta:
- label = _("Dropdown field")
- icon = "arrow-down-big"
- def get_field_kwargs(self, struct_value):
- kwargs = super(DropdownFieldBlock, self).get_field_kwargs(struct_value)
- kwargs["choices"].insert(0, BLANK_CHOICE_DASH[0])
- return kwargs
- class CheckboxesFieldBlock(OptionalFormFieldBlock):
- checkboxes = ListBlock(CharBlock(label=_("Checkbox")))
- field_class = forms.MultipleChoiceField
- widget = forms.CheckboxSelectMultiple
- class Meta:
- label = _("Multiple checkboxes field")
- icon = "list-ul"
- def get_field_kwargs(self, struct_value):
- kwargs = super(CheckboxesFieldBlock, self).get_field_kwargs(
- struct_value
- )
- kwargs["choices"] = [
- (choice, choice) for choice in struct_value["checkboxes"]
- ]
- return kwargs
- class DatePickerInput(forms.DateInput):
- def __init__(self, *args, **kwargs):
- attrs = kwargs.get("attrs")
- if attrs is None:
- attrs = {}
- attrs.update(
- {
- "data-provide": "datepicker",
- "data-date-format": "yyyy-mm-dd",
- }
- )
- kwargs["attrs"] = attrs
- super().__init__(*args, **kwargs)
- class DateFieldBlock(OptionalFormFieldBlock):
- default_value = DateBlock(required=False)
- field_class = forms.DateField
- widget = DatePickerInput
- class Meta:
- label = _("Date field")
- icon = "date"
- class HTML5TimeInput(forms.TimeInput):
- input_type = "time"
- class TimeFieldBlock(OptionalFormFieldBlock):
- default_value = TimeBlock(required=False)
- field_class = forms.TimeField
- widget = HTML5TimeInput
- class Meta:
- label = _("Time field")
- icon = "time"
- class DateTimePickerInput(forms.SplitDateTimeWidget):
- def __init__(self, attrs=None, date_format=None, time_format=None):
- super().__init__(
- attrs=attrs, date_format=date_format, time_format=time_format
- )
- self.widgets = (
- DatePickerInput(attrs=attrs, format=date_format),
- HTML5TimeInput(attrs=attrs, format=time_format),
- )
- def decompress(self, value):
- if isinstance(value, str):
- value = parse_datetime(value)
- return super().decompress(value)
- class DateTimeFieldBlock(OptionalFormFieldBlock):
- default_value = DateTimeBlock(required=False)
- field_class = forms.SplitDateTimeField
- widget = DateTimePickerInput
- class Meta:
- label = _("Date+time field")
- icon = "date"
- class ImageFieldBlock(OptionalFormFieldBlock):
- field_class = forms.ImageField
- class Meta:
- label = _("Image field")
- icon = "image"
- class FileFieldBlock(OptionalFormFieldBlock):
- field_class = forms.FileField
- class Meta:
- label = _("File field")
- icon = "download"
- class FormFieldsBlock(StreamBlock):
- char = CharFieldBlock(group=_("Fields"))
- text = TextFieldBlock(group=_("Fields"))
- number = NumberFieldBlock(group=_("Fields"))
- checkbox = CheckboxFieldBlock(group=_("Fields"))
- radios = RadioButtonsFieldBlock(group=_("Fields"))
- dropdown = DropdownFieldBlock(group=_("Fields"))
- checkboxes = CheckboxesFieldBlock(group=_("Fields"))
- date = DateFieldBlock(group=_("Fields"))
- time = TimeFieldBlock(group=_("Fields"))
- datetime = DateTimeFieldBlock(group=_("Fields"))
- image = ImageFieldBlock(group=_("Fields"))
- file = FileFieldBlock(group=_("Fields"))
- text_markup = RichTextBlock(group=_("Other"))
- class Meta:
- label = _("Form fields")
- class FormStepBlock(StructBlock):
- name = CharBlock(label=_("Name"), required=False)
- form_fields = FormFieldsBlock()
- class Meta:
- label = _("Form step")
- class FormStepsBlock(StreamBlock):
- step = FormStepBlock()
- class Meta:
- label = _("Form steps")
|