From 3f900617c89c4deafe831950f05c72f421ffdb2d Mon Sep 17 00:00:00 2001 From: Jaap Joris Vens Date: Fri, 14 Feb 2020 17:20:41 +0100 Subject: [PATCH] Re-introduce formsets No more clicking individual sections to edit them. From now on, there will only be one edit button! The biggest challenge was getting the javascript closures to understand. --- cms/forms.py | 13 +++- cms/static/cms/cms.scss | 4 +- cms/static/cms/cms.scss.css | 4 +- cms/templates/cms/confirm.html | 39 ++++++++++ cms/templates/cms/edit.html | 74 +++++++++++++------ cms/templates/cms/formfield.html | 2 +- cms/templates/cms/page.html | 10 --- cms/views.py | 32 +++++++- .../app/templates/app/sections/button.html | 2 - .../app/templates/app/sections/contact.html | 3 - example/app/templates/app/sections/image.html | 3 - example/app/templates/app/sections/text.html | 2 - example/app/templates/app/sections/video.html | 3 - 13 files changed, 135 insertions(+), 56 deletions(-) create mode 100644 cms/templates/cms/confirm.html diff --git a/cms/forms.py b/cms/forms.py index eb3403a..09168d0 100644 --- a/cms/forms.py +++ b/cms/forms.py @@ -2,6 +2,7 @@ import swapper from django import forms from django.contrib.contenttypes.models import ContentType from django.core.mail import EmailMessage +from django.forms import inlineformset_factory from django.utils.translation import gettext_lazy as _ Page = swapper.load_model('cms', 'Page') @@ -42,8 +43,13 @@ class SectionForm(forms.ModelForm): # Repopulate the 'choices' attribute of the type field from # the child model. self.fields['type'].choices = self._meta.model.TYPES + self.fields['type'].initial = self._meta.model.TYPES[0][0] - def save(self): + def delete(self): + instance = super().save() + instance.delete() + + def save(self, commit=True): section = super().save() # Explanation: get the content type of the model that the user @@ -56,7 +62,8 @@ class SectionForm(forms.ModelForm): model=section.type.lower(), ) - section.save() + if commit: + section.save() return section class Meta: @@ -69,3 +76,5 @@ class SectionForm(forms.ModelForm): # There is definitely a bug in Django, since the above 'field_classes' gets # ignored entirely. Workaround to force a ChoiceField anyway: type = forms.ChoiceField() + +SectionFormSet = inlineformset_factory(Page, Section, form=SectionForm, extra=1) diff --git a/cms/static/cms/cms.scss b/cms/static/cms/cms.scss index 195acb5..ca55dfe 100644 --- a/cms/static/cms/cms.scss +++ b/cms/static/cms/cms.scss @@ -289,12 +289,12 @@ form.cms { clear: both; box-sizing: border-box; - &#type, &#number { + &.type, &.number { width: 75%; clear: none; float: left; } - &#number { + &.number { width: 20%; float: right; } diff --git a/cms/static/cms/cms.scss.css b/cms/static/cms/cms.scss.css index a4e7b3f..1bafd6b 100644 --- a/cms/static/cms/cms.scss.css +++ b/cms/static/cms/cms.scss.css @@ -206,11 +206,11 @@ form.cms div.formfield { padding: 10px 0; clear: both; box-sizing: border-box; } - form.cms div.formfield#type, form.cms div.formfield#number { + form.cms div.formfield.type, form.cms div.formfield.number { width: 75%; clear: none; float: left; } - form.cms div.formfield#number { + form.cms div.formfield.number { width: 20%; float: right; } diff --git a/cms/templates/cms/confirm.html b/cms/templates/cms/confirm.html new file mode 100644 index 0000000..b1e0e0c --- /dev/null +++ b/cms/templates/cms/confirm.html @@ -0,0 +1,39 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block content %} +
+ {% csrf_token %} + {{form.media}} + +
+
+ {% if protected %} +
+

You can't do that

+
+ + In order to delete this page, you will first need to delete the following sections: + +
    + {{protected|unordered_list}} +
+ + {% else %} +
+

Are you sure?

+
+ + The following objects will be deleted: + +
    + {{deleted|unordered_list}} +
+ + + {% endif %} + +
+
+
+{% endblock %} diff --git a/cms/templates/cms/edit.html b/cms/templates/cms/edit.html index 2cd8337..4411dfd 100644 --- a/cms/templates/cms/edit.html +++ b/cms/templates/cms/edit.html @@ -5,6 +5,9 @@
{% csrf_token %} {{form.media}} +
+ +
@@ -19,6 +22,17 @@ {% for field in form %} {% include 'cms/formfield.html' with field=field %} {% endfor %} + {% if form.instance.pk %} +
+
+ +
+
+ +
+
+ {% endif %} +
@@ -32,27 +46,19 @@

{{form.instance}}

