`` is a web component to let the browser pre-validate and manipulate one or more
8 | Django ``Form``-s. This facilitates developers to build beautiful forms with a contemporary user
9 | experience. This library ships with a set of widgets, which integrate seamlessly with their
10 | Django's counterparts.
11 |
12 |
13 | .. toctree::
14 | :maxdepth: 2
15 | :caption: Contents:
16 | :numbered:
17 |
18 | intro
19 | installation
20 | django-formset
21 | single-form
22 | styling
23 | dark-mode
24 | default-widgets
25 | alternative-widgets
26 | buttons
27 | activators
28 | withholding-feedback
29 | collections
30 | fieldsets
31 | model-forms
32 | model-collections
33 | form-renderer
34 | conditionals
35 | uploading
36 | selectize
37 | dual-selector
38 | dialog-forms
39 | dialog-model-forms
40 | form-stepper
41 | richtext
42 | richtext-extensions
43 | slug-input
44 | date-time-input
45 | date-time-range
46 | country-selectize
47 | phone-number-field
48 | development
49 | contributing
50 | faq
51 | changes
52 | history
53 | chat-gpt
54 |
55 | Project Home
56 | ============
57 |
58 | The complete source for **django-formset** is available on GitHub at
59 | https://github.com/jrief/django-formset
60 |
61 |
62 | License
63 | =======
64 |
65 | **django-formset** is licensed according to the MIT public license.
66 |
--------------------------------------------------------------------------------
/fly.toml:
--------------------------------------------------------------------------------
1 | # fly.toml app configuration file generated for django-formset-quiet-waterfall-43 on 2024-04-04T14:00:35+02:00
2 | #
3 | # See https://fly.io/docs/reference/configuration/ for information about how to use this file.
4 | #
5 |
6 | app = 'django-formset'
7 | primary_region = 'ams'
8 | console_command = '/web/manage.py shell'
9 |
10 | [build]
11 | dockerfile = ".deployment/Dockerfile"
12 |
13 | [mounts]
14 | source = 'workdir'
15 | destination = '/web/workdir'
16 |
17 | [env]
18 | PORT = '8080'
19 | DJANGO_WORKDIR = '/web/workdir'
20 | DJANGO_MEDIA_ROOT = '/web/workdir/media'
21 | DJANGO_STATIC_ROOT = '/web/staticfiles'
22 |
23 | [http_service]
24 | internal_port = 8080
25 | force_https = true
26 | auto_stop_machines = true
27 | auto_start_machines = true
28 | min_machines_running = 0
29 | processes = ['app']
30 |
31 | [[vm]]
32 | memory = '1gb'
33 | cpu_kind = 'shared'
34 | cpus = 1
35 |
36 | [[statics]]
37 | guest_path = '/web/static'
38 | url_prefix = '/static/'
39 |
--------------------------------------------------------------------------------
/formset/__init__.py:
--------------------------------------------------------------------------------
1 | VERSION = 1, 7, 7
2 | __version__ = '.'.join(map(str, VERSION))
3 |
--------------------------------------------------------------------------------
/formset/exceptions.py:
--------------------------------------------------------------------------------
1 | class FormCollectionError(Exception):
2 | """Some kind of problem with a FormCollection."""
3 | pass
4 |
--------------------------------------------------------------------------------
/formset/richtext/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/formset/richtext/__init__.py
--------------------------------------------------------------------------------
/formset/richtext/fields.py:
--------------------------------------------------------------------------------
1 | from django.db.models.fields.json import JSONField
2 |
3 | from formset.richtext.widgets import RichTextarea
4 |
5 |
6 | class RichTextField(JSONField):
7 | def formfield(self, **kwargs):
8 | form_field = super().formfield(**kwargs)
9 | if not isinstance(form_field.widget, RichTextarea):
10 | form_field.widget = RichTextarea()
11 | return form_field
12 |
--------------------------------------------------------------------------------
/formset/static/formset/icons/file-audio.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/formset/static/formset/icons/file-empty.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/formset/static/formset/icons/file-font.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/formset/static/formset/icons/file-picture.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/formset/static/formset/tiptap-extensions/footnote.js:
--------------------------------------------------------------------------------
1 | {
2 | name: 'footnote',
3 | keepOnSplit: false,
4 | inline: true,
5 | group: 'inline',
6 | selectable: true,
7 |
8 | addAttributes() {
9 | return {
10 | content: {
11 | default: null,
12 | renderHTML: attributes => {
13 | return {
14 | content: JSON.stringify(attributes.content ?? {type: 'doc'}),
15 | };
16 | },
17 | parseHTML: element => {
18 | return JSON.parse(element.getAttribute('content') ?? '{"type": "doc"}');
19 | },
20 | },
21 | role: {
22 | default: 'note',
23 | },
24 | }
25 | },
26 |
27 | parseHTML() {
28 | return [{
29 | tag: 'span',
30 | role: 'note',
31 | }];
32 | },
33 |
34 | renderHTML({HTMLAttributes}) {
35 | return ['span', HTMLAttributes];
36 | },
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/formset/static/formset/tiptap-extensions/procurator.js:
--------------------------------------------------------------------------------
1 | {
2 | name: 'procurator', // renamed extension from "placeholder" to avoid naming conflict
3 | keepOnSplit: false,
4 |
5 | addAttributes() {
6 | return {
7 | variable_name: {
8 | default: null,
9 | },
10 | sample_value: {
11 | default: null,
12 | },
13 | role: {
14 | default: 'placeholder',
15 | },
16 | }
17 | },
18 |
19 | parseHTML() {
20 | return [{
21 | tag: 'output',
22 | role: 'placeholder',
23 | }];
24 | },
25 |
26 | renderHTML({HTMLAttributes}) {
27 | return ['output', HTMLAttributes, 0];
28 | },
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/formset/static/formset/tiptap-extensions/simple_image.js:
--------------------------------------------------------------------------------
1 | {
2 | name: 'simple_image',
3 | inline: true,
4 | group: 'inline',
5 | draggable: true,
6 |
7 | addAttributes() {
8 | return {
9 | src: {
10 | default: null,
11 | },
12 | alt: {
13 | default: null,
14 | },
15 | title: {
16 | default: null,
17 | },
18 | dataset: {
19 | default: {},
20 | },
21 | };
22 | },
23 |
24 | parseHTML() {
25 | return [{tag: 'img[src]'}];
26 | },
27 |
28 | renderHTML({HTMLAttributes}) {
29 | return ['img', HTMLAttributes];
30 | },
31 | }
32 |
--------------------------------------------------------------------------------
/formset/static/formset/tiptap-extensions/simple_link.js:
--------------------------------------------------------------------------------
1 | {
2 | name: 'simple_link',
3 | priority: 1000,
4 | keepOnSplit: false,
5 |
6 | addAttributes() {
7 | return {
8 | href: {
9 | default: null,
10 | },
11 | };
12 | },
13 |
14 | parseHTML() {
15 | return [{tag: 'a[href]:not([href *= "javascript:" i])'}];
16 | },
17 |
18 | renderHTML({HTMLAttributes}) {
19 | return ['a', HTMLAttributes, 0];
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/formset/stepper.py:
--------------------------------------------------------------------------------
1 | from formset.collection import BaseFormCollection, FormCollectionMeta
2 |
3 |
4 | class StepperCollectionMeta(FormCollectionMeta):
5 | def __new__(cls, *args, **kwargs):
6 | new_class = super().__new__(cls, *args, **kwargs)
7 | for holder in new_class.declared_holders.values():
8 | setattr(holder, 'induce_activate', getattr(holder, 'induce_activate', None))
9 | setattr(holder, 'step_label', getattr(holder, 'step_label', ''))
10 | return new_class
11 |
12 |
13 | class StepperCollection(BaseFormCollection, metaclass=StepperCollectionMeta):
14 | template_name = 'formset/default/stepper_collection.html'
15 |
16 | def iter_many(self):
17 | raise NotImplementedError("StepperCollection can not be used with siblings")
18 |
19 | def render(self, template_name=None, context=None, renderer=None):
20 | context = context or {}
21 | return super().render(template_name, context, renderer)
22 |
23 | __str__ = render
24 | __html__ = render
25 |
--------------------------------------------------------------------------------
/formset/templates/admin/formset/change_form.html:
--------------------------------------------------------------------------------
1 | {% extends "admin/change_form.html" %}
2 | {% load static %}
3 |
4 | {% block extrahead %}
5 | {{ block.super }}
6 |
8 | {% endblock %}
9 |
10 | {% block content %}
11 |
12 | {{ block.super }}
13 |
14 | {% endblock %}
15 |
--------------------------------------------------------------------------------
/formset/templates/calendar/hours.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 |
3 |
6 |
9 |
12 |
15 |
16 |
17 | {% block sheet-body %}
18 |
19 | {% for shift in calendar.shifts %}
20 |
21 | {% for datetime, hour, minutes in shift %}
22 | - {{ hour }}
23 | {% endfor %}
24 |
25 | {% for datetime, hour, minutes in shift %}
26 | {% if minutes %}
27 |
28 | {% for datetime, minute in minutes %}
29 | - {{ minute }}
30 | {% endfor %}
31 |
32 | {% endif %}
33 | {% endfor %}
34 | {% endfor %}
35 |
36 | {% endblock %}
37 |
38 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/calendar/months.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 |
3 |
6 |
9 |
12 |
15 |
18 |
19 |
20 | {% block sheet-body %}
21 |
22 |
23 | {% for date, month in calendar.months %}
24 | - {{ month }}
25 | {% endfor %}
26 |
27 |
28 | {% endblock %}
29 |
30 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/calendar/range.html:
--------------------------------------------------------------------------------
1 | {% extends calendar.template %}
2 | {% block sheet-body %}
3 |
4 | {{ block.super }}
5 |
6 | {% endblock %}
--------------------------------------------------------------------------------
/formset/templates/calendar/weeks.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 |
3 |
6 |
9 |
12 |
15 |
16 |
17 | {% block sheet-body %}
18 |
19 |
20 | {% for abbr, weekday in calendar.weekdays %}
21 | - {{ abbr }}
22 | {% endfor %}
23 |
24 |
25 | {% for date, day, classes in calendar.monthdays %}
26 | - {{ day }}
27 | {% endfor %}
28 |
29 |
30 | {% endblock %}
31 |
32 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/calendar/years.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 |
3 |
6 |
9 | {% with first_year=calendar.years|first last_year=calendar.years|last %}
10 |
11 | {% endwith %}
12 |
15 |
18 |
19 |
20 | {% block sheet-body %}
21 |
22 |
23 | {% for date, year in calendar.years %}
24 | - {{ year }}
25 | {% endfor %}
26 |
27 |
28 | {% endblock %}
29 |
30 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/buttons/add_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/add_collection.html" %}
2 | {% block "button-classes" %} btn btn-sm btn-outline-contrast{% endblock %}
3 | {% block "label-classes" %}ms-1{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/buttons/remove_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/remove_collection.html" %}
2 | {% block "button-classes" %} btn btn-sm btn-outline-contrast{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/buttons/richtext_align.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/richtext_align.html" %}
2 | {% block dropdown_menu_class %} class="dropdown-menu"{% endblock %}
3 | {% block dropdown_menu_item %} class="dropdown-item"{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/buttons/richtext_color.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/richtext_color.html" %}
2 | {% block dropdown_menu_class %} class="dropdown-menu"{% endblock %}
3 | {% block dropdown_menu_item %} class="dropdown-item"{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/buttons/richtext_heading.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/richtext_heading.html" %}
2 | {% block dropdown_menu_class %} class="dropdown-menu"{% endblock %}
3 | {% block dropdown_menu_item %} class="dropdown-item"{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/field_group.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 | {{ field.label_tag }}
4 | {% if control_css_classes %}
{% endif %}
5 | {{ field }}
6 | {{ field.errors }}
7 | {% with help_text=field.help_text %}
8 | {% if help_text %}{% include "./help_text.html" %}{% endif %}
9 | {% endwith %}
10 | {% if control_css_classes %}
{% endif %}
11 |
12 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/form.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/form.html" %}
2 |
3 | {% block fields %}{% spaceless %}
4 | {% for field in form %}
5 | {% if field.is_hidden %}{{ field }}{% else %}{% include "formset/bootstrap/field_group.html" %}{% endif %}
6 | {% endfor %}
7 | {% endspaceless %}{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/help_text.html:
--------------------------------------------------------------------------------
1 | {{ help_text }}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/widgets/checkbox.html:
--------------------------------------------------------------------------------
1 |
2 | {% include widget.template_name %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/widgets/dual_selector.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/dual_selector.html" %}
2 |
3 | {% block "wrapper_classes" %}{{ block.super }} row{% endblock %}
4 | {% block "left-column" %}{{ block.super }}
{% endblock %}
5 | {% block "control-panel" %}
6 |
7 |
8 | {% with button_classes="btn btn-outline-secondary" %}
9 | {% include "formset/default/buttons/move_all_right.html" %}
10 | {% include "formset/default/buttons/move_selected_right.html" %}
11 | {% include "formset/default/buttons/move_selected_left.html" %}
12 | {% include "formset/default/buttons/move_all_left.html" %}
13 | {% include "formset/default/buttons/undo_selected.html" %}
14 | {% include "formset/default/buttons/redo_selected.html" %}
15 | {% endwith %}
16 |
17 |
18 | {% endblock %}
19 | {% block "right-column" %}{{ block.super }}
{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/widgets/file.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/file.html" %}
2 | {% load i18n %}
3 |
4 | {% block "choose-file" %}
5 |
6 | {% endblock %}
7 |
8 | {% block "file-caption" %}
9 |
10 |
11 | - {% trans 'Name' %}:
12 | - ${name}
13 |
14 |
15 | - {% trans 'Content-Type (Size)' %}:
16 | - ${content_type} (${size})
17 |
18 |
22 |
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/widgets/input_option.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/widgets/multiple_input.html:
--------------------------------------------------------------------------------
1 | {% with id=widget.attrs.id %}{% for group, options, index in widget.optgroups %}{% if group %}
2 |
{{ group }}
{% endif %}{% for option in options %}
3 |
{% include option.template_name with widget=option %}
{% endfor %}{% if group %}
4 |
{% endif %}{% endfor %}
5 |
{% endwith %}
--------------------------------------------------------------------------------
/formset/templates/formset/bootstrap/widgets/richtextarea.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/richtextarea.html" %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/buttons/add_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/add_collection.html" %}
2 | {% block "button-classes" %} button is-small mb-2{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/buttons/remove_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/remove_collection.html" %}
2 | {% block "button-classes" %} button is-small{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/field_group.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 | {{ field.label_tag }}
4 | {{ field }}
5 | {{ field.errors }}
6 | {% with help_text=field.help_text %}
7 | {% if help_text %}
{{ help_text }}
{% endif %}
8 | {% endwith %}
9 |
10 | {% endspaceless %}
11 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/form.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/form.html" %}
2 |
3 | {% block fields %}{% spaceless %}
4 | {% for field in form %}
5 | {% if field.is_hidden %}{{ field }}{% else %}{% include "formset/bulma/field_group.html" %}{% endif %}
6 | {% endfor %}
7 | {% endspaceless %}{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/widgets/checkbox.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/widgets/dual_selector.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/dual_selector.html" %}
2 | {% load translate from i18n %}
3 |
4 | {% block "left-column" %}
5 |
11 | {% endblock %}
12 |
13 | {% block "control-panel" %}
14 |
15 |
16 | {% with button_classes="btn btn-outline-secondary btn-sm" %}
17 | {% include "formset/default/buttons/move_all_right.html" %}
18 | {% include "formset/default/buttons/move_selected_right.html" %}
19 | {% include "formset/default/buttons/move_selected_left.html" %}
20 | {% include "formset/default/buttons/move_all_left.html" %}
21 | {% include "formset/default/buttons/undo_selected.html" %}
22 | {% include "formset/default/buttons/redo_selected.html" %}
23 | {% endwith %}
24 |
25 |
26 | {% endblock %}
27 |
28 | {% block "right-column" %}
29 |
35 | {% endblock %}
36 |
37 |
38 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/widgets/file.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/file.html" %}
2 | {% load i18n %}
3 |
4 | {% block "choose-file" %}
5 |
6 | {% endblock %}
7 |
8 | {% block "file-caption" %}
9 |
10 |
11 | - {% trans 'Name' %}:
12 | - ${name}
13 |
14 |
15 | - {% trans 'Content-Type (Size)' %}:
16 | - ${content_type} (${size})
17 |
18 |
22 |
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/widgets/input_option.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/widgets/multiple_input.html:
--------------------------------------------------------------------------------
1 | {% with id=widget.attrs.id %}{% for group, options, index in widget.optgroups %}{% if group %}
2 |
{{ group }}
{% endif %}{% for option in options %}
3 | {% include option.template_name with widget=option %}{% endfor %}{% if group %}
4 |
{% endif %}{% endfor %}
5 |
{% endwith %}
--------------------------------------------------------------------------------
/formset/templates/formset/bulma/widgets/select.html:
--------------------------------------------------------------------------------
1 | {% include widget.template_name %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/add_collection.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/move_all_left.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/move_all_right.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/move_selected_left.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/move_selected_right.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/redo_selected.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/remove_collection.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/buttons/undo_selected.html:
--------------------------------------------------------------------------------
1 | {% load translate from i18n %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/detached_field.html:
--------------------------------------------------------------------------------
1 | {{ field.as_widget }}
2 | {% with help_text=field.help_text %}
3 | {% if help_text %}{% include help_text_template %}{% endif %}
4 | {% endwith %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/field_errors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{% for error in errors %}- {{ error }}
{% endfor %}
4 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/field_group.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 | {% if field.label %}{{ field.label_tag }}{% endif %}
4 | {{ field }}
5 | {{ field.errors }}
6 | {% with help_text=field.help_text %}
7 | {% if help_text %}{% include "./help_text.html" %}{% endif %}
8 | {% endwith %}
9 |
10 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/fieldset.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 |
15 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/form.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 |
4 | {% include "formset/non_field_errors.html" %}
5 | {% block fields %}
6 | {% for field in form %}
7 | {% if field.is_hidden %}
8 | {{ field }}
9 | {% else %}
10 | {% include "formset/default/field_group.html" %}
11 | {% endif %}
12 | {% endfor %}
13 | {% endblock %}
14 |
15 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/form_dialog.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
37 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/help_text.html:
--------------------------------------------------------------------------------
1 | {{ help_text }}
--------------------------------------------------------------------------------
/formset/templates/formset/default/stepper_collection.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 | {% if collection.legend %}{% endif %}
3 |
4 |
14 | {% for holder in collection %}
15 |
16 | {{ holder }}
17 |
18 | {% endfor %}
19 | {% if collection.help_text %}{% include help_text_template with help_text=collection.help_text %}{% endif %}
20 |
21 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/button.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/calendar.html:
--------------------------------------------------------------------------------
1 | {% include "django/forms/widgets/input.html" %}
2 |
3 | {% include "calendar/range.html" %}
4 |
5 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/country_selectize.html:
--------------------------------------------------------------------------------
1 | {% extends "./selectize.html" %}
2 | {% block "templates" %}
3 | {{ block.super }}
4 |
5 | ${label}
6 |
7 | {% endblock %}
8 |
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/datetime.html:
--------------------------------------------------------------------------------
1 | {% include "django/forms/widgets/input.html" %}
2 | {% if calendar %}
3 |
4 | {% include calendar.template %}
5 |
6 | {% endif %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/multiple_input.html:
--------------------------------------------------------------------------------
1 | {% with id=widget.attrs.id %}{% for group, options, index in widget.optgroups %}{% if group %}
2 |
{% endif %}{% endfor %}
5 |
{% endwith %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/richtextarea.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 |
{{ control_panel }}
4 | {% for dialog_form in dialog_forms %}{{ dialog_form }}{% endfor %}
5 |
6 |
7 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/select.html:
--------------------------------------------------------------------------------
1 | {% include "django/forms/widgets/select.html" %}
--------------------------------------------------------------------------------
/formset/templates/formset/default/widgets/selectize.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | {% spaceless %}
3 | {% block "selectize-select-widget" %}
4 |
9 | {% endblock %}
10 | {% if widget.attrs.multiple %}{% with script_id=widget.attrs.id|add:"_initial" %}
11 | {{ widget.value|json_script:script_id }}
12 | {% endwith %}{% endif %}
13 | {% block "templates" %}
14 | {% block "select-no-results" %}
15 |
16 | {% trans "No results found for '${input}'" %}
17 |
18 | {% endblock %}
19 | {% block "selectize-remove-item" %}
20 | {% trans "Remove item" %}
21 | {% endblock %}
22 | {% endblock %}
23 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/form_attrs.html:
--------------------------------------------------------------------------------
1 | {% if form.prefix %} name="{{ form.prefix }}"{% endif %}{% if form.form_id %} id="{{ form.form_id }}"{% endif %}{% if form.method %} method="{{ form.method }}"{% endif %}{% if form.is_transient %} df-transient{% endif %}{% if form.extension %} richtext-extension="{{ form.extension }}"{% endif %}{% if form.novalidate %} novalidate{% endif %}
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/buttons/add_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/add_collection.html" %}
2 | {% block "button-classes" %} tiny hollow button secondary{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/buttons/remove_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/remove_collection.html" %}
2 | {% block "button-classes" %} tiny hollow secondary{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/field_group.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 | {{ field.label_tag }}
4 | {{ field }}
5 | {{ field.errors }}
6 | {% with help_text=field.help_text %}
7 | {% if help_text %}
{{ help_text }}
{% else %}
{% endif %}
8 | {% endwith %}
9 |
10 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/form.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/form.html" %}
2 |
3 | {% block fields %}{% spaceless %}
4 | {% for field in form %}
5 | {% if field.is_hidden %}{{ field }}{% else %}{% include "formset/foundation/field_group.html" %}{% endif %}
6 | {% endfor %}
7 | {% endspaceless %}{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/widgets/checkbox.html:
--------------------------------------------------------------------------------
1 | {% include widget.template_name %}
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/widgets/dual_selector.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/dual_selector.html" %}
2 |
3 | {% block "wrapper_classes" %}{{ block.super }} grid-x{% endblock %}
4 | {% block "left-column" %}{{ block.super }}
{% endblock %}
5 | {% block "control-panel" %}
6 |
7 |
8 | {% with button_classes="hollow button tiny" %}
9 | {% include "formset/default/buttons/move_all_right.html" %}
10 | {% include "formset/default/buttons/move_selected_right.html" %}
11 | {% include "formset/default/buttons/move_selected_left.html" %}
12 | {% include "formset/default/buttons/move_all_left.html" %}
13 | {% include "formset/default/buttons/undo_selected.html" %}
14 | {% include "formset/default/buttons/redo_selected.html" %}
15 | {% endwith %}
16 |
17 |
18 | {% endblock %}
19 | {% block "right-column" %}{{ block.super }}
{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/widgets/file.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/file.html" %}
2 | {% load i18n %}
3 |
4 | {% block "choose-file" %}
5 |
6 | {% endblock %}
7 |
8 | {% block "file-caption" %}
9 |
10 |
11 | - {% trans 'Name' %}:
12 | - ${name}
13 |
14 |
15 | - {% trans 'Content-Type (Size)' %}:
16 | - ${content_type} (${size})
17 |
18 | {% trans "Delete" %}
19 | {% trans "Download" %}
20 |
21 | {% endblock %}
22 |
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/widgets/inlined_input_option.html:
--------------------------------------------------------------------------------
1 | {% include "django/forms/widgets/input.html" %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/foundation/widgets/multiple_input.html:
--------------------------------------------------------------------------------
1 | {% with id=widget.attrs.id %}{% endwith %}
--------------------------------------------------------------------------------
/formset/templates/formset/icons/activator.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/add-fill.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/align-center.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/align-justify.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/align-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/align-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/arrow-up.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/blockquote.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/bold.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/bulletlist.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/calendar-today.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/chevron-double-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/chevron-double-right.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/chevron-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/chevron-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/clearformat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/codeblock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/decreasemargin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/delete-back.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/double-chevron-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/double-chevron-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/font-family.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/font-size.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/footnote.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/hardbreak.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/heading.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/heading1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/heading2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/heading3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/heading4.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/heading5.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/heading6.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/horizontalrule.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/image.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/increasemargin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/indentfirstline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/italic.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/letters.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/line-height.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/orderedlist.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/outdentfirstline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/placeholder.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/questionmark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/redo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/reset.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/send.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/separator.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/strike.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/subscript.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/superscript.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/textcolor.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/trash.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/underline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/undo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/icons/unlink.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/non_field_errors.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/align.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 | {% if alignments|length == 1 %}
3 | {% with icon="formset/icons/align-"|add:default_alignment|add:".svg" %}
4 |
5 | {% endwith %}
6 | {% else %}
7 | {% with icon="formset/icons/align-"|add:default_alignment|add:".svg" %}
8 |
9 | {% endwith %}
10 |
11 | {% for alignment in alignments %}
12 | -
13 | {% with icon="formset/icons/align-"|add:alignment|add:".svg" %}
14 | {% include icon %}
15 | {% endwith %}
16 |
17 | {% endfor %}
18 |
19 | {% endif %}
20 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/class_based.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 |
3 |
4 | {% for css_class, class_name in css_classes.items %}
5 | -
6 |
7 | {{ class_name }}
8 |
9 |
10 | {% endfor %}
11 |
12 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/color.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 |
3 |
4 | {% for color in colors %}
5 | -
6 |
7 | {% include "formset/icons/letters.svg" %}
8 |
9 |
10 | {% endfor %}
11 |
12 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/control.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/control_group.html:
--------------------------------------------------------------------------------
1 | {% for element in elements %}{{ element }}{% endfor %}
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/dialog_control.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/form_dialog.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% include "formset/default/form_dialog.html" %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/heading.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% spaceless %}
2 | {% if levels|length == 1 %}
3 | {% with icon="formset/icons/heading"|add:levels.0|add:".svg" %}
4 |
5 | {% endwith %}
6 | {% else %}
7 |
8 |
9 | {% for level in levels %}
10 | -
11 | {% with icon="formset/icons/heading"|add:level|add:".svg" %}
12 | {% include icon %}
13 | {% endwith %}
14 |
15 | {% endfor %}
16 |
17 | {% endif %}
18 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/richtext/separator.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/buttons/add_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/add_collection.html" %}
2 | {% block "button-classes" %} inline-flex justify-center my-2 py-1 px-1 border border-transparent shadow-sm text-sm font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2{% endblock %}
3 | {% block "label-classes" %}ml-2{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/buttons/remove_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/remove_collection.html" %}
2 | {% block "button-classes" %} inline-flex justify-center py-1 px-1 border border-transparent shadow-sm text-sm font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/field_group.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 | {{ field.label_tag }}
4 | {{ field }}
5 | {{ field.errors }}
6 | {% with help_text=field.help_text %}
7 | {% if help_text %}
{{ help_text }}
{% endif %}
8 | {% endwith %}
9 |
10 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/form.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/form.html" %}
2 |
3 | {% block fields %}{% spaceless %}
4 | {% for field in form %}
5 | {% if field.is_hidden %}{{ field }}{% else %}{% include "formset/tailwind/field_group.html" %}{% endif %}
6 | {% endfor %}
7 | {% endspaceless %}{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/help_text.html:
--------------------------------------------------------------------------------
1 | {{ help_text }}
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/widgets/checkbox.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/widgets/dual_selector.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/dual_selector.html" %}
2 |
3 | {% block "wrapper_classes" %}{{ block.super }} flex flex-row{% endblock %}
4 | {% block "left-column" %}{{ block.super }}
{% endblock %}
5 | {% block "control-panel" %}
6 |
7 |
8 | {% with button_classes="bg-gray-100 hover:bg-gray-500 py-1 px-3 my-0.5 mx-2 rounded" %}
9 | {% include "formset/default/buttons/move_all_right.html" %}
10 | {% include "formset/default/buttons/move_selected_right.html" %}
11 | {% include "formset/default/buttons/move_selected_left.html" %}
12 | {% include "formset/default/buttons/move_all_left.html" %}
13 | {% include "formset/default/buttons/undo_selected.html" %}
14 | {% include "formset/default/buttons/redo_selected.html" %}
15 | {% endwith %}
16 |
17 |
18 | {% endblock %}
19 | {% block "right-column" %}{{ block.super }}
{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/widgets/file.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/file.html" %}
2 | {% load i18n %}
3 |
4 | {% block "choose-file" %}
5 |
6 | {% endblock %}
7 |
8 | {% block "file-caption" %}
9 |
10 |
11 | - {% trans 'Name' %}:
12 | - ${name}
13 |
14 |
15 | - {% trans 'Content-Type (Size)' %}:
16 | - ${content_type} (${size})
17 |
18 | {% trans "Delete" %}
19 | {% trans "Download" %}
20 |
21 | {% endblock %}
22 |
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/widgets/input_option.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/widgets/multiple_input.html:
--------------------------------------------------------------------------------
1 | {% with id=widget.attrs.id %}{% for group, options, index in widget.optgroups %}{% if group %}
2 |
{{ group }}
{% endif %}{% for option in options %}
3 |
{% include option.template_name with widget=option %}
{% endfor %}{% if group %}
4 |
{% endif %}{% endfor %}
5 |
{% endwith %}
--------------------------------------------------------------------------------
/formset/templates/formset/tailwind/widgets/radio.html:
--------------------------------------------------------------------------------
1 | {% with id=widget.attrs.id %}{% for group, options, index in widget.optgroups %}{% if group %}
2 |
{{ group }}{% endif %}{% for option in options %}
3 |
{% include option.template_name with widget=option %}
{% endfor %}{% if group %}
4 |
{% endif %}{% endfor %}
5 |
{% endwith %}
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/buttons/add_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/add_collection.html" %}
2 | {% block "button-classes" %} uk-button{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/buttons/remove_collection.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/buttons/remove_collection.html" %}
2 | {% block "button-classes" %} uk-button{% endblock %}
3 |
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/field_group.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 |
3 | {{ field.label_tag }}
4 | {{ field }}
5 | {% with help_text=field.help_text %}
6 | {% if help_text %}{{ help_text }}{% endif %}
7 | {% endwith %}
8 | {{ field.errors }}
9 |
10 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/form.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/form.html" %}
2 |
3 | {% block fields %}{% spaceless %}
4 | {% for field in form %}
5 | {% if field.is_hidden %}{{ field }}{% else %}{% include "formset/uikit/field_group.html" %}{% endif %}
6 | {% endfor %}
7 | {% endspaceless %}{% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/widgets/checkbox.html:
--------------------------------------------------------------------------------
1 | {% include widget.template_name %}
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/widgets/file.html:
--------------------------------------------------------------------------------
1 | {% extends "formset/default/widgets/file.html" %}
2 | {% load i18n %}
3 |
4 | {% block "choose-file" %}
5 |
6 | {% endblock %}
7 |
8 | {% block "file-caption" %}
9 |
10 |
11 | - {% trans 'Name' %}:
12 | - ${name}
13 |
14 |
15 | - {% trans 'Content-Type (Size)' %}:
16 | - ${content_type} (${size})
17 |
18 | {% trans "Delete" %}
19 | {% trans "Download" %}
20 |
21 | {% endblock %}
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/widgets/input_option.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/formset/templates/formset/uikit/widgets/multiple_input.html:
--------------------------------------------------------------------------------
1 | {% with id=widget.attrs.id inlined_options=widget.inlined_options %}{% endwith %}
--------------------------------------------------------------------------------
/formset/templates/richtext/README.md:
--------------------------------------------------------------------------------
1 | Templates in this directory are exclusively used to transform JSON into HTML when rendered through
2 | the template tag `render_richtext`. The staring point for any richtext is the template `doc.html`.
3 |
--------------------------------------------------------------------------------
/formset/templates/richtext/bulletlist.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}{% if node.content %}
2 |
3 | {% for item in node.content %}
4 | {% with template="richtext/"|add:item.type|lower|add:".html" %}
5 | {% include template with node=item %}
6 | {% endwith %}
7 | {% endfor %}
8 |
9 | {% endif %}{% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/richtext/doc.html:
--------------------------------------------------------------------------------
1 | {% if node.content %}
2 | {% for item in node.content %}
3 | {% with template="richtext/"|add:item.type|lower|add:".html" %}
4 | {% include template with node=item %}
5 | {% endwith %}
6 | {% endfor %}
7 | {% endif %}
8 | {% include "richtext/footnotes_list.html" %}
--------------------------------------------------------------------------------
/formset/templates/richtext/footnote.html:
--------------------------------------------------------------------------------
1 | {% load render_footnote from richtext %}
2 | {% render_footnote "richtext/footnote_ref.html" node.attrs %}
--------------------------------------------------------------------------------
/formset/templates/richtext/footnote_ref.html:
--------------------------------------------------------------------------------
1 | [{{ footnote_counter }}]
--------------------------------------------------------------------------------
/formset/templates/richtext/footnotes_list.html:
--------------------------------------------------------------------------------
1 | {% load render_richtext from richtext %}
2 | {% if richtext_footnotes %}
3 |
4 | {% for footnote in richtext_footnotes %}
5 |
8 | {% endfor %}
9 |
10 | {% endif %}
--------------------------------------------------------------------------------
/formset/templates/richtext/heading.html:
--------------------------------------------------------------------------------
1 | {% if node.content %}{% with level=node.attrs.level %}
2 |
3 | {% for item in node.content %}
4 | {% with template="richtext/"|add:item.type|lower|add:".html" %}
5 | {% include template with node=item %}
6 | {% endwith %}
7 | {% endfor %}
8 |
9 | {% endwith %}{% endif %}
--------------------------------------------------------------------------------
/formset/templates/richtext/horizontalrule.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/formset/templates/richtext/listitem.html:
--------------------------------------------------------------------------------
1 | {% if node.content %}
2 |
3 | {% for item in node.content %}
4 | {% with template="richtext/"|add:item.type|lower|add:".html" %}
5 | {% include template with node=item %}
6 | {% endwith %}
7 | {% endfor %}
8 |
9 | {% endif %}
--------------------------------------------------------------------------------
/formset/templates/richtext/marks/bold.html:
--------------------------------------------------------------------------------
1 | {{ text }}
--------------------------------------------------------------------------------
/formset/templates/richtext/marks/code.html:
--------------------------------------------------------------------------------
1 | {{ text }}
--------------------------------------------------------------------------------
/formset/templates/richtext/marks/italic.html:
--------------------------------------------------------------------------------
1 | {{ text }}
--------------------------------------------------------------------------------
/formset/templates/richtext/marks/procurator.html:
--------------------------------------------------------------------------------
1 | {% spaceless %}
2 | {% verbatim %}
3 | {{
4 | {% endverbatim %}
5 | {{ attrs.variable_name }}|default:"{{ attrs.sample_value }}"
6 | {% verbatim %}
7 | }}
8 | {% endverbatim %}
9 | {% endspaceless %}
--------------------------------------------------------------------------------
/formset/templates/richtext/marks/simple_link.html:
--------------------------------------------------------------------------------
1 | {{ text }}
--------------------------------------------------------------------------------
/formset/templates/richtext/marks/textcolor.html:
--------------------------------------------------------------------------------
1 | {{ text }}
--------------------------------------------------------------------------------
/formset/templates/richtext/marks/underline.html:
--------------------------------------------------------------------------------
1 | {{ text }}
--------------------------------------------------------------------------------
/formset/templates/richtext/orderedlist.html:
--------------------------------------------------------------------------------
1 | {% if node.content %}
2 |
3 | {% for item in node.content %}
4 | {% with template="richtext/"|add:item.type|lower|add:".html" %}
5 | {% include template with node=item %}
6 | {% endwith %}
7 | {% endfor %}
8 |
9 | {% endif %}
--------------------------------------------------------------------------------
/formset/templates/richtext/paragraph.html:
--------------------------------------------------------------------------------
1 | {% load render_attributes from richtext %}
2 | {% if node.content %}
3 |
4 | {% for item in node.content %}
5 | {% with template="richtext/"|add:item.type|lower|add:".html" %}{% include template with node=item %}{% endwith %}
6 | {% endfor %}
7 |
8 | {% endif %}
--------------------------------------------------------------------------------
/formset/templates/richtext/text.html:
--------------------------------------------------------------------------------
1 | {% for mark in node.marks %}{% with template="richtext/marks/"|add:mark.type|lower|add:".html" %}{% include template with text=node.text attrs=mark.attrs %}{% endwith %}{% empty %}{{ node.text }}{% endfor %}
--------------------------------------------------------------------------------
/formset/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/formset/templatetags/__init__.py
--------------------------------------------------------------------------------
/formset/templatetags/phonenumber.py:
--------------------------------------------------------------------------------
1 | from django import template
2 |
3 | try:
4 | from phonenumbers import PhoneNumberFormat, format_number, parse
5 | except ImportError:
6 | def format_phonenumber(value, arg=None):
7 | """As backup, render phonenumber in E.164 format."""
8 | return value
9 | else:
10 | def format_phonenumber(value, arg='international'):
11 | """Formats a phonenumber according to the country's convenience."""
12 | phone_number = parse(value, None)
13 | num_format = PhoneNumberFormat.NATIONAL if arg == 'national' else PhoneNumberFormat.INTERNATIONAL
14 | return format_number(phone_number, num_format)
15 |
16 | register = template.Library()
17 | register.filter('format_phonenumber', format_phonenumber)
18 |
--------------------------------------------------------------------------------
/formset/validators.py:
--------------------------------------------------------------------------------
1 | from django.core.validators import RegexValidator
2 | from django.utils.regex_helper import _lazy_re_compile
3 | from django.utils.translation import gettext_lazy as _
4 |
5 | phone_number_validator = RegexValidator(
6 | _lazy_re_compile(r'^\+\d{3,15}$'),
7 | message=_("Enter a valid phone number."),
8 | code="invalid",
9 | )
10 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'ts-jest',
3 | modulePaths: [
4 | '/client/'
5 | ],
6 | testEnvironment: 'node',
7 | testMatch: [
8 | '/client/tests/*.test.ts'
9 | ]
10 | };
11 |
--------------------------------------------------------------------------------
/readmeimg/bootstrap-actions.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/bootstrap-actions.gif
--------------------------------------------------------------------------------
/readmeimg/bootstrap-address-horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/bootstrap-address-horizontal.png
--------------------------------------------------------------------------------
/readmeimg/bootstrap-address.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/bootstrap-address.png
--------------------------------------------------------------------------------
/readmeimg/bootstrap-contact.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/bootstrap-contact.png
--------------------------------------------------------------------------------
/readmeimg/bootstrap-multiple-input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/bootstrap-multiple-input.png
--------------------------------------------------------------------------------
/readmeimg/bootstrap-upload-empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/bootstrap-upload-empty.png
--------------------------------------------------------------------------------
/readmeimg/bootstrap-upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/bootstrap-upload.png
--------------------------------------------------------------------------------
/readmeimg/tailwind-address.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/tailwind-address.png
--------------------------------------------------------------------------------
/readmeimg/tailwind-dual-selector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/tailwind-dual-selector.png
--------------------------------------------------------------------------------
/readmeimg/tailwind-selectize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/readmeimg/tailwind-selectize.png
--------------------------------------------------------------------------------
/testapp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/testapp/__init__.py
--------------------------------------------------------------------------------
/testapp/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .forms.complete import CompleteForm
4 |
5 |
6 | # @admin.register(DummyModel)
7 | class DummyAdmin(admin.ModelAdmin):
8 | form = CompleteForm
9 | change_form_template = 'admin/formset/change_form.html'
10 |
--------------------------------------------------------------------------------
/testapp/asgi.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.core.asgi import get_asgi_application
4 |
5 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
6 |
7 | application = get_asgi_application()
8 |
--------------------------------------------------------------------------------
/testapp/assets/broken-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/testapp/assets/broken-image.jpg
--------------------------------------------------------------------------------
/testapp/assets/dummy.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/testapp/assets/dummy.pdf
--------------------------------------------------------------------------------
/testapp/assets/python-django.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/testapp/assets/python-django.png
--------------------------------------------------------------------------------
/testapp/forms/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/testapp/forms/__init__.py
--------------------------------------------------------------------------------
/testapp/forms/address.py:
--------------------------------------------------------------------------------
1 | from django.forms import fields, forms
2 |
3 | from formset.fields import Activator
4 | from formset.renderers import ButtonVariant
5 | from formset.widgets import Button
6 |
7 |
8 | class AddressForm(forms.Form):
9 | """
10 | Grouping fields using CSS
11 | """
12 |
13 | recipient = fields.CharField(
14 | label="Recipient",
15 | max_length=100,
16 | )
17 | postal_code = fields.CharField(
18 | label="Postal Code",
19 | max_length=8,
20 | )
21 | city = fields.CharField(
22 | label="City",
23 | max_length=50,
24 | )
25 | submit = Activator(
26 | label="Submit",
27 | widget=Button(
28 | action='disable -> submit -> reload !~ scrollToError',
29 | button_variant=ButtonVariant.PRIMARY,
30 | icon_path='formset/icons/send.svg',
31 | ),
32 | )
33 | reset = Activator(
34 | label="Reset to initial",
35 | widget=Button(
36 | action='reset',
37 | button_variant=ButtonVariant.WARNING,
38 | icon_path='formset/icons/reset.svg',
39 | ),
40 | )
41 |
--------------------------------------------------------------------------------
/testapp/forms/article.py:
--------------------------------------------------------------------------------
1 | from django.forms import fields, forms
2 |
3 | from formset.widgets import SlugInput
4 |
5 |
6 | class ArticleForm(forms.Form):
7 | """
8 | In Django, a ``SlugField`` can be configured to be prepopulated using the content of another text input
9 | field. To emulate a similar behaviour, **django-formset** provides a special widget named ``SlugInput``.
10 | """
11 |
12 | title = fields.CharField(
13 | label="Title",
14 | max_length=100,
15 | )
16 |
17 | slug = fields.SlugField(
18 | label="Slug",
19 | widget=SlugInput('title'),
20 | help_text="The slug will be automatically generated from the title",
21 | )
22 |
--------------------------------------------------------------------------------
/testapp/forms/booking.py:
--------------------------------------------------------------------------------
1 | from datetime import date
2 |
3 | from django import forms
4 |
5 | from formset.ranges import DateRangeCalendar, DateRangeField, DateRangePicker, DateRangeTextbox
6 |
7 |
8 | class BookingBoxForm(forms.Form):
9 | date_range = DateRangeField(widget=DateRangeTextbox())
10 |
11 |
12 | class BookingCalendarForm(forms.Form):
13 | date_range = DateRangeField(
14 | widget=DateRangeCalendar(),
15 | initial=[
16 | date(2024, 5, 18),
17 | date(2024, 10, 12),
18 | ],
19 | )
20 |
21 |
22 | class BookingPickerForm(forms.Form):
23 | date_range = DateRangeField(
24 | widget=DateRangePicker(),
25 | initial=[
26 | date(2023, 5, 18),
27 | date(2023, 10, 12),
28 | ],
29 | )
30 |
--------------------------------------------------------------------------------
/testapp/forms/country.py:
--------------------------------------------------------------------------------
1 | from django.forms import fields, forms
2 |
3 | from django_countries import countries
4 |
5 | from formset.widgets import CountrySelectize, CountrySelectizeMultiple
6 |
7 |
8 | class CountryForm(forms.Form):
9 | """
10 | How to use the CountrySelectize and CountrySelectizeMultiple widgets.
11 | """
12 | single_country = fields.ChoiceField(
13 | label="Single Country",
14 | widget=CountrySelectize,
15 | choices=countries,
16 | )
17 | many_countries = fields.MultipleChoiceField(
18 | label="Multiple Countries",
19 | widget=CountrySelectizeMultiple(max_items=8),
20 | choices=countries,
21 | help_text="Select up to 8 countries",
22 | )
23 |
--------------------------------------------------------------------------------
/testapp/forms/customer.py:
--------------------------------------------------------------------------------
1 | from django.forms import fields, forms
2 |
3 | from formset.fieldset import Fieldset
4 | from formset.collection import FormCollection
5 |
6 |
7 | class CustomerForm(Fieldset):
8 | legend = "Customer"
9 | hide_condition = 'register.no_customer'
10 |
11 | name = fields.CharField(
12 | label="Recipient",
13 | max_length=100,
14 | )
15 |
16 | address = fields.CharField(
17 | label="Address",
18 | max_length=100,
19 | )
20 |
21 | phone_number = fields.RegexField(
22 | r'^\+?[ 0-9.\-]{4,25}$',
23 | label="Phone Number",
24 | error_messages={'invalid': "Phone number have 4-25 digits and may start with '+'."},
25 | required=False,
26 | )
27 |
28 |
29 | class RegisterForm(forms.Form):
30 | no_customer = fields.BooleanField(
31 | label="I'm not a customer",
32 | required=False,
33 | )
34 |
35 |
36 | class CustomerCollection(FormCollection):
37 | customer = CustomerForm()
38 |
39 | register = RegisterForm()
40 |
--------------------------------------------------------------------------------
/testapp/forms/gallerycollection.py:
--------------------------------------------------------------------------------
1 | from django.forms import fields, widgets
2 | from django.forms.models import ModelForm
3 |
4 | from formset.collection import FormCollection
5 | from formset.widgets import UploadedFileInput
6 |
7 | from testapp.models.gallery import Image, Gallery
8 |
9 |
10 | class ImageForm(ModelForm):
11 | id = fields.IntegerField(
12 | required=False,
13 | widget=widgets.HiddenInput,
14 | )
15 |
16 | class Meta:
17 | model = Image
18 | fields = ['id', 'image', 'caption']
19 | widgets = {
20 | 'image': UploadedFileInput,
21 | }
22 |
23 |
24 | class ImageCollection(FormCollection):
25 | min_siblings = 0
26 | extra_siblings = 1
27 | image = ImageForm()
28 | legend = "Gallery Images"
29 | add_label = "Add Image"
30 | related_field = 'gallery'
31 |
32 | def retrieve_instance(self, data):
33 | if data := data.get('image'):
34 | try:
35 | return self.instance.images.get(id=data.get('id') or 0)
36 | except (AttributeError, Image.DoesNotExist, ValueError):
37 | return Image(image=data.get('image'), gallery=self.instance)
38 |
39 |
40 | class GalleryForm(ModelForm):
41 | class Meta:
42 | model = Gallery
43 | fields = '__all__'
44 |
45 |
46 | class GalleryCollection(FormCollection):
47 | gallery = GalleryForm()
48 | images = ImageCollection()
49 |
--------------------------------------------------------------------------------
/testapp/forms/phone.py:
--------------------------------------------------------------------------------
1 | from django.forms import fields, forms
2 |
3 | from formset.validators import phone_number_validator
4 | from formset.widgets import PhoneNumberInput
5 |
6 |
7 | class PhoneForm(forms.Form):
8 | """
9 | How to use the PhoneNumberInput widget.
10 | """
11 | phone_number = fields.CharField(
12 | label="Phone Number",
13 | validators=[phone_number_validator],
14 | widget=PhoneNumberInput,
15 | )
16 |
17 | mobile_number = fields.CharField(
18 | label="Mobile Number",
19 | initial='+43 664 1234567',
20 | validators=[phone_number_validator],
21 | widget=PhoneNumberInput(attrs={'default-country-code': 'at', 'mobile-only': True}),
22 | )
23 |
--------------------------------------------------------------------------------
/testapp/forms/poll.py:
--------------------------------------------------------------------------------
1 | from django.forms import models
2 |
3 | from formset.collection import FormCollection
4 | from formset.widgets import DualSortableSelector
5 |
6 | from testapp.models import PollModel
7 |
8 |
9 | class ModelPollForm(models.ModelForm):
10 | """
11 | Many-to-Many Field with specific mapping model
12 | """
13 |
14 | class Meta:
15 | model = PollModel
16 | fields = '__all__'
17 | widgets = {
18 | 'weighted_opinions': DualSortableSelector(search_lookup='label__icontains'),
19 | }
20 |
21 |
22 | class PollCollection(FormCollection):
23 | """
24 | Wrap a ModelForm into a FormCollection
25 | """
26 | legend = "Sortable Many-to-Many Field"
27 | help_text = "Selected options on the right hand side can be sorted by dragging"
28 | poll = ModelPollForm()
29 |
--------------------------------------------------------------------------------
/testapp/forms/questionnaire.py:
--------------------------------------------------------------------------------
1 | from django.forms import fields, forms, widgets
2 |
3 |
4 | class QuestionnaireForm(forms.Form):
5 | """
6 | This Form shows how to use the tag attribute ``df-show="…"``.
7 | """
8 |
9 | full_name = fields.RegexField(
10 | r'^[A-Z][a-z\-]+\s[ A-Za-z\-]{2,}$',
11 | label="First and last name",
12 | min_length=3,
13 | max_length=100,
14 | error_messages={'invalid': "A name consist of a first and last name."},
15 | help_text="Please enter a first- and a last name, starting in upper case.",
16 | )
17 |
18 | gender = fields.ChoiceField(
19 | label="Gender",
20 | choices=[('m', "Male"), ('f', "Female"), ('x', "Inapplicable")],
21 | widget=widgets.RadioSelect,
22 | error_messages={'invalid_choice': "Please select your gender."},
23 | )
24 |
25 | pregnant = fields.BooleanField(
26 | label="Are you pregnant?",
27 | required=False,
28 | widget=widgets.CheckboxInput(attrs={'df-show': ".gender=='f'"})
29 | )
30 |
31 |
32 | sample_questionnaire_data = {
33 | 'first_name': "John Doe",
34 | 'gender': 'm',
35 | 'pregnant': False,
36 | }
37 |
--------------------------------------------------------------------------------
/testapp/forms/schedule.py:
--------------------------------------------------------------------------------
1 | from datetime import timedelta
2 |
3 | from django import forms
4 | from django.utils.timezone import datetime
5 |
6 | from formset.ranges import DateTimeRangeCalendar, DateTimeRangeField, DateTimeRangePicker, DateTimeRangeTextbox
7 |
8 |
9 | class ScheduleBoxForm(forms.Form):
10 | date_range = DateTimeRangeField(widget=DateTimeRangeTextbox())
11 |
12 |
13 | class ScheduleCalendarForm(forms.Form):
14 | date_range = DateTimeRangeField(
15 | widget=DateTimeRangeCalendar(attrs={
16 | 'step': timedelta(minutes=10),
17 | }),
18 | initial=(
19 | datetime(2024, 9, 9, 9, 40),
20 | datetime(2024, 10, 10, 16, 10),
21 | ),
22 | )
23 |
24 |
25 | class SchedulePickerForm(forms.Form):
26 | date_range = DateTimeRangeField(
27 | widget=DateTimeRangePicker(attrs={
28 | 'step': timedelta(minutes=10),
29 | }),
30 | initial=(
31 | datetime(2024, 9, 9, 9, 40),
32 | datetime(2024, 10, 10, 16, 10),
33 | ),
34 | )
35 |
--------------------------------------------------------------------------------
/testapp/forms/upload.py:
--------------------------------------------------------------------------------
1 | from django.forms import forms, fields
2 |
3 | from formset.widgets import UploadedFileInput
4 |
5 |
6 | class UploadForm(forms.Form):
7 | """
8 | This form shows how to use Django's ``django.db.models.FileField`` and/or
9 | ``django.db.models.ImageField``. It allows us to visually upload a file, which means that the
10 | uploaded payload is pre-submitted and a thumbnailed depiction is rendered. Since the uploaded
11 | file already waits in a temporary location on the server, the final form submission also is a
12 | lot faster.
13 |
14 | .. code-block:: python
15 |
16 | class UploadForm(forms.Form):
17 | avatar = fields.FileField(
18 | label="Avatar",
19 | widget=UploadedFileInput,
20 | required=True,
21 | )
22 |
23 | In combination with our webcomponent ````, using the widget
24 | ``UploadedFileInput`` is mandatory for fields of type ``FileField`` or ``ImageField``.
25 | This is because uploading the payload is separated from its form submission.
26 | """
27 | avatar = fields.FileField(
28 | label="Avatar",
29 | widget=UploadedFileInput,
30 | required=True,
31 | )
32 |
--------------------------------------------------------------------------------
/testapp/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | sys.path.insert(0, os.path.abspath(os.path.join(os.pardir)))
10 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
11 | try:
12 | from django.core.management import execute_from_command_line
13 | except ImportError as exc:
14 | raise ImportError(
15 | "Couldn't import Django. Are you sure it's installed and "
16 | "available on your PYTHONPATH environment variable? Did you "
17 | "forget to activate a virtual environment?"
18 | ) from exc
19 | execute_from_command_line(sys.argv)
20 |
21 |
22 | if __name__ == '__main__':
23 | main()
24 |
--------------------------------------------------------------------------------
/testapp/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/testapp/migrations/__init__.py
--------------------------------------------------------------------------------
/testapp/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .article import Article, Reporter
2 | from .annotation import Annotation
3 | from .company import Company, Department, Team
4 | from .county import County, CountyUnnormalized, State
5 | from .blog import BlogModel
6 | from .issue import IssueModel
7 | from .page import PageModel
8 | from .person import PersonModel, UserContact
9 | from .poll import OpinionModel, PollModel, WeightedOpinion
10 | from .user import ExtendUser, User
11 |
--------------------------------------------------------------------------------
/testapp/models/annotation.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Annotation(models.Model):
5 | content = models.CharField(max_length=200)
6 |
7 | created_by = models.CharField(
8 | editable=False,
9 | max_length=40,
10 | db_index=True,
11 | )
12 |
13 | def __str__(self):
14 | return self.content
15 |
--------------------------------------------------------------------------------
/testapp/models/article.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from .reporter import Reporter
4 |
5 |
6 | class Article(models.Model):
7 | pub_date = models.DateField()
8 | headline = models.CharField(max_length=200)
9 | content = models.TextField()
10 | reporter = models.ForeignKey(
11 | Reporter,
12 | on_delete=models.CASCADE,
13 | )
14 | teaser = models.FileField(
15 | upload_to='images',
16 | blank=True,
17 | )
18 | created_by = models.CharField(
19 | editable=False,
20 | max_length=40,
21 | db_index=True,
22 | )
23 |
24 | def __str__(self):
25 | return self.headline
26 |
--------------------------------------------------------------------------------
/testapp/models/blog.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from formset.richtext.fields import RichTextField
4 |
5 |
6 | class BlogModel(models.Model):
7 | body = RichTextField()
8 |
9 | created_by = models.CharField(
10 | editable=False,
11 | max_length=40,
12 | db_index=True,
13 | )
14 |
--------------------------------------------------------------------------------
/testapp/models/county.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class CountyUnnormalized(models.Model):
5 | state_code = models.CharField(
6 | verbose_name="State code",
7 | max_length=2,
8 | )
9 |
10 | state_name = models.CharField(
11 | verbose_name="State name",
12 | max_length=20,
13 | db_index=True,
14 | )
15 |
16 | county_name = models.CharField(
17 | verbose_name="County name",
18 | max_length=30,
19 | )
20 |
21 | class Meta:
22 | ordering = ['state_name', 'county_name']
23 |
24 |
25 | def __str__(self):
26 | return f"{self.county_name} ({self.state_code})"
27 |
28 |
29 | class State(models.Model):
30 | code = models.CharField(
31 | verbose_name="Code",
32 | max_length=2,
33 | )
34 |
35 | name = models.CharField(
36 | verbose_name="Name",
37 | max_length=20,
38 | db_index=True,
39 | )
40 |
41 | class Meta:
42 | ordering = ['name']
43 |
44 | def __str__(self):
45 | return self.name
46 |
47 |
48 | class County(models.Model):
49 | state = models.ForeignKey(
50 | State,
51 | on_delete=models.CASCADE,
52 | )
53 |
54 | name = models.CharField(
55 | verbose_name="Name",
56 | max_length=30,
57 | )
58 |
59 | class Meta:
60 | ordering = ['state', 'name']
61 |
62 | def __str__(self):
63 | return f"{self.name} ({self.state.code})"
64 |
--------------------------------------------------------------------------------
/testapp/models/gallery.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from formset.richtext.fields import RichTextField
4 |
5 |
6 | class Gallery(models.Model):
7 | name = models.CharField(
8 | verbose_name="Gallery name",
9 | max_length=50,
10 | )
11 | created_by = models.CharField(
12 | editable=False,
13 | max_length=40,
14 | db_index=True,
15 | )
16 |
17 | class Meta:
18 | verbose_name = "Gallery"
19 | verbose_name_plural = "Galleries"
20 | unique_together = ['name', 'created_by']
21 |
22 | def __str__(self):
23 | return self.name
24 |
25 |
26 | class Image(models.Model):
27 | image = models.FileField(
28 | upload_to='images',
29 | blank=True,
30 | )
31 | caption = RichTextField(
32 | blank=True,
33 | null=True,
34 | )
35 | gallery = models.ForeignKey(
36 | Gallery,
37 | on_delete=models.CASCADE,
38 | related_name='images',
39 | )
40 |
--------------------------------------------------------------------------------
/testapp/models/issue.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from testapp.models.reporter import Reporter
4 |
5 |
6 | class IssueModel(models.Model):
7 | title = models.CharField(
8 | verbose_name="Issue Title",
9 | max_length=100,
10 | )
11 | reporter = models.ForeignKey(
12 | Reporter,
13 | on_delete=models.CASCADE,
14 | verbose_name="Reporter",
15 | related_name='issues',
16 | )
17 | created_by = models.CharField(
18 | editable=False,
19 | max_length=40,
20 | db_index=True,
21 | )
22 |
23 | def __str__(self):
24 | return self.title
25 |
26 | def get_absolute_url(self):
27 | return f"/pages/{self.id}/"
28 |
--------------------------------------------------------------------------------
/testapp/models/page.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from testapp.models.reporter import Reporter
4 |
5 |
6 | class PageModel(models.Model):
7 | title = models.CharField(
8 | verbose_name="Page Title",
9 | max_length=100,
10 | )
11 | slug = models.SlugField(
12 | verbose_name="Page Slug",
13 | unique=True,
14 | null=True,
15 | )
16 | reporter = models.ForeignKey(
17 | Reporter,
18 | on_delete=models.CASCADE,
19 | verbose_name="Reporter",
20 | related_name='pages',
21 | )
22 | created_by = models.CharField(
23 | editable=False,
24 | max_length=40,
25 | db_index=True,
26 | )
27 |
28 | def __str__(self):
29 | return self.title
30 |
31 | def get_absolute_url(self):
32 | return f"/pages/{self.slug}/"
33 |
--------------------------------------------------------------------------------
/testapp/models/poll.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from formset.fields import SortableManyToManyField
3 |
4 |
5 | class OpinionModel(models.Model):
6 | tenant = models.PositiveSmallIntegerField()
7 |
8 | label = models.CharField(
9 | "Opinion",
10 | max_length=50,
11 | )
12 |
13 | class Meta:
14 | unique_together = ['tenant', 'label']
15 |
16 | def __str__(self):
17 | return self.label
18 |
19 | def __repr__(self):
20 | return f'<{self.__class__.__name__}: "{self.label}">'
21 |
22 |
23 | class PollModel(models.Model):
24 | weighted_opinions = SortableManyToManyField(
25 | OpinionModel,
26 | through='testapp.WeightedOpinion',
27 | verbose_name="Weighted Opinions",
28 | )
29 |
30 | created_by = models.CharField(
31 | editable=False,
32 | max_length=40,
33 | db_index=True,
34 | )
35 |
36 |
37 | class WeightedOpinion(models.Model):
38 | poll = models.ForeignKey(
39 | PollModel,
40 | on_delete=models.CASCADE,
41 | )
42 |
43 | opinion = models.ForeignKey(
44 | OpinionModel,
45 | on_delete=models.CASCADE,
46 | )
47 |
48 | weight = models.BigIntegerField(
49 | "Weighted Opinion",
50 | default=0,
51 | db_index=True,
52 | )
53 |
54 | class Meta:
55 | ordering = ['weight']
56 |
57 | def __repr__(self):
58 | return f'<{self.__class__.__name__}: [{self.weight}] "{self.opinion.label}">'
59 |
--------------------------------------------------------------------------------
/testapp/models/reporter.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Reporter(models.Model):
5 | full_name = models.CharField(max_length=70)
6 |
7 | def __str__(self):
8 | return self.full_name
9 |
--------------------------------------------------------------------------------
/testapp/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | DJANGO_SETTINGS_MODULE = testapp.settings
3 | django_find_project = false
4 | addopts = --tb=native
5 |
--------------------------------------------------------------------------------
/testapp/requirements.txt:
--------------------------------------------------------------------------------
1 | asgiref==3.8.1
2 | beautifulsoup4==4.13.4
3 | coverage==7.8.0
4 | https://github.com/jrief/django-countries/archive/refs/heads/main.zip
5 | docutils==0.21.2
6 | django-filter==25.1
7 | greenlet==3.2.1
8 | iniconfig==2.1.0
9 | packaging==25.0
10 | Pillow==11.2.1
11 | phonenumbers==8.13.55
12 | playwright==1.52.0
13 | pluggy==1.5.0
14 | pyee==13.0.0
15 | pytest==8.3.5
16 | pytest-django==4.11.1
17 | pytest-mock==3.14.0
18 | soupsieve==2.7
19 | sqlparse==0.5.3
20 | typing_extensions==4.13.2
21 |
--------------------------------------------------------------------------------
/testapp/static/testapp/css/bootstrap.css:
--------------------------------------------------------------------------------
1 | @import "/static/node_modules/bootstrap/dist/css/bootstrap.min.css";
2 | @import "/static/node_modules/bootstrap-icons/font/bootstrap-icons.css";
3 | @import "/static/formset/css/collections.css";
4 | @import "/static/formset/css/bootstrap5-extra.css";
5 |
6 | .container {
7 | margin-bottom: 250px;
8 | }
9 |
10 | django-form-collection[sibling-position] {
11 | padding-top: 0.5rem;
12 | padding-bottom: 0.5rem;
13 | }
14 | django-form-collection[sibling-position]:not(:last-of-type) {
15 | border-bottom: 1px dashed light-dark(var(--bs-gray-400), var(--bs-gray-700));
16 | }
17 | django-form-collection[sibling-position] > .remove-collection {
18 | top: 0.25rem;
19 | }
20 | django-form-collection[sibling-position] > .collection-drag-handle ~ .remove-collection {
21 | top: 0.375rem;
22 | }
23 | .collection-siblings {
24 | border-bottom: 1px solid light-dark(var(--bs-gray-400), var(--bs-gray-700));
25 | margin-bottom: -9px;
26 | }
27 | .add-collection {
28 | margin-top: 0.75rem;
29 | margin-bottom: 0.75rem;
30 | }
31 |
32 | #id_some_date ~ .dj-calendar .monthdays > li {
33 | display: flex;
34 | flex-direction: column;
35 | }
36 | #id_some_date ~ .dj-calendar .monthdays > li > sub {
37 | height: 1em;
38 | bottom: 0;
39 | }
40 |
--------------------------------------------------------------------------------
/testapp/static/testapp/css/bulma.css:
--------------------------------------------------------------------------------
1 | @import "../../node_modules/bulma/css/bulma.min.css";
2 | @import "../../formset/css/collections.css";
3 |
4 |
5 | django-form-collection[sibling-position] {
6 | margin-top: 0.75rem;
7 | padding-top: 0.75rem;
8 | padding-top: 0.75rem;
9 | border-top: 1px solid #dbdbdb;
10 | }
11 |
--------------------------------------------------------------------------------
/testapp/static/testapp/css/debug.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: light-dark(white, black);
3 | color: light-dark(black, white);
4 | }
5 | /* use this stylesheet to see nesting levels on collections and their form validation status */
6 | .dj-form {
7 | padding: 0.5rem;
8 | border: 1px dotted grey;
9 | min-height: 1em;
10 | }
11 | form:valid + :is(.dj-form, fieldset) {
12 | border-color: rgba(0%, 100%, 0%, 0.5);
13 | }
14 | form:invalid + :is(.dj-form, fieldset) {
15 | border-color: rgba(100%, 0%, 0%, 0.5);
16 | }
17 |
18 | select:disabled {
19 | opacity: 0.5;
20 | }
21 |
22 | django-form-collection {
23 | padding: 0.5rem;
24 | border-left: 2px solid grey;
25 | border-right: 2px solid grey;
26 | display: block;
27 | }
28 | django-form-collection:first-of-type {
29 | border-top: 2px solid grey;
30 | }
31 | django-form-collection:last-of-type {
32 | border-bottom: 2px solid grey;
33 | margin-bottom: 0.5rem;
34 | }
35 | django-form-collection[sibling-position]:not(:first-of-type) {
36 | border-top: 2px dashed grey;
37 | }
38 |
39 | button.add-collection {
40 | margin-top: -0.5rem;
41 | margin-bottom: 0.5rem;
42 | }
43 | button.remove-collection {
44 | margin-top: 0.25rem;
45 | margin-bottom: 0.5rem;
46 | }
47 |
--------------------------------------------------------------------------------
/testapp/static/testapp/css/foundation.css:
--------------------------------------------------------------------------------
1 | @import "../../node_modules/foundation-sites/dist/css/foundation.min.css";
2 | @import "../../formset/css/collections.css";
3 |
4 | django-formset [role="group"] .dj-errorlist {
5 | margin-top: -0.75rem;
6 | margin-bottom: 0.75rem;
7 | }
8 |
9 | django-formset django-form-collection[sibling-position] {
10 | margin-top: 0.75rem;
11 | padding-top: 0.75rem;
12 | padding-top: 0.75rem;
13 | border-top: 1px solid var(--bs-gray-400);
14 | }
15 |
--------------------------------------------------------------------------------
/testapp/static/testapp/css/tailwind.css:
--------------------------------------------------------------------------------
1 | @import "/static/formset/css/tailwind.css";
2 | @import "/static/formset/css/collections.css";
3 |
4 | :root {
5 | --border-color: rgb(209 213 219);
6 | }
7 |
8 | django-form-collection[sibling-position] {
9 | padding-top: 0.25rem;
10 | margin-bottom: 0.25rem;
11 | }
12 | django-form-collection[sibling-position]:not(:last-of-type) {
13 | border-bottom: 1px dashed var(--border-color);
14 | }
15 | django-form-collection[sibling-position] > .remove-collection {
16 | top: -0.25rem;
17 | }
18 | django-form-collection[sibling-position] > .collection-drag-handle ~ .remove-collection {
19 | top: 0.25rem;
20 | }
21 | .collection-siblings {
22 | border-bottom: 1px solid var(--border-color);
23 | margin-bottom: -1px;
24 | }
25 | .add-collection {
26 | margin-top: 0.75rem;
27 | margin-bottom: 0.75rem;
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/testapp/static/testapp/css/uikit.css:
--------------------------------------------------------------------------------
1 | @import "../../node_modules/uikit/dist/css/uikit.min.css";
2 | @import "../../formset/css/collections.css";
3 |
4 | django-form-collection[sibling-position] {
5 | margin-top: 0.75rem;
6 | padding-top: 0.75rem;
7 | padding-top: 0.75rem;
8 | border-top: 1px solid grey;
9 | }
10 |
--------------------------------------------------------------------------------
/testapp/static/testapp/js/bootstrap-auto-dark-mode.js:
--------------------------------------------------------------------------------
1 | // check https://www.cssscript.com/automatic-dark-mode-bootstrap/ for details
2 | (function () {
3 | const htmlElement = document.querySelector("html");
4 | if(htmlElement.getAttribute("data-bs-theme") === 'auto') {
5 | function updateTheme() {
6 | document.querySelector("html").setAttribute("data-bs-theme",
7 | window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
8 | }
9 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme);
10 | updateTheme();
11 | }
12 | })();
13 |
--------------------------------------------------------------------------------
/testapp/static/testapp/tiptap-extensions/custom_hyperlink.js:
--------------------------------------------------------------------------------
1 | {
2 | name: 'custom_hyperlink',
3 | priority: 1000,
4 | keepOnSplit: false,
5 |
6 | addAttributes() {
7 | return {
8 | href: {
9 | default: null,
10 | },
11 | page_id: {
12 | default: null,
13 | },
14 | };
15 | },
16 |
17 | parseHTML() {
18 | return [{tag: 'a[href]:not([href *= "javascript:" i])'}];
19 | },
20 |
21 | renderHTML({HTMLAttributes}) {
22 | return ['a', HTMLAttributes, 0];
23 | },
24 | }
25 |
--------------------------------------------------------------------------------
/testapp/storage.py:
--------------------------------------------------------------------------------
1 | from django.contrib.staticfiles.storage import ManifestStaticFilesStorage
2 |
3 |
4 | class NoSourceMapsManifestStaticStorage(ManifestStaticFilesStorage):
5 | patterns = (
6 | (
7 | "*.css",
8 | (
9 | "(?Purl\\(['\"]{0,1}\\s*(?P.*?)[\"']{0,1}\\))",
10 | (
11 | "(?P@import\\s*[\"']\\s*(?P.*?)[\"'])",
12 | '@import url("%(url)s")',
13 | ),
14 | ),
15 | ),
16 | (
17 | "*.js",
18 | (
19 | ),
20 | ),
21 | )
22 |
--------------------------------------------------------------------------------
/testapp/templates/alternative-richtext/doc.html:
--------------------------------------------------------------------------------
1 |
2 | {% if node.content %}
3 | {% for item in node.content %}
4 | {% with template="richtext/"|add:item.type|lower|add:".html" %}
5 | {% include template with node=item %}
6 | {% endwith %}
7 | {% endfor %}
8 | {% endif %}
9 |
--------------------------------------------------------------------------------
/testapp/templates/bootstrap/base.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 | {% block "head" %}
7 |
8 |
9 | Django-Formset Demo
10 |
11 |
12 |
13 |
14 |
15 |
16 | {% endblock %}
17 |
18 |
19 |
20 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/testapp/templates/bootstrap/buttons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/testapp/templates/bootstrap/person-form.html:
--------------------------------------------------------------------------------
1 | {% extends "bootstrap/base.html" %}
2 | {% load render_form from formsetify %}
3 |
4 | {% block main-content %}
5 |
6 | {% render_form form "bootstrap" field_classes="row mb-3" label_classes="col-sm-3" control_classes="col-sm-9" %}
7 | {% include "bootstrap/buttons.html" %}
8 |
9 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/bulma/base.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 | Django-Formset Demo
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
28 | {{ doc }}
29 | {% block main-content %}{% endblock %}
30 | {% include "testapp/formset-data.html" %}
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/testapp/templates/bulma/buttons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/testapp/templates/calendar/weeks-moon.html:
--------------------------------------------------------------------------------
1 | {% extends "calendar/weeks.html" %}
2 |
3 | {% block sheet-body %}{% spaceless %}
4 |
5 |
6 | {% for abbr, weekday in calendar.weekdays %}
7 | - {{ abbr }}
8 | {% endfor %}
9 |
10 |
11 | {% for date, day, classes, phase in calendar.monthdays %}
12 | - {{ phase }} {{ day }}
13 | {% endfor %}
14 |
15 |
16 | {% endspaceless %}{% endblock %}
17 |
--------------------------------------------------------------------------------
/testapp/templates/calendar/weeks-reservation.html:
--------------------------------------------------------------------------------
1 | {% extends "calendar/weeks.html" %}
2 |
3 | {% block sheet-body %}{% spaceless %}
4 |
5 |
6 | {% for abbr, weekday in calendar.weekdays %}
7 | - {{ abbr }}
8 | {% endfor %}
9 |
10 |
11 | {% for date, day, classes, available in calendar.monthdays %}
12 | - {{ day }}
13 | {% endfor %}
14 |
15 |
16 | {% endspaceless %}{% endblock %}
17 |
--------------------------------------------------------------------------------
/testapp/templates/docutils.txt:
--------------------------------------------------------------------------------
1 | %(body)s
2 |
--------------------------------------------------------------------------------
/testapp/templates/foundation/base.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 | Django-Formset Demo
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
26 | {{ doc }}
27 |
28 | {% block main-content %}{% endblock %}
29 | {% include "testapp/formset-data.html" %}
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/testapp/templates/foundation/buttons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/testapp/templates/landing.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 | Django-Formset
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Django Formset Demo
19 |
20 |
Version {{ FORMSET_VERSION }}
21 |
Here is a list of forms and form collections to demonstrate all features the
22 | django-formset library currently offers.
23 |
Detailed documentation can be found on ReadTheDocs.
24 |
django-formset can work with any of the supported CSS frameworks, or with self-declared
25 | CSS classes. Please choose a CSS framework.
26 |
Currently only CSS frameworks Bootstrap and Tailwind are fully supported. Please help me to support the widgets in the remaining frameworks.
27 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/testapp/templates/richtext/marks/custom_hyperlink.html:
--------------------------------------------------------------------------------
1 | {% load page_url from hyperlink %}
2 | {{ text }}
--------------------------------------------------------------------------------
/testapp/templates/sphinx_view/page.html:
--------------------------------------------------------------------------------
1 | {% extends "sphinx_view/base.html" %}
2 |
3 | {% block main-content %}
4 |
5 |
6 |
7 | Back to top
8 |
9 |
10 |
11 |
18 |
19 |
23 |
24 |
25 | {% block doc %}{{ doc.body|safe }}{% endblock doc %}
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/testapp/templates/sphinx_view/search.html:
--------------------------------------------------------------------------------
1 | {% extends "sphinx_view/base.html" %}
2 | {% load static %}
3 |
4 | {% block title %}Search{% endblock title %}
5 |
6 | {% block main-content %}
7 |
8 | {% endblock %}
9 |
10 |
11 | {% block regular_scripts %}
12 | {{ block.super }}
13 |
14 |
15 |
16 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/success.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block main-content %}
4 | Submitted succesfully with this formset data:
5 | {{ valid_formset_data }}
6 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/tailwind/buttons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/base.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 | Django-Formset Demo
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 | {{ doc }}
21 | {% block main-content %}{% endblock %}
22 | {% include "testapp/formset-data.html" %}
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/button-actions.html:
--------------------------------------------------------------------------------
1 | {% extends framework|default:"testapp"|add:"/base.html" %}
2 | {% load render_form from formsetify %}
3 |
4 | {% block main-content %}
5 |
6 | {% render_form form framework form_classes=form_css_classes field_classes=field_css_classes fieldset_classes=fieldset_css_classes label_classes=label_css_classes|default:None control_classes=control_css_classes %}
7 | {% include framework|default:"testapp"|add:"/buttons.html" %}
8 |
9 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/buttons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/extended-form.html:
--------------------------------------------------------------------------------
1 | {% extends framework|default:"testapp"|add:"/base.html" %}
2 |
3 | {% block main-content %}
4 |
5 | {% include "formset/non_field_errors.html" %}
6 | {{ form }}
7 | {% include framework|default:"testapp"|add:"/buttons.html" %}
8 |
9 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/field-by-field.html:
--------------------------------------------------------------------------------
1 | {% extends framework|default:"testapp"|add:"/base.html" %}
2 | {% load formsetify %}
3 |
4 | {% block main-content %}
5 |
6 | {% include "formset/non_field_errors.html" %}
7 | {% formsetify form framework form_classes=form_css_classes field_classes=field_css_classes label_classes=label_css_classes|default:None control_classes=control_css_classes %}
8 |
9 | {% include "formset/non_field_errors.html" %}
10 | {% for field in form %}
11 | {% if field.is_hidden %}
12 | {{ field }}
13 | {% else %}
14 | {% include "formset/default/field_group.html" %}
15 | {% endif %}
16 | {% endfor %}
17 | {% include framework|default:"testapp"|add:"/buttons.html" %}
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/form-collection-no-buttons.html:
--------------------------------------------------------------------------------
1 | {% extends framework|default:"testapp"|add:"/base.html" %}
2 |
3 | {% block main-content %}
4 |
5 | {% include "formset/non_field_errors.html" %}
6 | {{ form_collection }}
7 |
8 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/form-collection.html:
--------------------------------------------------------------------------------
1 | {% extends framework|default:"testapp"|add:"/base.html" %}
2 |
3 | {% block main-content %}
4 |
5 | {% include "formset/non_field_errors.html" %}
6 | {{ form_collection }}
7 | {% include framework|default:"testapp"|add:"/buttons.html" %}
8 |
9 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/formset-data.html:
--------------------------------------------------------------------------------
1 | {% if valid_formset_data %}
2 |
3 | Submitted Formset Data:
4 | {{ valid_formset_data }}
5 | {% endif %}
6 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/house.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/index.html:
--------------------------------------------------------------------------------
1 | {% extends "testapp/base.html" %}
2 |
3 | {% block main-content %}
4 | Here is a list of examples to demonstrate the features django-formset
5 | currently offers.
6 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/margin-bottom.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/testapp/templates/testapp/native-form-no-buttons.html:
--------------------------------------------------------------------------------
1 | {% extends framework|default:"testapp"|add:"/base.html" %}
2 | {% load render_form from formsetify %}
3 |
4 | {% block main-content %}
5 |
6 | {% include "formset/non_field_errors.html" %}
7 | {% render_form form framework form_classes=form_css_classes field_classes=field_css_classes fieldset_classes=fieldset_css_classes label_classes=label_css_classes|default:None control_classes=control_css_classes %}
8 |
9 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/native-form-tiptap.html:
--------------------------------------------------------------------------------
1 | {% extends "./native-form.html" %}
2 | {% load render_form from formsetify %}
3 | {% load richtext %}
4 |
5 | {% block main-content %}
6 | {{ block.super }}
7 |
8 | {% render_richtext object.text framework='bootstrap' %}
9 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/native-form.html:
--------------------------------------------------------------------------------
1 | {% extends framework|default:"testapp"|add:"/base.html" %}
2 | {% load render_form from formsetify %}
3 |
4 | {% block main-content %}
5 |
6 | {% include "formset/non_field_errors.html" %}
7 | {% render_form form framework form_classes=form_css_classes field_classes=field_css_classes fieldset_classes=fieldset_css_classes label_classes=label_css_classes|default:None control_classes=control_css_classes %}
8 | {% include framework|default:"testapp"|add:"/buttons.html" %}
9 |
10 | {% endblock %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/tiptap-alternative.html:
--------------------------------------------------------------------------------
1 | {% load richtext %}{% render_richtext object.text "alternative-richtext/doc.html" %}
--------------------------------------------------------------------------------
/testapp/templates/testapp/tiptap.html:
--------------------------------------------------------------------------------
1 | {% load richtext %}{% render_richtext object.text %}
--------------------------------------------------------------------------------
/testapp/templates/uikit/base.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 | Django-Formset Demo
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {% block main-content %}{% endblock %}
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/testapp/templates/uikit/buttons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/testapp/templatetags/hyperlink.py:
--------------------------------------------------------------------------------
1 | from django import template
2 |
3 | from testapp.models import PageModel
4 |
5 | register = template.Library()
6 |
7 |
8 | @register.simple_tag
9 | def page_url(page_id):
10 | page = PageModel.objects.get(pk=page_id)
11 | return page.get_absolute_url()
12 |
--------------------------------------------------------------------------------
/testapp/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jrief/django-formset/25e03a3fbea6b53baa3b60d9932d4ef46b31e6e2/testapp/tests/__init__.py
--------------------------------------------------------------------------------
/testapp/tests/test_phone_number.py:
--------------------------------------------------------------------------------
1 | from django.template import Template, Context
2 |
3 |
4 | def test_format_phonenumber():
5 | template = Template('{% load phonenumber %}{{ value|format_phonenumber }}')
6 | context = Context({'value': '+49301234567'})
7 | assert template.render(context) == '+49 30 1234567'
8 |
9 |
10 | def test_format_national_phonenumber():
11 | template = Template('{% load phonenumber %}{{ value|format_phonenumber:"national" }}')
12 | context = Context({'value': '+12121234567'})
13 | assert template.render(context) == '(212) 123-4567'
14 |
15 |
16 | def test_format_international_phonenumber():
17 | template = Template('{% load phonenumber %}{{ value|format_phonenumber:"international" }}')
18 | context = Context({'value': '+442012345678'})
19 | assert template.render(context) == '+44 20 1234 5678'
20 |
--------------------------------------------------------------------------------
/testapp/tests/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.urls import path
4 | from django.views.i18n import JavaScriptCatalog
5 |
6 |
7 | use_monolithic_build = os.environ.get('PYTEST_USE_MONOLITHIC_BUILD') == '1'
8 |
9 |
10 | class ContextMixin:
11 | def get_context_data(self, **kwargs):
12 | context = super().get_context_data(**kwargs)
13 | context.update(use_monolithic_build=use_monolithic_build)
14 | return context
15 |
16 |
17 | def get_javascript_catalog():
18 | return path(
19 | 'jsi18n/myapp/',
20 | JavaScriptCatalog.as_view(packages=['formset']),
21 | name='javascript-catalog',
22 | )
23 |
--------------------------------------------------------------------------------
/testapp/wsgi.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | from django.core.wsgi import get_wsgi_application
5 |
6 | sys.path.insert(0, os.path.abspath(os.path.join(os.pardir)))
7 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
8 |
9 | application = get_wsgi_application()
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2019",
4 | "module": "esnext",
5 | "moduleResolution": "node",
6 | "noEmitOnError": true,
7 | "lib": ["esnext", "dom", "dom.iterable"],
8 | "strict": true,
9 | "esModuleInterop": false,
10 | "allowJs": false,
11 | "allowSyntheticDefaultImports": true,
12 | "experimentalDecorators": true,
13 | "importHelpers": true,
14 | "rootDir": "./",
15 | "baseUrl": "./client",
16 | "declaration": false,
17 | "declarationMap": false,
18 | "incremental": true
19 | },
20 | "include": [
21 | "**/*.ts"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------