class ImageTextItem(ContentItem): """ A block with image + text """ ALIGN_LEFT = 'left' ALIGN_RIGHT = 'right' ALIGN_CHOICES = ( (ALIGN_LEFT, _("Left")), (ALIGN_RIGHT, _("Right")), ) title = models.CharField(_("Title"), max_length=200) image = PluginImageField(_("Image")) align = models.CharField(_("Align"), max_length=10, choices=ALIGN_CHOICES, default=ALIGN_LEFT) body = PluginHtmlField(_("Body")) url = PluginUrlField(_("URL"), blank=True) url_text = models.CharField(_("Text"), max_length=200, blank=True) class Meta: verbose_name = _("Image+text") verbose_name_plural = _("Image+text items") def __str__(self): return self.title @property def image_css_class(self): if self.align == self.ALIGN_RIGHT: return 'image_fr' else: return 'image_fl'
class ExcerptImageEntryMixin(models.Model): """ Optional Mixin for adding an excerpt image to a blog entry. """ excerpt_image = PluginImageField(_("Intro image")) class Meta: abstract = True
class Marker(CachedModelMixin, models.Model): """ A single point on the map """ title = models.CharField(_("Title"), max_length=200) image = PluginImageField(_("Image"), blank=True) description = PluginHtmlField(_("Description"), blank=True) group = models.ForeignKey(MarkerGroup, related_name='markers', verbose_name=_("Group"), blank=True, null=True) location = GeopositionField(_("Location")) # TODO: use different package? class Meta: verbose_name = _("Marker") verbose_name_plural = _("Markers") ordering = ('title', ) def __str__(self): return self.title def clear_cache(self): # Called on save/delete by CachedModelMixin _clear_mapitem_cache() def to_dict(self, detailed=False): """ Export the marker data for the frontend. :param expanded: Tell whether more detailed information should be added, for the detail page. :type expanded: bool """ geoposition = self.location return { 'id': self.pk, 'title': self.title, 'image': _image_to_dict(self, self.image), 'description': self.description, 'group_id': self.group_id, 'location': [float(geoposition.latitude), float(geoposition.longitude)], #'click_zoom': 7, #cluster_weight }
class Col12Item(ContentItem): """ A column that takes 1/2 of the width """ title = models.CharField(_("Title"), max_length=200) icon = PluginImageField(_("Icon"), blank=True) body = PluginHtmlField(_("Body")) class Meta: verbose_name = _("Column (1/2)") verbose_name_plural = _("Columns (1/2)") def __str__(self): return self.title
class MarkerGroup(CachedModelMixin, models.Model): """ Grouping of markers in a given category, """ title = models.CharField(_("Title"), max_length=200) marker_image = PluginImageField(_("Marker image")) marker_zoom = models.PositiveSmallIntegerField(_("Zoom level on click"), default=7) class Meta: verbose_name = _("Marker Group") verbose_name_plural = _("Marker Groups") ordering = ('title', ) def __str__(self): return self.title def clear_cache(self): # Called on save/delete by CachedModelMixin _clear_mapitem_cache() @property def url(self): return self.image.url if self.image else None @property def anchor(self): return (0, 0) @property def origin(self): return (0, 0) def to_dict(self): """ Export the group data for the frontend. """ return { 'id': self.pk, 'title': self.title, 'icon': { 'url': self.marker_image.url if self.marker_image else None, 'width': self.marker_image.width if self.marker_image else 16, 'height': self.marker_image.height if self.marker_image else 16, 'marker_zoom': self.marker_zoom, }, 'markers': [marker.to_dict() for marker in self.markers.all()], }
class PictureItem(ContentItem): """ Display a picture """ ALIGN_LEFT = "left" ALIGN_CENTER = "center" ALIGN_RIGHT = "right" ALIGN_CHOICES = ( (ALIGN_LEFT, _("Left")), (ALIGN_CENTER, _("Center")), (ALIGN_RIGHT, _("Right")), ) image = PluginImageField(_("Image"), upload_to=appsettings.FLUENT_PICTURE_UPLOAD_TO) caption = models.TextField(_("Caption"), blank=True) align = models.CharField(_("Align"), max_length=10, choices=ALIGN_CHOICES, blank=True) url = PluginUrlField(_("URL"), blank=True) in_new_window = models.BooleanField(_("Open in a new window"), default=False, blank=True) objects = ContentItemManager() # Avoid Django 1.10 migrations class Meta: verbose_name = _("Picture") verbose_name_plural = _("Pictures") def __str__(self): return self.caption or str(self.image) @property def align_class(self): """ The CSS class for alignment. """ if self.align == self.ALIGN_LEFT: return "align-left" elif self.align == self.ALIGN_CENTER: return "align-center" elif self.align == self.ALIGN_RIGHT: return "align-right" else: return ""
class TeaserItem(ContentItem): title = models.CharField(_("title"), max_length=256) image = PluginImageField( _("image"), upload_to=appsettings.FLUENTCMS_TEASER_UPLOAD_TO, blank=True, null=True ) url = PluginUrlField( _("URL"), null=True, blank=True, help_text=_("If present image will be clickable.") ) url_title = models.CharField(_("URL title"), max_length=200, blank=True, null=True) description = PluginHtmlField(_("description"), blank=True, null=True) target = models.CharField( _("target"), blank=True, max_length=100, choices=( ( ("", _("same window")), ("_blank", _("new window")), ("_parent", _("parent window")), ("_top", _("topmost frame")), ) ), ) class Meta: verbose_name = _("Teaser") verbose_name_plural = _("Teasers") def __str__(self): return self.title def save(self, *args, **kwargs): if appsettings.FLUENTCMS_TEASER_CLEAN_HTML: self.description = clean_html(self.description) # Remove unwanted tags if requested if appsettings.FLUENTCMS_TEASER_SANITIZE_HTML: self.description = sanitize_html(self.description) super().save(*args, **kwargs)