Coverage for utilities/forms/widgets/misc.py: 58%
40 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django import forms
3__all__ = (
4 'ArrayWidget',
5 'ChoicesWidget',
6 'ClearableFileInput',
7 'MarkdownWidget',
8 'NumberWithOptions',
9 'SlugWidget',
10)
13class ClearableFileInput(forms.ClearableFileInput):
14 """
15 Override Django's stock ClearableFileInput with a custom template.
16 """
17 template_name = 'widgets/clearable_file_input.html'
20class MarkdownWidget(forms.Textarea):
21 """
22 Provide a live preview for Markdown-formatted content.
23 """
24 template_name = 'widgets/markdown_input.html'
26 def __init__(self, attrs=None):
27 # Markdown fields should use monospace font
28 default_attrs = {
29 "class": "font-monospace",
30 }
31 if attrs: 31 ↛ 32line 31 didn't jump to line 32 because the condition on line 31 was never true
32 default_attrs.update(attrs)
34 super().__init__(default_attrs)
37class NumberWithOptions(forms.NumberInput):
38 """
39 Number field with a dropdown pre-populated with common values for convenience.
40 """
41 template_name = 'widgets/number_with_options.html'
43 def __init__(self, options, attrs=None):
44 self.options = options
45 super().__init__(attrs)
47 def get_context(self, name, value, attrs):
48 context = super().get_context(name, value, attrs)
49 context['widget']['options'] = self.options
50 return context
53class SlugWidget(forms.TextInput):
54 """
55 Subclass TextInput and add a slug regeneration button next to the form field.
56 """
57 template_name = 'widgets/sluginput.html'
59 def __init__(self, attrs=None):
60 local_attrs = {} if attrs is None else attrs.copy()
61 if 'class' in local_attrs: 61 ↛ 62line 61 didn't jump to line 62 because the condition on line 61 was never true
62 local_attrs['class'] = f"{local_attrs['class']} slug-field"
63 else:
64 local_attrs['class'] = 'slug-field'
65 super().__init__(local_attrs)
68class ArrayWidget(forms.Textarea):
69 """
70 Render each item of an array on a new line within a textarea for easy editing/
71 """
72 def format_value(self, value):
73 if value is None or not len(value):
74 return None
75 return '\n'.join(value)
78class ChoicesWidget(forms.Textarea):
79 """
80 Render each key-value pair of a dictionary on a new line within a textarea for easy editing.
81 """
82 def format_value(self, value):
83 if not value:
84 return None
85 if type(value) is list:
86 return '\n'.join([f'{k}:{v}' for k, v in value])
87 return value