Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import re
2from django.db import models
3from django.utils.translation import gettext_lazy as _
4from django.core.exceptions import ValidationError
6from filer.fields.image import FilerImageField
7from cms.models import CMSPlugin
8from djangocms_link.models import AbstractLink
9from djangocms_text_ckeditor.fields import HTMLField
10from djangocms_picture.models import AbstractPicture
11from cms.models.fields import PlaceholderField
12from filer.fields.file import FilerFileField
14from .constants import TAB_TYPE_CHOICES, STAFF_LISTING_CHOICES
16class UnimelbTab(CMSPlugin):
17 """
18 Creates a tab using the Unimelb theme.
20 See https://web.unimelb.edu.au/components/tabs
22 Based on https://github.com/django-cms/djangocms-bootstrap4/blob/master/djangocms_bootstrap4/contrib/bootstrap4_tabs/
23 """
24 tab_type = models.CharField(
25 verbose_name=_('Type'),
26 choices=TAB_TYPE_CHOICES,
27 default=TAB_TYPE_CHOICES[0][0],
28 max_length=255,
29 )
30 tab_index = models.PositiveIntegerField(
31 verbose_name=_('Index'),
32 null=True,
33 blank=True,
34 help_text=_('Index of element to open on page load starting at 1.'),
35 default=1,
36 )
38 def __str__(self):
39 return f"{self.tab_type}"
41 def get_short_description(self):
42 text = '({})'.format(self.tab_type)
44 return text
47class UnimelbTabItem(CMSPlugin):
48 """
49 Creates an item in a tab using the Unimelb theme.
51 See https://web.unimelb.edu.au/components/tabs
52 """
53 tab_title = models.CharField(
54 verbose_name=_('Tab title'),
55 max_length=255,
56 )
58 def __str__(self):
59 return self.tab_title
61 def get_short_description(self):
62 return self.tab_title
65class UnimelbStaffListing(CMSPlugin):
66 """
67 Adds a listing of staff members
69 https://web.unimelb.edu.au/components/people
70 """
71 listing_type = models.CharField(
72 verbose_name=_('Type'),
73 choices=STAFF_LISTING_CHOICES,
74 default=STAFF_LISTING_CHOICES[0][0],
75 max_length=255,
76 )
78 def __str__(self):
79 return f"{self.pk}"
82class UnimelbStaffMember(CMSPlugin):
83 """
84 Adds a listing of staff members
86 https://web.unimelb.edu.au/components/people
87 """
88 name = models.CharField(max_length=255)
89 url = models.CharField(
90 verbose_name=_('URL'),
91 max_length=1023,
92 blank=True,
93 default="",
94 )
95 image = FilerImageField(
96 blank=True,
97 null=True,
98 default=None,
99 on_delete=models.SET_NULL,
100 related_name='+',
101 help_text="An image of this staff member."
102 )
103 image_external_url = models.CharField(
104 max_length=1023,
105 blank=True,
106 default="",
107 help_text="An external URL to an image for this staff member. This is only used if the 'image' field is empty.",
108 )
109 title = models.CharField(max_length=255, blank=True, default="")
110 institution = models.CharField(max_length=255, blank=True, default="", help_text="e.g. University of Melbourne")
112 def __str__(self):
113 return self.name
115 def image_url(self):
116 if self.image:
117 return self.image.url
118 return self.image_external_url
121class UnimelbHeading(CMSPlugin):
122 """
123 https://web.unimelb.edu.au/components/headings
124 """
125 text = models.CharField(max_length=255, blank=True, help_text="If blank then it takes the title of the current page or tab item.")
126 aligned = models.BooleanField(default=False, blank=True)
127 padding_top = models.CharField(max_length=255, blank=True, help_text="e.g. 2.0rem")
129 def __str__(self):
130 return self.text
133class UnimelbHeader(CMSPlugin):
134 """
135 https://web.unimelb.edu.au/components/headers
136 """
137 heading = models.CharField(max_length=255, default="", blank=True, help_text="The heading for the banner.")
138 subline = models.CharField(max_length=1023, default="", blank=True)
139 image = FilerImageField(
140 blank=True,
141 null=True,
142 default=None,
143 on_delete=models.SET_NULL,
144 related_name='+',
145 help_text="The image to use in the background of the banner."
146 )
147 tint = models.CharField(
148 max_length=255,
149 default="",
150 blank=True,
151 help_text="A colour to tint the header image. e.g. rgba(16, 41, 80, 0.7)",
152 )
153 messages = models.BooleanField(default=True,help_text="Displays alert messages underneath header.")
155 def __str__(self):
156 if self.heading:
157 return self.heading
158 if self.subline:
159 return self.subline
160 if self.image:
161 return str(self.image)
162 return str(self.pk)
165class UnimelbFooter(CMSPlugin):
166 light = models.BooleanField(default=False, help_text="If the background colour should be light.")
169IconChoices = models.TextChoices('IconChoices', 'add bar bike bus cafe campaign car cart chat chevron-right check check-circle city clock close computer cutlery delete devices download edit ellipsis face facebook faculty flight group home hr instagram jobs library linkedin location lock mail map menu money pharmacy phone print profile rss search send share smartphone student tag train twitter vimeo walk world youtube zoom-in zoom-out question info info-outline'.title())
172class UnimelbFooterLink(AbstractLink):
173 text = models.CharField(max_length=31, default="", blank=True, help_text="The text to accompany the link.")
174 icon = models.CharField(max_length=31, default="", blank=True, choices=IconChoices.choices)
177class UnimelbBlockListing(CMSPlugin):
178 """
179 https://web.unimelb.edu.au/components/block-listing
180 """
181 def __str__(self):
182 return str(self.pk)
185class MediaLink(AbstractLink):
186 file = FilerFileField(
187 blank=True,
188 null=True,
189 on_delete=models.SET_NULL,
190 related_name='+',
191 )
192 class Meta:
193 abstract = True
195 def get_link(self):
196 link = super().get_link()
198 if not link and self.file:
199 link = self.file.url
201 return link
204class OptionalPicture(AbstractPicture):
205 class Meta:
206 abstract = True
208 def clean(self):
209 try:
210 super().clean()
211 except ValidationError as err:
212 # TODO Check message
213 pass
216BlockListingCategory = models.TextChoices('BlockListingCategory', 'news newshero exhibition event instagram twitter')
217ImageLocation = models.TextChoices('ImageLocation', 'DEFAULT TOP BACKGROUND')
220class UnimelbBlockListingItem(OptionalPicture):
221 """
222 https://web.unimelb.edu.au/components/block-listing
224 See parent: https://github.com/django-cms/djangocms-link/blob/master/djangocms_link/models.py
225 """
226 category = models.CharField(max_length=10, default=BlockListingCategory.news, choices=BlockListingCategory.choices)
227 heading = models.CharField(max_length=255, default="", blank=True, help_text="The heading for the block listing.")
228 minor_heading = models.CharField(max_length=255, default="", blank=True, help_text="A secondary heading for the block listing.")
229 text = HTMLField(default="", blank=True, help_text="The text for the block listing. Only a few lines are visible.")
230 call_to_action = models.CharField(max_length=255, default="", blank=True, help_text="The text in a call to action button.")
231 meta_left = models.CharField(max_length=255, default="", blank=True, help_text="The text at the bottom left.")
232 meta_right = models.CharField(max_length=255, default="", blank=True, help_text="The text at the bottom right.")
233 double = models.BooleanField(default=False, help_text="Whether or not this block listing should take up two boxes.")
234 image_location = models.CharField(max_length=10, default=ImageLocation.DEFAULT, choices=ImageLocation.choices, help_text="The location of the image (if present).")
235 link_is_optional = True
236 file = FilerFileField(
237 blank=True,
238 null=True,
239 on_delete=models.SET_NULL,
240 related_name='+',
241 )
243 def __str__(self):
244 if self.heading:
245 return self.heading
246 if self.text:
247 return self.text
248 if self.meta_left:
249 return str(self.meta_left)
250 return str(self.pk)
252 def get_short_description(self):
253 return str(self)
255 def image_in_backround(self):
256 if not self.img_src:
257 return False
258 if self.image_location == ImageLocation.DEFAULT:
259 return self.category in ('newshero', 'instagram')
260 return self.image_location == ImageLocation.BACKGROUND
262 def image_at_top(self):
263 if not self.img_src:
264 return False
265 return not self.image_in_backround()
267 def get_link(self):
268 link = super().get_link()
270 if not link and self.file:
271 link = self.file.url
273 return link
277class UnimelbPathfinder(CMSPlugin):
278 """
279 https://web.unimelb.edu.au/components/pathfinder
280 """
281 def __str__(self):
282 return str(self.pk)
284 def number(self):
285 return len(child_plugin_instances)
288class UnimelbPathfinderBox(AbstractLink):
289 """
290 https://web.unimelb.edu.au/components/pathfinder
292 See parent: https://github.com/django-cms/djangocms-link/blob/master/djangocms_link/models.py
293 """
294 heading = models.CharField(max_length=255, default="", blank=True, help_text="The heading for the pathfinder box.")
295 text = models.CharField(max_length=1023, default="", blank=True, help_text="The text for the pathfinder box.")
296 button = models.CharField(max_length=255, default="", blank=True, help_text="The text for the button.")
298 def __str__(self):
299 if self.heading:
300 return self.heading
301 if self.text:
302 return self.text
303 if self.button:
304 return str(self.button)
305 return str(self.pk)
307 def get_short_description(self):
308 return str(self)
311class UnimelbSearchForm(AbstractLink):
312 """
313 https://web.unimelb.edu.au/components/search
314 """
315 pass
318class UnimelbSearchResults(CMSPlugin):
319 """
320 https://web.unimelb.edu.au/components/search
321 https://github.com/etianen/django-watson
322 """
323 pagination = models.PositiveIntegerField(default=30)
325 def __str__(self):
326 return str(self.pk)
329class UnimelbAccordion(CMSPlugin):
330 """
331 https://web.unimelb.edu.au/components/accordion
332 https://resources.web.unimelb.edu.au/web-content/creating-content/how-to-use-accordions-well
333 """
334 def __str__(self):
335 return str(self.pk)
338class UnimelbAccordionItem(CMSPlugin):
339 """
340 https://web.unimelb.edu.au/components/accordion
341 https://resources.web.unimelb.edu.au/web-content/creating-content/how-to-use-accordions-well
342 """
343 title = models.CharField(max_length=255)
344 visible = models.BooleanField(default=False, blank=True)
346 def __str__(self):
347 return str(self.title)
350class UnimelbTimeline(CMSPlugin):
351 """
352 https://web.unimelb.edu.au/components/timeline
353 https://www.w3schools.com/tags/tag_dl.asp
354 """
355 def __str__(self):
356 return str(self.pk)
359class UnimelbTimelineItem(CMSPlugin):
360 """
361 https://web.unimelb.edu.au/components/timeline
362 https://www.w3schools.com/tags/tag_dl.asp
364 Shows the 'time' string before the 'bold' string'.
365 """
366 time = models.CharField(max_length=255, default="", blank=True)
367 bold = models.CharField(max_length=255, default="", blank=True)
369 def __str__(self):
370 return re.sub( r"\s+", " ", self.time + " " + self.bold)
373class UnimelbMessages(CMSPlugin):
374 """
375 https://docs.djangoproject.com/en/3.2/ref/contrib/messages/
376 https://web.unimelb.edu.au/components/notices
378 Displays a message
379 """
380 pass
383class Status(models.TextChoices):
384 UNPUBLISHED = 'UN', 'Unpublished'
385 PUBLISHED = 'PB', 'Published'
388NoticeType = models.TextChoices('NoticeType', 'success info warning danger')
390class UnimelbNotice(CMSPlugin):
391 """
392 https://web.unimelb.edu.au/components/notices
393 """
394 notice_type = models.CharField(max_length=7, choices=NoticeType.choices)
395 dismiss = models.BooleanField(default=False, help_text="Displays a button to dismiss the notice.")
397 def __str__(self):
398 return self.notice_type
401class UnimelbLead(CMSPlugin):
402 """
403 https://web.unimelb.edu.au/components/text
404 """
405 pass
408BlockquoteStyle = models.TextChoices('BlockquoteStyle', 'classic left right')
410class UnimelbBlockquote(CMSPlugin):
411 """
412 https://web.unimelb.edu.au/components/text
413 """
414 text = models.CharField(max_length=1023, default="", blank=True)
415 cite = models.CharField(max_length=255, default="", blank=True)
416 style = models.CharField(max_length=7, choices=BlockquoteStyle.choices, blank=True, default="")
418 def __str__(self):
419 return self.text
421 def css_class(self):
422 if self.style == "classic":
423 return "blockquote-classic"
424 return self.style
427class FigureSize(models.TextChoices):
428 DEFAULT = '', 'Default'
429 MIN = 'min', 'Min'
430 MAX = 'max', 'Max'
433class FigureInset(models.TextChoices):
434 DEFAULT = '', 'Default'
435 LEFT = 'left', 'Left'
436 RIGHT = 'right', 'Right'
439class UnimelbFigure(AbstractPicture, CMSPlugin):
440 """
441 https://web.unimelb.edu.au/components/figure
442 """
443 confined = models.BooleanField(default=False, help_text="Should the figure be confined to align with the text.")
444 caption = HTMLField(default="", blank=True)
445 size = models.CharField(max_length=3, choices=FigureSize.choices, blank=True, default=FigureSize.DEFAULT, help_text="If the figure should shrink to fit its content (min) or expand to its maximum width (max).")
446 inset = models.CharField(max_length=5, choices=FigureInset.choices, blank=True, default=FigureInset.DEFAULT, help_text="If the figure should be on the left or the right.")
448 def caption_no_paragraph(self):
449 return re.sub(r"^\<p\>(.*)\<\/p\>$", r"\1", self.caption )
452class UnimelbFigureDiv(CMSPlugin):
453 """
454 https://web.unimelb.edu.au/components/figure
455 """
456 clearfix = models.BooleanField(default=True, help_text="If you don't want the figures to overflow into the content that follows.")
459class UnimelbArticle(models.Model):
460 """
461 https://web.unimelb.edu.au/components/news
462 """
463 title = models.CharField(max_length=255, help_text="The title of this article to be displayed as a heading and in the listing.")
464 description = models.CharField(max_length=1023, help_text="A description of this article to be displayed as a summary in the listing.")
465 content = PlaceholderField('content')