class ImageFormMixin(EntangledModelFormMixin): image_file = CascadeImageField() image_title = CharField( label=_('Image Title'), required=False, help_text=_( "Caption text added to the 'title' attribute of the <img> element." ), ) alt_tag = CharField( label=_('Alternative Description'), required=False, help_text= _("Textual description of the image added to the 'alt' tag of the <img> element." ), ) _image_properties = EntangledField() class Meta: entangled_fields = { 'glossary': ['image_file', 'image_title', 'alt_tag', '_image_properties'] } def __init__(self, *args, **kwargs): if not getattr(self, 'require_image', True): self.base_fields['image_file'].required = False super().__init__(*args, **kwargs) def clean_image_file(self): image_file = self.cleaned_data['image_file'] # _image_properties are just a cached representation, maybe useless if image_file: self.cleaned_data['_image_properties'] = { 'width': image_file._width, 'height': image_file._height, 'exif_orientation': image_file.exif.get('Orientation', 1), } return image_file
class ImageFormMixin(EntangledModelFormMixin): image_file = CascadeImageField() image_title = CharField( label=_('Image Title'), required=False, help_text=_( "Caption text added to the 'title' attribute of the <img> element." ), ) alt_tag = CharField( label=_('Alternative Description'), required=False, help_text= _("Textual description of the image added to the 'alt' tag of the <img> element." ), ) _image_properties = EntangledField() class Meta: entangled_fields = { 'glossary': ['image_file', 'image_title', 'alt_tag', '_image_properties'] } def clean(self): cleaned_data = super().clean() image_file = cleaned_data.get('image_file') if not image_file: raise ValidationError(_("No image has been selected.")) # _image_properties are just a cached representation, maybe useless cleaned_data['_image_properties'] = { 'width': image_file._width, 'height': image_file._height, 'exif_orientation': image_file.exif.get('Orientation', 1), } return cleaned_data
class JumbotronFormMixin(EntangledModelFormMixin): """ Form class to validate the JumbotronPlugin. """ ATTACHMENT_CHOICES = ['scroll', 'fixed', 'local'] VERTICAL_POSITION_CHOICES = ['top', '10%', '20%', '30%', '40%', 'center', '60%', '70%', '80%', '90%', 'bottom'] HORIZONTAL_POSITION_CHOICES = ['left', '10%', '20%', '30%', '40%', 'center', '60%', '70%', '80%', '90%', 'right'] REPEAT_CHOICES = ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'] SIZE_CHOICES = ['auto', 'width/height', 'cover', 'contain'] fluid = BooleanField( label=_("Is fluid"), initial=True, required=False, help_text=_("Shall this element occupy the entire horizontal space of its parent."), ) element_heights = BootstrapMultiSizeField( label=("Element Heights"), required=True, allowed_units=['rem', 'px', 'auto'], initial='300px', help_text=_("This property specifies the height for each Bootstrap breakpoint."), ) background_color = ColorField( label=_("Background color"), ) image_file = CascadeImageField( label=_("Background image"), required=False, ) background_repeat = ChoiceField( label=_("Background repeat"), choices=[(c, c) for c in REPEAT_CHOICES], widget=widgets.RadioSelect, initial='no-repeat', required=False, help_text=_("This property specifies how the background image repeates."), ) background_attachment = ChoiceField( label=_("Background attachment"), choices=[(c, c) for c in ATTACHMENT_CHOICES], widget=widgets.RadioSelect, initial='local', required=False, help_text=_("This property specifies how to move the background image relative to the viewport."), ) background_vertical_position = ChoiceField( label=_("Background vertical position"), choices=[(c, c) for c in VERTICAL_POSITION_CHOICES], initial='center', required=False, help_text=_("This property moves a background image vertically within its container."), ) background_horizontal_position = ChoiceField( label=_("Background horizontal position"), choices=[(c, c) for c in HORIZONTAL_POSITION_CHOICES], initial='center', required=False, help_text=_("This property moves a background image horizontally within its container."), ) background_size = ChoiceField( label=_("Background size"), choices=[(c, c) for c in SIZE_CHOICES], widget=widgets.RadioSelect, initial='auto', required=False, help_text=_("This property specifies how the background image is sized."), ) background_width_height = MultiSizeField( ['width', 'height'], label=_("Background width/height"), allowed_units=['px', '%'], required=False, help_text=_("This property specifies the width and height of a background image in px or %."), ) class Meta: entangled_fields = {'glossary': ['fluid', 'background_color', 'element_heights', 'image_file', 'background_repeat', 'background_attachment', 'background_vertical_position', 'background_horizontal_position', 'background_size', 'background_width_height']} def validate_optional_field(self, name): field = self.fields[name] value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) if value in field.empty_values: self.add_error(name, ValidationError(field.error_messages['required'], code='required')) else: return value def clean(self): cleaned_data = super().clean() if cleaned_data['image_file']: self.validate_optional_field('background_repeat') self.validate_optional_field('background_attachment') self.validate_optional_field('background_vertical_position') self.validate_optional_field('background_horizontal_position') if self.validate_optional_field('background_size') == 'width/height': try: cleaned_data['background_width_height']['width'] except KeyError: msg = _("You must at least set a background width.") self.add_error('background_width_height', msg) raise ValidationError(msg) return cleaned_data