class MarkerForm(EntangledModelForm): title = CharField( label=_("Marker Title"), widget=widgets.TextInput(attrs={'size': 60}), help_text=_( "Please choose a title, then go to the map to set a marker pin")) use_icon = BooleanField( label=_("Use customized marker icon"), initial=False, required=False, ) marker_image = AdminImageFormField( ManyToOneRel(FilerImageField, Image, 'file_ptr'), Image.objects.all(), label=_("Marker Image"), required=False, to_field_name='image_file', ) marker_width = SizeField( label=_("Marker Width"), allowed_units=['px'], required=False, help_text=_("Width of the marker icon in pixels."), ) marker_anchor = MultiSizeField( ['left', 'top'], label=_("Marker Anchor"), allowed_units=['px', '%'], required=False, help_text= _("The coordinates of the icon's anchor (relative to its top left corner)." ), ) popup_text = HTMLFormField( required=False, help_text=_("Optional rich text to display in popup."), ) position = HiddenDictField() class Meta: entangled_fields = { 'glossary': [ 'title', 'use_icon', 'marker_image', 'marker_width', 'marker_anchor', 'popup_text', 'position' ] } def clean(self): cleaned_data = super().clean() try: position = cleaned_data['position'] if isinstance(position, str): position = json.loads(position) elif not isinstance(position, dict): raise ValueError except (ValueError, KeyError): raise ValidationError( "Invalid internal position data. Check your Javascript imports." ) else: if 'lat' not in position or 'lng' not in position: # place the marker in the center of the current map position = { k: v for k, v in self.instance.cascade_element. glossary['map_position'].items() if k in ['lat', 'lng'] } cleaned_data['position'] = position popup_text = cleaned_data.pop('popup_text', '') if strip_tags(popup_text): cleaned_data['popup_text'] = strip_spaces_between_tags(popup_text) 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
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'] background_color = ColorField(label=_("Background color"), ) background_repeat = ChoiceField( label=_("Background repeat"), choices=[(c, c) for c in REPEAT_CHOICES], widget=widgets.RadioSelect, initial='no-repeat', help_text=_("This property specifies how an image repeates."), ) background_attachment = ChoiceField( label=_("Background attachment"), choices=[(c, c) for c in ATTACHMENT_CHOICES], widget=widgets.RadioSelect, initial='local', help_text= _("This property specifies how to move the background relative to the viewport." ), ) background_vertical_position = ChoiceField( label=_("Background vertical position"), choices=[(c, c) for c in VERTICAL_POSITION_CHOICES], initial='center', 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', 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', help_text=_("This property specifies how an 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': [ 'background_color', 'background_repeat', 'background_attachment', 'background_vertical_position', 'background_horizontal_position', 'background_size', 'background_width_height' ] } def clean(self): cleaned_data = super().clean() if cleaned_data['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