- {% for field in form.visible_fields %} - {% include 'cms/formfield.html' with field=field %} - {% endfor %} +
+ {% for field in form.visible_fields %} + {% if field.name == 'DELETE' and not form.instance.pk %} + + {% else %} + {% include 'cms/formfield.html' with field=field counter=forloop.parentloop.counter0 %} + {% endif %} + {% endfor %} +
{% endfor %} - -
- -
{% endif %} - -
- -
{% endblock %} @@ -61,7 +67,6 @@ {% endblock %} diff --git a/cms/templates/cms/formfield.html b/cms/templates/cms/formfield.html index a0f7965..bfbcb5e 100644 --- a/cms/templates/cms/formfield.html +++ b/cms/templates/cms/formfield.html @@ -1,4 +1,4 @@ -
+
{{field.errors}}
diff --git a/cms/templates/cms/page.html b/cms/templates/cms/page.html index 373498b..9d9734e 100644 --- a/cms/templates/cms/page.html +++ b/cms/templates/cms/page.html @@ -21,14 +21,4 @@ {% endif %}
- {% if user.is_staff %} -
- -
- {% endif %} - {% endblock %} diff --git a/cms/views.py b/cms/views.py index c0d333e..5e6d7a8 100644 --- a/cms/views.py +++ b/cms/views.py @@ -4,13 +4,14 @@ import swapper from django.views import generic from django.shortcuts import redirect from django.views.generic.edit import FormMixin +from django.contrib.admin.utils import NestedObjects from django.core.exceptions import ImproperlyConfigured from django.contrib.contenttypes.models import ContentType from django.contrib.auth.mixins import UserPassesTestMixin from django.http import HttpResponseRedirect, HttpResponseBadRequest from .decorators import register_view -from .forms import PageForm, SectionForm +from .forms import PageForm, SectionForm, SectionFormSet Page = swapper.load_model('cms', 'Page') Section = swapper.load_model('cms', 'Section') @@ -138,13 +139,38 @@ class BaseUpdateView(generic.UpdateView): template_name = 'cms/edit.html' def form_valid(self, form): - form.save() + if 'delete' in self.request.POST: + collector = NestedObjects(using='default') + collector.collect([self.object]) + self.template_name = 'cms/confirm.html' + return self.render_to_response(self.get_context_data(deleted=collector.nested(), protected=collector.protected)) + else: + form.save() return redirect(self.request.session.get('previous_url')) -class UpdatePage(StaffRequiredMixin, MenuMixin, BaseUpdateView): +class UpdatePage(StaffRequiredMixin, TypeMixin, BaseUpdateView): model = Page form_class = PageForm + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + if 'formset' not in context: + context['formset'] = SectionFormSet(instance=self.object) + return context + + def post(self, request, *args, **kwargs): + self.object = self.get_object() + form = self.get_form() + formset = SectionFormSet(request.POST, request.FILES, instance=self.object) + if form.is_valid() and formset.is_valid(): + formset.save() + return self.form_valid(form) + else: + return self.form_invalid(form, formset) + + def form_invalid(self, form, formset): + return self.render_to_response(self.get_context_data(form=form, formset=formset)) + class UpdateSection(StaffRequiredMixin, TypeMixin, BaseUpdateView): model = Section form_class = SectionForm diff --git a/example/app/templates/app/sections/button.html b/example/app/templates/app/sections/button.html index 9d379db..7af698d 100644 --- a/example/app/templates/app/sections/button.html +++ b/example/app/templates/app/sections/button.html @@ -5,7 +5,5 @@ {{section.button_text}}
{% endif %} - - {% include 'cms/editlink.html' %} diff --git a/example/app/templates/app/sections/contact.html b/example/app/templates/app/sections/contact.html index ad40559..7bb4a21 100644 --- a/example/app/templates/app/sections/contact.html +++ b/example/app/templates/app/sections/contact.html @@ -1,5 +1,4 @@ {% load i18n %} -
@@ -15,7 +14,5 @@
- - {% include 'cms/editlink.html' %}
diff --git a/example/app/templates/app/sections/image.html b/example/app/templates/app/sections/image.html index f74037e..fbf7da2 100644 --- a/example/app/templates/app/sections/image.html +++ b/example/app/templates/app/sections/image.html @@ -2,13 +2,10 @@
- {% if section.image %}
{{section.title}}
{% endif %} - - {% include 'cms/editlink.html' %}
diff --git a/example/app/templates/app/sections/text.html b/example/app/templates/app/sections/text.html index e6a063a..a323a9c 100644 --- a/example/app/templates/app/sections/text.html +++ b/example/app/templates/app/sections/text.html @@ -15,7 +15,5 @@ {{section.content|markdown}} {% endif %} - - {% include 'cms/editlink.html' %} diff --git a/example/app/templates/app/sections/video.html b/example/app/templates/app/sections/video.html index dd88766..a185ac1 100644 --- a/example/app/templates/app/sections/video.html +++ b/example/app/templates/app/sections/video.html @@ -2,7 +2,6 @@
- {% if section.video %}
@@ -10,7 +9,5 @@
{% endif %} - - {% include 'cms/editlink.html' %}