Ensure that form media required by InlinePanels is correctly pulled in to the edit page - fixes #2662.

Based on code from #2659 by @Gagaro - thanks!
pull/2673/merge
Matt Westcott 2016-06-03 14:26:19 +01:00 zatwierdzone przez Mikalai Radchuk
rodzic c39f830ae2
commit 892c4c77d6
10 zmienionych plików z 156 dodań i 2 usunięć

Wyświetl plik

@ -13,6 +13,7 @@ Changelog
* Fix: When editing a document link in rich text, the document ID is no longer erroneously interpreted as a page ID (Stephen Rice)
* Fix: Removing embedded media from rich text by mouse click action now gets correctly registered as a change to the field (Loic Teixeira)
* Fix: Rich text editor is no longer broken in InlinePanels (Matt Westcott, Yann Fouillat)
1.5 (31.05.2016)

Wyświetl plik

@ -139,6 +139,7 @@ Contributors
* Robert Moggach
* Stephen Rice
* Behzad Nategh
* Yann Fouillat
Translators
===========

Wyświetl plik

@ -16,4 +16,4 @@ Bug fixes
* When editing a document link in rich text, the document ID is no longer erroneously interpreted as a page ID (Stephen Rice)
* Removing embedded media from rich text by mouse click action now gets correctly registered as a change to the field (Loic Teixeira)
* Rich text editor is no longer broken in InlinePanels (Matt Westcott, Yann Fouillat)

Wyświetl plik

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import wagtail.wagtailcore.fields
import modelcluster.fields
class Migration(migrations.Migration):
dependencies = [
('snippetstests', '0004_fileuploadsnippet'),
]
operations = [
migrations.CreateModel(
name='MultiSectionRichTextSnippet',
fields=[
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='RichTextSection',
fields=[
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
('body', wagtail.wagtailcore.fields.RichTextField()),
('snippet', modelcluster.fields.ParentalKey(to='snippetstests.MultiSectionRichTextSnippet', related_name='sections')),
],
),
]

Wyświetl plik

@ -2,7 +2,11 @@ from __future__ import absolute_import, unicode_literals
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
from wagtail.wagtailadmin.edit_handlers import FieldPanel, InlinePanel
from wagtail.wagtailcore.fields import RichTextField
from wagtail.wagtailsearch import index
from wagtail.wagtailsnippets.models import register_snippet
@ -71,3 +75,19 @@ class FancySnippet(models.Model):
@register_snippet
class FileUploadSnippet(models.Model):
file = models.FileField()
class RichTextSection(models.Model):
snippet = ParentalKey('MultiSectionRichTextSnippet', related_name='sections')
body = RichTextField()
panels = [
FieldPanel('body'),
]
@register_snippet
class MultiSectionRichTextSnippet(ClusterableModel):
panels = [
InlinePanel('sections'),
]

Wyświetl plik

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import modelcluster.fields
import wagtail.wagtailcore.fields
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0029_unicode_slugfield_dj19'),
('tests', '0005_customrichblockfieldpage_customrichtextfieldpage_defaultrichblockfieldpage_defaultrichtextfieldpage'),
]
operations = [
migrations.CreateModel(
name='SectionedRichTextPage',
fields=[
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='SectionedRichTextPageSection',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
('sort_order', models.IntegerField(editable=False, null=True, blank=True)),
('body', wagtail.wagtailcore.fields.RichTextField()),
('page', modelcluster.fields.ParentalKey(related_name='sections', to='tests.SectionedRichTextPage')),
],
options={
'ordering': ['sort_order'],
'abstract': False,
},
),
]

Wyświetl plik

@ -708,3 +708,21 @@ class CustomRichBlockFieldPage(Page):
FieldPanel('title', classname="full title"),
StreamFieldPanel('body'),
]
# a page that only contains RichTextField within an InlinePanel,
# to test that the inline child's form media gets pulled through
class SectionedRichTextPageSection(Orderable):
page = ParentalKey('tests.SectionedRichTextPage', related_name='sections')
body = RichTextField()
panels = [
FieldPanel('body')
]
class SectionedRichTextPage(Page):
content_panels = [
FieldPanel('title', classname="full title"),
InlinePanel('sections')
]

Wyświetl plik

@ -13,6 +13,7 @@ from django.db import models, transaction
from django.forms.widgets import TextInput
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.six import with_metaclass
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy, ungettext
from modelcluster.forms import ClusterForm, ClusterFormMetaclass
@ -254,7 +255,16 @@ class WagtailAdminModelFormMetaclass(ClusterFormMetaclass):
new_class = super(WagtailAdminModelFormMetaclass, cls).__new__(cls, name, bases, attrs)
return new_class
WagtailAdminModelForm = WagtailAdminModelFormMetaclass(str('WagtailAdminModelForm'), (ClusterForm,), {})
class WagtailAdminModelForm(with_metaclass(WagtailAdminModelFormMetaclass, ClusterForm)):
@property
def media(self):
# Include media from formsets forms. This allow StreamField in InlinePanel for example.
media = super(WagtailAdminModelForm, self).media
for formset in self.formsets.values():
media += formset.media
return media
# Now, any model forms built off WagtailAdminModelForm instead of ModelForm should pick up
# the nice form fields defined in FORM_FIELD_OVERRIDES.

Wyświetl plik

@ -2956,3 +2956,22 @@ class TestIssue2599(TestCase, WagtailTestUtils):
self.assertEqual(response.context['self'].depth, homepage.depth + 1)
self.assertTrue(response.context['self'].path.startswith(homepage.path))
self.assertEqual(response.context['self'].get_parent(), homepage)
class TestInlinePanelMedia(TestCase, WagtailTestUtils):
"""
Test that form media required by InlinePanels is correctly pulled in to the edit page
"""
def test_inline_panel_media(self):
homepage = Page.objects.get(id=2)
self.login()
# simplepage does not need hallo...
response = self.client.get(reverse('wagtailadmin_pages:add', args=('tests', 'simplepage', homepage.id)))
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, 'wagtailadmin/js/hallo-bootstrap.js')
# but sectionedrichtextpage does
response = self.client.get(reverse('wagtailadmin_pages:add', args=('tests', 'sectionedrichtextpage', homepage.id)))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'wagtailadmin/js/hallo-bootstrap.js')

Wyświetl plik

@ -651,3 +651,15 @@ class TestSnippetEditHandlers(TestCase, WagtailTestUtils):
form_class = edit_handler_class.get_form_class(FancySnippet)
self.assertTrue(issubclass(form_class, WagtailAdminModelForm))
self.assertTrue(issubclass(form_class, FancySnippetForm))
class TestInlinePanelMedia(TestCase, WagtailTestUtils):
"""
Test that form media required by InlinePanels is correctly pulled in to the edit page
"""
def test_inline_panel_media(self):
self.login()
response = self.client.get(reverse('wagtailsnippets:add', args=('snippetstests', 'multisectionrichtextsnippet')))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'wagtailadmin/js/hallo-bootstrap.js')