Giter Site home page Giter Site logo

wagtail-deprecated / wagtail-react-streamfield Goto Github PK

View Code? Open in Web Editor NEW
73.0 25.0 23.0 1.43 MB

Powerful field for inserting multiple blocks with nesting. (NO LONGER MAINTAINED - See Wagtail 2.13 Release Notes)

Home Page: https://wagtail.github.io/react-streamfield/public/

License: BSD 3-Clause "New" or "Revised" License

Python 56.59% JavaScript 37.21% HTML 0.93% SCSS 5.27%
react streamfield wagtail

wagtail-react-streamfield's People

Contributors

bertrandbordage avatar colinappnovation avatar lb- avatar mwesterhof avatar pyneda avatar roelio avatar shagrat avatar thibaudcolas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wagtail-react-streamfield's Issues

Fields with default values not saving properly

When adding a field (such as a ChoiceBlock) that has a default value to a page
the default value appears in the field (visually) but is not set when the page is saved.
This causes a validation error as no value is being set.

Version: 0.8.5

Steps to Reproduce:

  1. Create new page and add a block (ChoiceBlock or CharBlock in this case) that contains a default value.
  2. Save the page.

Result: A validation error occurs on the field.

Expected Result: The page saves with the default value in the field.

Workaround: Select different value in choices and the reselect default value. Page then saves without error.

Here is a sample of the code used to recreate this issue:

class TestStreamBlock(StreamBlock):
    NUMBERS = (('one', 'one'), ('two', 'two'),)

    time = TimeBlock()
    name = CharBlock(default='Test Name 1')
    number = ChoiceBlock(max_length=3, choices=NUMBERS, default=NUMBERS[0])

class TestPage(Page):
    content = StreamField(TestStreamBlock(required=False),blank=True)

    content_panels = Page.content_panels + [
        StreamFieldPanel('content'),
    ]

FieldBlock created for MultiValueField instance throws javascript error.

I'm creating a StructBlock with a Django SplitDateTimeField form field like this:

class EventBlock(blocks.StructBlock):
    title = blocks.CharBlock()
    text = blocks.TextBlock()
    datetime = SplitDateTimeBlock()

So I implemented the SplitDateTimeBlock() to wrap the SplitDateTimeField like this:

class SplitDateTimeBlock(FieldBlock):
    def __init__(self, *args, **kwargs):
        self.field = SplitDateTimeField(*args, **kwargs)
        super().__init__(*args, **kwargs)

But SplitDateTimeField extends from MultiValueField and it seems to be causing an error. When I click to add the EventBlock I get a javascript error (below) and the page goes blank.

image

Do you know why this is happening? Is there a way to get wagtail react streamfield to support FieldBlocks based on MultiValueField form fields?

Cannot display properties from SnippetChooserPanel in titleTemplate

I have a very simply structblock:

class MemberRoleBlock(BaseBlockMixin, blocks.StructBlock):
    member= SnippetChooserBlock(target_model='members.Member', required=True)
    role = blocks.CharBlock(required=False)

    @property
    def definition(self):
        definition = super(PersonRoleBlock, self).definition
        definition['titleTemplate'] = "${member}"
        return definition

... but I have to display the name of the member as the title when the block is collasped. The problem is that the value for member at this stage is the id. Is there any hack, monkey patch, really, any solution to get the actual member.name field displayed as the title? I am completely stuck.

issue loading pages in admin with react_streamfield after upgrade to wagtail 2.3

after upgrading to wagtail 2.3 this morning, my pages with react_streamfield would no longer load in the editor although they would still render regular page calls. My pages without streamfields loaded in the editor as normal.

here is the error output
Request Method: | GET

http://localhost:8000/admin/pages/16/edit/
wagtail version 2.0.8
TypeError
render_with_errors() got an unexpected keyword argument 'renderer'

Error during template rendering

In template C:\Users\Student\Envs\CMS\lib\site-packages\wagtail\admin\templates\wagtailadmin\shared\field.html, error at line 7

while maybe not obvious in Traceback below, the last steps of trace with local vars show attempting to form NewBlockWidget for react_streamfield but fails a couple steps later on key error 'renderer' which looks to be pased in kwargs
local vars:
bound_field | <django.forms.boundfield.BoundField object at 0x000000000EDA35F8>
widget | <wagtail_react_streamfield.widgets.NewBlockWidget object at 0x000000000EDDF588>

Traceback:
Environment:
Request Method: GET
Request URL: http://localhost:8000/admin/pages/16/edit/

Django Version: 2.0.8
Python Version: 3.6.5
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
'wagtail.contrib.forms',
'wagtail.contrib.redirects',
'wagtail.contrib.routable_page',
'wagtail.contrib.styleguide',
'wagtail.contrib.modeladmin',
'wagtail.contrib.settings',
'wagtailmenus',
'wagtail_react_streamfield',
'wagtail.embeds',
'wagtail.sites',
'wagtail.users',
'wagtail.snippets',
'wagtail.documents',
'wagtail.images',
'wagtailcodeblock',
'wagtail.search',
'wagtail.admin',
'wagtail.core',
'modelcluster',
'taggit',
'taggit_templatetags2',
'el_pagination',
'treebeard',
'widget_tweaks',
'home',
'blog',
'projects']
Installed Middleware:
['django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'wagtail.core.middleware.SiteMiddleware',
'wagtail.contrib.redirects.middleware.RedirectMiddleware']

Template error:
In template ....~\Envs\CMS\lib\site-packages\wagtail\admin\templates\wagtailadmin\shared\field.html, error at line 7
render_with_errors() got an unexpected keyword argument 'renderer'
1 : {% load wagtailadmin_tags %}
2 :


3 : {% if show_label|default_if_none:True %}{{ field.label_tag }}{% endif %}
4 :

5 :

6 : {% block form_field %}
7 : {{ field|render_with_errors }}
8 : {% endblock %}
9 :
10 : {# This span only used on rare occasions by certain types of input #}
11 :
12 :

13 : {% if show_help_text|default_if_none:True and field.help_text %}
14 :

{{ field.help_text }}


15 : {% endif %}
16 :
17 : {% if field|has_unrendered_errors %}

Traceback:

File "....~\Envs\CMS\lib\site-packages\django\core\handlers\exception.py" in inner
35. response = get_response(request)

File "....~\Envs\CMS\lib\site-packages\django\core\handlers\base.py" in _get_response
128. response = self.process_exception_by_middleware(e, request)

File "....~\Envs\CMS\lib\site-packages\django\core\handlers\base.py" in _get_response
126. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "....~\Envs\CMS\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
44. response = view_func(request, *args, **kwargs)

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\urls_init_.py" in wrapper
102. return view_func(request, *args, **kwargs)

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\decorators.py" in decorated_view
34. return view_func(request, *args, **kwargs)

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\views\pages.py" in edit
537. 'has_unsaved_changes': has_unsaved_changes,

File "....~\Envs\CMS\lib\site-packages\django\shortcuts.py" in render
36. content = loader.render_to_string(template_name, context, request, using=using)

File "....~\Envs\CMS\lib\site-packages\django\template\loader.py" in render_to_string
62. return template.render(context, request)

File "....~\Envs\CMS\lib\site-packages\django\template\backends\django.py" in render
61. return self.template.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
175. return self._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\loader_tags.py" in render
155. return compiled_parent._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\loader_tags.py" in render
155. return compiled_parent._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\loader_tags.py" in render
155. return compiled_parent._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\loader_tags.py" in render
67. result = block.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\loader_tags.py" in render
67. result = block.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
993. output = self.filter_expression.resolve(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in resolve
676. obj = self.var.resolve(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in resolve
802. value = self._resolve_lookup(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _resolve_lookup
864. current = current()

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\edit_handlers.py" in render_form_content
230. return mark_safe(self.render_as_object() + self.render_missing_fields())

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\edit_handlers.py" in render_as_object
198. return self.render()

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\edit_handlers.py" in render
299. 'self': self

File "....~\Envs\CMS\lib\site-packages\django\template\loader.py" in render_to_string
62. return template.render(context, request)

File "....~\Envs\CMS\lib\site-packages\django\template\backends\django.py" in render
61. return self.template.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
175. return self._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\defaulttags.py" in render
211. nodelist.append(node.render_annotated(context))

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
993. output = self.filter_expression.resolve(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in resolve
676. obj = self.var.resolve(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in resolve
802. value = self._resolve_lookup(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _resolve_lookup
864. current = current()

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\edit_handlers.py" in render_as_object
198. return self.render()

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\edit_handlers.py" in render
299. 'self': self

File "....~\Envs\CMS\lib\site-packages\django\template\loader.py" in render_to_string
62. return template.render(context, request)

File "....~\Envs\CMS\lib\site-packages\django\template\backends\django.py" in render
61. return self.template.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
175. return self._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\defaulttags.py" in render
211. nodelist.append(node.render_annotated(context))

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
993. output = self.filter_expression.resolve(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in resolve
676. obj = self.var.resolve(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in resolve
802. value = self._resolve_lookup(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _resolve_lookup
864. current = current()

File "....~\Envs\CMS\lib\site-packages\wagtail\admin\edit_handlers.py" in render_as_object
457. 'field': self.bound_field,

File "....~\Envs\CMS\lib\site-packages\django\template\loader.py" in render_to_string
62. return template.render(context, request)

File "....~\Envs\CMS\lib\site-packages\django\template\backends\django.py" in render
61. return self.template.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
175. return self._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\loader_tags.py" in render
194. return template.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
177. return self._render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\loader_tags.py" in render
58. result = self.nodelist.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in render
993. output = self.filter_expression.resolve(context)

File "....~\Envs\CMS\lib\site-packages\django\template\base.py" in resolve
703. new_obj = func(obj, *arg_vals)

Fle "....~\Envs\CMS\lib\site-packages\wagtail\admin\templatetags\wagtailadmin_tags.py" in render_with_errors
244. return bound_field.as_widget()

File "....~\Envs\CMS\lib\site-packages\django\forms\boundfield.py" in as_widget
118. **kwargs

File "....~\Envs\CMS\lib\site-packages\wagtail\core\blocks\base.py" in render
505. return self.render_with_errors(name, value, attrs=attrs, errors=None, renderer=renderer)

Exception Type: TypeError at /admin/pages/16/edit/
Exception Value: render_with_errors() got an unexpected keyword argument 'renderer'

Validation error messages for stream fields not shown

When trying to save a page with an invalid stream field (e.g. required blocks missing or less / more blocks than allowed inside the stream field), the error message/s is/are not shown

validation error message for stream field missing

This might arise from this: in 'classic' wagtail, the error messages (block_errors) are contained in the 'sequence-container' (admin\templates\wagtailadmin\block_forms\sequence.html) which does not appear with wagtail-react-streamfield installed.

No ability to add streamfield items within an inline panel without min_num=1

Hi guys

I found a bug today, defining:

class MyPageFooItem(Orderable):
    page = ParentalKey(..., related_name='foos')
    content = StreamField([...])

    panels = [
        StreamFieldPanel('content'),
    ]

class MyPage(Page):
    ...
    content_panels = Page.content_panels + [
        InlinePanel('foos', label="Foos"),
    ]

renders no options to add any item from the streamfield within the inline panel. You just get a label Foos:. If you then oddly add min_num=1 to the inline they appear and you can happily add content:

class MyPage(Page):
    ...
    content_panels = Page.content_panels + [
        InlinePanel('foos', label="Foos", min_num=1),
    ]

Im guessing its prob a js thing in that with min_num=1 one will be on the page already.

Also adding a second inline via the button renders no content till you try to save it.

Cheers
Stu

Validation error in ListBlock element causing an exception

I got the same error now as #32 , using the latest version

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\blocks\struct_block.py" in prepare_value
66. else children_errors.get(k))
Exception Type: AttributeError at /admin/pages/3/edit/
Exception Value: 'list' object has no attribute 'get'

The block itself is quite simple:

class TopNewsItem(BaseBlockMixin, blocks.StructBlock):
    date = blocks.CharBlock(label=_('Date (or tag)'), required=False)
    title = blocks.CharBlock(label=_('Title'), required=True)
    subtitle = blocks.CharBlock(label=_('Subtitle'), required=False)
    picture = ImageChooserBlock(label=_('Picture'), required=True)
    label = blocks.CharBlock(label=_('Tab label'), required=False)

    details_url = blocks.URLBlock(label=_('Link to details page'), required=False)

    class Meta:
        closed = True


class TopNewsBlock(BaseBlockMixin, blocks.ListBlock):
    class Meta:
        icon = "media"
        closed = True

Used as:

body = StreamField(
    ('topnews', TopNewsBlock(label=_("Top carousel block"),  child_block=TopNewsItem(label=_("Carousel element"))))
    blank=True, 
    null=True
)

Wagtail 2.6.1, wagtail-react-streamfield 1.3.4

Full traceback:

File "C:\virtualenv\wagtailcms\lib\site-packages\django\core\handlers\exception.py" in inner
  34.             response = get_response(request)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\core\handlers\base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\core\handlers\base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\urls\__init__.py" in wrapper
  102.             return view_func(request, *args, **kwargs)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\decorators.py" in decorated_view
  34.             return view_func(request, *args, **kwargs)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\views\pages.py" in edit
  545.         'has_unsaved_changes': has_unsaved_changes,

File "C:\virtualenv\wagtailcms\lib\site-packages\django\shortcuts.py" in render
  36.     content = loader.render_to_string(template_name, context, request, using=using)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader.py" in render_to_string
  62.     return template.render(context, request)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\backends\django.py" in render
  61.             return self.template.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  171.                     return self._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  62.                 result = block.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  62.                 result = block.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in resolve
  671.                 obj = self.var.resolve(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in resolve
  796.             value = self._resolve_lookup(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _resolve_lookup
  858.                             current = current()

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\edit_handlers.py" in render_form_content
  252.         return mark_safe(self.render_as_object() + self.render_missing_fields())

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\edit_handlers.py" in render_as_object
  220.         return self.render()

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\edit_handlers.py" in render
  324.             'self': self

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader.py" in render_to_string
  62.     return template.render(context, request)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\backends\django.py" in render
  61.             return self.template.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  171.                     return self._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\defaulttags.py" in render
  209.                     nodelist.append(node.render_annotated(context))

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in resolve
  671.                 obj = self.var.resolve(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in resolve
  796.             value = self._resolve_lookup(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _resolve_lookup
  858.                             current = current()

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\edit_handlers.py" in render_as_object
  220.         return self.render()

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\edit_handlers.py" in render
  324.             'self': self

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader.py" in render_to_string
  62.     return template.render(context, request)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\backends\django.py" in render
  61.             return self.template.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  171.                     return self._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\defaulttags.py" in render
  209.                     nodelist.append(node.render_annotated(context))

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in resolve
  671.                 obj = self.var.resolve(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in resolve
  796.             value = self._resolve_lookup(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _resolve_lookup
  858.                             current = current()

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\edit_handlers.py" in render_as_object
  482.             'field': self.bound_field,

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader.py" in render_to_string
  62.     return template.render(context, request)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\backends\django.py" in render
  61.             return self.template.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  171.                     return self._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  188.             return template.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  173.                 return self._render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in _render
  163.         return self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\loader_tags.py" in render
  53.                 result = self.nodelist.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  937.                 bit = node.render_annotated(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render_annotated
  904.             return self.render(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "C:\virtualenv\wagtailcms\lib\site-packages\django\template\base.py" in resolve
  698.                 new_obj = func(obj, *arg_vals)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail\admin\templatetags\wagtailadmin_tags.py" in render_with_errors
  248.             errors=bound_field.errors

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\widgets.py" in render_with_errors
  94.         streamfield_config = self.get_streamfield_config(value, errors=errors)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\widgets.py" in get_streamfield_config
  89.             'value': self.block_def.prepare_value(value, errors=errors),

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\monkey_patch.py" in inner
  19.             return new_method(*args, **kwargs)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\blocks\stream_block.py" in prepare_value
  70.                                                    errors=child_errors),

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\monkey_patch.py" in inner
  19.             return new_method(*args, **kwargs)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\blocks\list_block.py" in prepare_value
  70.                                                         errors=errors),

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\monkey_patch.py" in inner
  19.             return new_method(*args, **kwargs)

File "C:\virtualenv\wagtailcms\lib\site-packages\wagtail_react_streamfield\blocks\struct_block.py" in prepare_value
  66.                             else children_errors.get(k))

Exception Type: AttributeError at /admin/pages/3/edit/
Exception Value: 'list' object has no attribute 'get'

Django dropped support for django.utils.six

File "/home/lennart/Envs/wagtailTest/lib/python3.6/site-packages/wagtail_react_streamfield/monkey_patch.py", line 1, in <module>
    from django.utils.six import wraps
ModuleNotFoundError: No module named 'django.utils.six'

django >= 3 no longer supports django.utils.six

Issues rendering StreamBlock and ListBlock as children of StreamField

While trying the new stream field UI I encountered problems with the following model:

class Test(Page):
    content = StreamField([
        ('blockA', blocks.StreamBlock([
            ('subBlockA', blocks.BooleanBlock())
        ])),
        ('blockB', blocks.ListBlock(blocks.StructBlock([
            ("subBlockA", blocks.DecimalBlock()),
            ("subBlockB", blocks.TextBlock(required=False)),
        ])))
    ], blank=True)

    content_panels = Page.content_panels + [StreamFieldPanel("content")]
  • When trying to add blockA I get an error in console: wagtail-react-streamfield.js:1 Uncaught TypeError: Cannot read property 'subBlockA' of undefined (It seems to happen at https://github.com/noripyt/react-streamfield/blob/master/src/BlockContent.js#L117 because the childBlocksByType is empty)
  • Adding blockB turns into a memory overflow issue and the tab freezes in Chrome (it looks like its creating an infinite of BlockContent components)

I wanted to add a testcase for you, but there is not test framework setup yet. Let me know if I can help in other ways.

Radio buttons display and functionality broken

Wagtail 2.4
Wagtail react streamfield 1.2.0

Radio buttons within the edit form don't have enough space and grow into each other. Also they look like they're not properly given a name attribute which is why you're able to select more than one.

image

Note that radio buttons are not default Wagtail, but a customized ChoiceBlock:
image

No image thumbnails

When I have a StreamField with an ImageChooserBlock, I get thumbnail previews when I'm adding new images. But when I later edit the page, there are no thumbnails for any image. This is particularly inconvenient for image carousels (ListBlock containing an ImageChooserBlock) because I can't figure out which image I need to change or delete. Thanks for any advice!

screen shot 2018-10-01 at 11 03 16 am

ListBlock breaks when a sub-block throws a validation error

When a child block of ListBlock raises a validation error, an AttributeError is thrown during rendering of the invalid form.

Version: 1.1.1

Steps to Reproduce:
-Add a list block to a page.
-Save the page while a block in ListBlock is in an invalid state.

Result: An error occurs during template rendering "AttributeError: 'list' object has no attribute 'get'"

Expected Result: The page displays the validation error and marks the invalid fields.

Example Code:

class TestStreamBlock(StreamBlock):
    names = ListBlock(CharBlock(max_length=50))

class TestPage(Page):
    content = StreamField(TestStreamBlock(required=False),blank=True)

    content_panels = Page.content_panels + [
        StreamFieldPanel('content'),
    ]

TimeBlock wont accept value from timepicker

I would like to say that I am excited about this project and can't wait for it to be merged into Wagtail. It is a much needed improvement over the current StreamField backend. Great work! I have a couple of bugs to report that I am submitting as two separate issues.

Version: 0.8.5

Steps to reproduce:

  1. Create a new page and add a TimeBlock
  2. Selecting time from the time picker and then saving will trigger a validation error on the field and empty it.
  3. If โ€œ:00โ€ is added to the end of the time that is selected from the picker then the page will save fine.
    The issue seems to be in the way time values are recognized in the javascript.

Here is a sample of the code used to recreate this issue:

class TestStreamBlock(StreamBlock):
    NUMBERS = (('one', 'one'), ('two', 'two'),)

    time = TimeBlock()
    name = CharBlock(default='Test Name 1')
    number = ChoiceBlock(max_length=3, choices=NUMBERS, default=NUMBERS[0])

class TestPage(Page):
    content = StreamField(TestStreamBlock(required=False),blank=True)

    content_panels = Page.content_panels + [
        StreamFieldPanel('content'),
    ]

StreamFields on Snippets do not persist

If you create a Wagtail snippet model like so:

from wagtail.admin.edit_handlers import StreamFieldPanel, FieldPanel
from wagtail.core import blocks
from wagtail.snippets.models import register_snippet
from wagtail.core.fields import StreamField
from django.db import models


@register_snippet
class TestSnippet(models.Model):
    name = models.CharField(max_length=255)

    link = StreamField([
        ('page_link', blocks.PageChooserBlock(required=True, help_text='Add Link to Page')),
        ('url_link', blocks.URLBlock(required=True, help_text='Add URL')),
        ('text', blocks.CharBlock(required=True))
    ], default=None)

    panels = [
        FieldPanel('name'),
        StreamFieldPanel('link'),
    ]

    def __str__(self):
        return self.name

The Snippet registers and is added to the Wagtail admin interface. However, with the wagtail_react_streamfield app installed, any contents placed in the StreamField are not persisted.

The validation runs as expected -- if you mark a field as required as shown in the example, not filling out the field will return an error as expected. However, once the validation rules are met, the JSON data for the StreamField is persisted as an empty array.

Validation working as expected:
Screen Shot 2020-01-09 at 9 31 28 AM

Attempting to save this with valid data appears to be successful, as you would expect:
Screen Shot 2020-01-09 at 9 32 05 AM
Screen Shot 2020-01-09 at 9 32 32 AM

However, attempting to edit this newly saved snippet shows that the StreamField is empty:
Screen Shot 2020-01-09 at 9 33 17 AM
... and the database entry reflects this:
Screen Shot 2020-01-09 at 9 34 21 AM

If I do not enable the wagtail_react_streamfield app, this persists as expected.

Django 2.2.9, Wagtail 2.7.1, wagtail-react-streamfield 1.3.5

Rendering of the wagtail.core.blocks.StaticBlock

Hi,

I've noticed an issue with the rendering of a StaticBlock using wagtail-react-streamfield==0.8.5 in combination with wagtail==2.2.2.

In these 2 cases I would be presented with an input field instead:

class LatestCoursesBlock(blocks.StructBlock):
    static = blocks.StaticBlock(admin_text="Latest courses: no configuration needed.")

    class Meta:
        template = 'latest_courses.html'
        icon = 'fa-graduation-cap'

screen shot 2018-10-15 at 17 47 44

class LatestCoursesBlock(blocks.StaticBlock):

    class Meta:
        template = 'latest_courses.html'
        admin_text = "Latest courses: no configuration needed."
        icon = 'fa-graduation-cap'

screen shot 2018-10-15 at 17 45 02

If you need more information I would be happy to supply it for you.

Thanks in regards!

wagtail-react-streamfield.js:33 Error: Could not find input with name "field-23efd488-c187-43a5-bd3c-86f635a1e6a4"

Wagtail V2.4
wagtail-react-streamfield V1.2.0.

Settings

    'rest_framework',
    'wagtail.contrib.forms',
    'wagtail.contrib.redirects',
    'wagtail.embeds',
    'wagtail.sites',
    'wagtail.users',
    'wagtail_react_streamfield',
    'wagtail.snippets',
    'wagtail.documents',
    'wagtail.images',
    'wagtail.search',
    'wagtail.admin',
    'wagtail.core',

    'modelcluster',
    'taggit',

SectionBreak Struct Block

class StaticHTMLInput(Widget):
    """
    Need an <input> widget that doesn't actually accept any input
    """

    input_type = "hidden"

    def __init__(self, raw_html=None, **kwargs):
        self.raw_html = raw_html
        super(StaticHTMLInput, self).__init__(**kwargs)

    def render(self, name, value, attrs=None, renderer=None):
        if self.raw_html is not None:
            return format_html(self.raw_html)
        else:
            return ""


class StaticHTMLField(Field):
    def __init__(self, raw_html=None, **kwargs):
        widget = StaticHTMLInput(raw_html=raw_html)
        super(StaticHTMLField, self).__init__(widget=widget, **kwargs)


class StaticHTMLBlock(blocks.FieldBlock):
    def __init__(self, raw_html=None, required=False, help_text=None, **kwargs):
        self.raw_html = raw_html
        self.field = StaticHTMLField(
            raw_html=self.raw_html, required=required, help_text=help_text
        )
        super(StaticHTMLBlock, self).__init__(**kwargs)

    def render(self, value, context=None):
        """
        Return a text rendering of 'value', suitable for display on templates.
        Note that we override this function so that we can render the raw HTML as this block
        is just a container; 'value' in this case will always be None
        """
        if self.raw_html is not None:
            return format_html(self.raw_html)
        else:
            return ""


class SectionBreakBlock(blocks.StructBlock):
    section_break = StaticHTMLBlock(raw_html="<hr>")

    def render(self, value, context=None):
        """
        Return a text rendering of 'value', suitable for display on templates.
        Note that we override this function so that we can render the child block as this block
        is just a container; 'value' in this case will always be None
        """
        return self.child_blocks["section_break"].render(value)

    class Meta:
        icon = "code"

I use this block in my description streamfield.
After clicking this block in CMS admin i get below errors in console and entire streamfield vanishes

wagtail-react-streamfield.js:33 Error: Could not find input with name "field-23efd488-c187-43a5-bd3c-86f635a1e6a4"
    at t.value (wagtail-react-streamfield.js:50)
    at za (wagtail-react-streamfield.js:33)
    at Va (wagtail-react-streamfield.js:33)
    at wagtail-react-streamfield.js:33
    at Object.t.unstable_runWithPriority (wagtail-react-streamfield.js:42)
    at Ou (wagtail-react-streamfield.js:33)
    at Pu (wagtail-react-streamfield.js:33)
    at Iu (wagtail-react-streamfield.js:33)
    at Ru (wagtail-react-streamfield.js:33)
    at Tn (wagtail-react-streamfield.js:33)

Am i missing anything ?

DateTime format for DateTimeBlock is not loaded correctly

Hi,

it seems there is a bug for DateTimeBlock (from wagtail.core.blocks), when a page containing it is edited or after the first save, saving again is resulting in a validation error:

datetime_format_bug

Version: 1.0.5

Steps to reproduce:

  1. Create a page with a stream field with a DateTimeBlock option

  2. Choose any valid DateTime and save

  3. The DateTime format should be incorrect now / trying to save again should produce a validation error.

The reason for this behaviour might be the usage of the InputJSONEncoder / DjangoJSONEncoder (in function render_with_errors) which uses isoformat().

new changes to stream field content is lost if a validation error occurred while saving

I've created a custom ImageGalleryBlock and ImageGalleryItemBlock as follow.

class ImageGalleryBlock(StructBlock):
    image_list = ListBlock(ImageGalleryItemBlock(), label="Image Gallery")
    title = CharBlock(label="Gallery Title")

class ImageGalleryItemBlock(StructBlock):
    image = ImageChooserBlock()
    caption = CharBlock(required=False)

When I try to save and there is validation error in the one of these blocks, react-streamfield crashes.(e.g: trying to save without 'title' for ImageGalleryBlock)
It shows Uncaught TypeError: Cannot read property 'split' of null in console.

Page Chooser bug while editing page

While editing an existing page with an already saved PageChooserBlock, a click on 'Choose another page' does not open the page chooser modal. The parent page id in the GET request is not a number:

page chooser page id bug

Possible reason in page-chooser.js, line 53

parentId: data.meta.parent

(parent is an object)

custom to_python function causes keyerror

Pardon the rather odd issue title, but I can't exactly think of a good way to summarise my particular issue.

I've got some code that works exactly as I expect it to using the current streamfield, both when rendering the page, and in the admin. Using this new streamfield that same code breaks, thus not quite being a drop in replacement for me. I don't mind if I need to change this code, especially if this new streamfield will become the version in core Wagtail going forward, but ideally I'd like to achieve something similar to what I've got.

I have a link block that asks for a page or a url, but to make the front end easier, and to make it so our front end devs don't need to handle this same logic in every template, I have a 'link' attribute that exists on the block and it returns either the page or the url depending on which has been given by the content editor. The template then just uses 'link' and the front end dev doesn't ever have to know if the link might be to a page, a url, or a document (another variant of this block).

Mostly, I'm trying to mimic this pattern but with blocks:

class LinkFields(models.Model):
    link_page = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    link_external = models.URLField("External link", blank=True)

    @property
    def link(self):
        if self.link_page:
            return self.link_page.url
        else:
            return self.link_external

    panels = [
        PageChooserPanel('link_page'),
        FieldPanel('link_external'),
    ]

    class Meta:
        abstract = True

So now the question is, are you doing anything different with this new Streamfield that I've missed that I can adapt my code to, or is this due to a part of the existing Streamfield logic you missed?

You can probably put together a simpler example using my LinkBlock, but below is what I'm doing, how I'm using it, and the error I got when trying to load the admin page.

class LinkBlock(StructBlock):
    _link_page = PageChooserBlock(required=False)
    _link_external = URLBlock(required=False)

    def to_python(self, value):
        page = self.child_blocks['_link_page'].to_python(value['_link_page'])
        external_link = self.child_blocks['_link_external'].to_python(
            value['_link_external'])

        if page:
            link = page.url
        else:
            link = external_link

        return StructValue(self, [
            ('_link_page', page),
            ('_link_external', external_link),
            ('link', link)
        ])

    def get_prep_value(self, value):
        if 'link' in value:
            value.pop('link')
        return super(LinkBlock, self).get_prep_value(value)

    class Meta:
        icon = "link"


class FeatureBlock(StructBlock):
    title = CharBlock(max_length=100, label="Title")
    description = TextBlock(max_length=300, label="Description")
    image = ImageChooserBlock(
        label="Image (can be empty), must be square (1:1)", required=False)
    read_more = LinkBlock(label="Read more link")

    class Meta:
        icon = "radio-full"


class BenefitFeatureListBase(StructBlock):
    title = CharBlock(max_length=100, label="Title", required=False)
    description = TextBlock(
        max_length=200, label="Description", required=False)
    image_size = IntegerBlock(
        max_value=200, min_value=80, default=100,
        help_text="Image width and height (1:1)")

    class Meta:
        abstract = True


class FeatureListBlock(BenefitFeatureListBase):
    features = ListBlock(FeatureBlock())

    class Meta:
        icon = "list-ul"
        template = 'core/blocks/feature_list_block.html'
{% load wagtailimages_tags %}

<div class="feature-list-wrapper">
  <div class="feature-list">
    <div class="container">
      {% if value.title %}
        <h3 class="feature-list-title">
          {{ value.title }}
          <a href="#{{ value.title|slugify }}" aria-hidden="true"
             class="title-anchor" id="{{ value.title|slugify }}">
            <span class="icon icon-link"></span>
          </a>
        </h3>
      {% endif %}

      {% if value.description %}
        <p class="feature-list-description">{{ value.description }}</p>
      {% endif %}

      <div class="row">
          {% for feature in value.features %}
              <div class="col-sm-6 feature-list-item">
                  {% if feature.image %}
                    {% image feature.image fill-200x200 as feature_img %}

                    {% if feature_img.width >= value.image_size %}
                    <img src="{{ feature_img.url }}" width="{{ value.image_size }}"
                         height="{{ value.image_size }}" alt="{{ feature_img.alt }}" class="feature-image" />
                    {% else %}
                    <img src="{{ feature_img.url }}" width="{{ feature_img.width }}"
                         height="{{ feature_img.height }}" alt="{{ feature_img.alt }}" class="feature-image" />
                    {% endif %}
                  {% endif %}
                  <h4>{{ feature.title }}</h4>
                  <p> {{ feature.description }} </p>
                  {% if read_more.link %}
                    <a href="{{ read_more.link }}" class="invisible-link">
                      <span class="sr-only">Read more</span>
                    </a>
                  {% endif %}
              </div>
          {% if forloop.counter|divisibleby:2 %}
          </div>
          <div class="row">
          {% endif %}
          {% endfor %}
      </div>
    </div>
  </div>
</div>
Internal Server Error: /admin/pages/3/edit/
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/decorators/cache.py", line 31, in _cache_controlled
    response = viewfunc(request, *args, **kw)
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/urls/__init__.py", line 102, in wrapper
    return view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/decorators.py", line 34, in decorated_view
    return view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/views/pages.py", line 535, in edit
    'has_unsaved_changes': has_unsaved_changes,
  File "/usr/local/lib/python3.6/site-packages/django/shortcuts.py", line 36, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 155, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 155, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 155, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 67, in render
    result = block.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 67, in render
    result = block.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    output = self.filter_expression.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 676, in resolve
    obj = self.var.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 802, in resolve
    value = self._resolve_lookup(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 864, in _resolve_lookup
    current = current()
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py", line 230, in render_form_content
    return mark_safe(self.render_as_object() + self.render_missing_fields())
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py", line 198, in render_as_object
    return self.render()
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py", line 299, in render
    'self': self
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py", line 211, in render
    nodelist.append(node.render_annotated(context))
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    output = self.filter_expression.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 676, in resolve
    obj = self.var.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 802, in resolve
    value = self._resolve_lookup(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 864, in _resolve_lookup
    current = current()
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py", line 198, in render_as_object
    return self.render()
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py", line 299, in render
    'self': self
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py", line 211, in render
    nodelist.append(node.render_annotated(context))
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    output = self.filter_expression.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 676, in resolve
    obj = self.var.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 802, in resolve
    value = self._resolve_lookup(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 864, in _resolve_lookup
    current = current()
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py", line 457, in render_as_object
    'field': self.bound_field,
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 194, in render
    return template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 177, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 167, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 58, in render
    result = self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 943, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 910, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    output = self.filter_expression.resolve(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 703, in resolve
    new_obj = func(obj, *arg_vals)
  File "/usr/local/lib/python3.6/site-packages/wagtail/admin/templatetags/wagtailadmin_tags.py", line 244, in render_with_errors
    return bound_field.as_widget()
  File "/usr/local/lib/python3.6/site-packages/django/forms/boundfield.py", line 118, in as_widget
    **kwargs
  File "/usr/local/lib/python3.6/site-packages/wagtail/core/blocks/base.py", line 505, in render
    return self.render_with_errors(name, value, attrs=attrs, errors=None)
  File "/usr/local/lib/python3.6/site-packages/wagtail_react_streamfield/widget.py", line 153, in render_with_errors
    errors=errors),
  File "/usr/local/lib/python3.6/site-packages/wagtail_react_streamfield/widget.py", line 74, in prepare_value
    for i, child_block_data in enumerate(value)]
  File "/usr/local/lib/python3.6/site-packages/wagtail_react_streamfield/widget.py", line 74, in <listcomp>
    for i, child_block_data in enumerate(value)]
  File "/usr/local/lib/python3.6/site-packages/wagtail_react_streamfield/widget.py", line 59, in prepare_value
    for k, v in value.items()]
  File "/usr/local/lib/python3.6/site-packages/wagtail_react_streamfield/widget.py", line 59, in <listcomp>
    for k, v in value.items()]
  File "/usr/local/lib/python3.6/site-packages/wagtail_react_streamfield/widget.py", line 59, in prepare_value
    for k, v in value.items()]
  File "/usr/local/lib/python3.6/site-packages/wagtail_react_streamfield/widget.py", line 59, in <listcomp>
    for k, v in value.items()]
KeyError: 'link'

DateBlock can't be serialized to JSON

Hi @BertrandBordage , I love what I see from this package so far. I've hit one issue with rendering a DateBlock in the Wagtail admin. If the DateBlock has a None value, all is well, but if it has a date value, the template throws a 500 at render_with_errors. I tracked the issue down to widgets.InputJSONEncoder, and also found a patch for a similar issue with wagtail-condensedinlinepanel. I'm curious if you've seen the same thing at any point, or if you can reproduce the issue?

For the time being, I've submitted a proof-of-concept patch in this PR, for you to consider.

Compatibility issue with wagtail-geo-widget

This may be a problem in wagtail-geo-widget and not in wagtail-react-streamfield, however I'm reporting it in case it is the latter.

When using a GeoBlock, I'm getting an error on page load:

  File "(...)/wagtail_react_streamfield/widgets.py", line 120, in get_definition
    block.to_python(None), prefix='field-__ID__')
  File "(...)/wagtailgeowidget/blocks.py", line 53, in to_python
    value = geosgeometry_str_to_struct(value)
  File "(...)/wagtailgeowidget/helpers.py", line 18, in geosgeometry_str_to_struct
    result = geos_ptrn.match(value)
TypeError: expected string or bytes-like object

Versions:
Latest wagtail-react-streamfield (79606df), Wagtail 2.2.1, Python 3.6.5.

Thank you!!

Streamfield rendering breaks for blocks without an ID

Wagtail doesn't require a StreamBlock to have an ID until the point that it is saved in the database. This is helpful for things like pre-populating inital content into a streamfield, where you can initialise it with JSON such as:

json.dumps([
    {'type': 'paragraph', 'value': '<p>This is a paragraph</p>'}
    {'type': 'paragraph', 'value': '<p>This is another paragraph</p>'}
])

Doing so breaks the front-end handling of this field by wagtail-react-streamfield however - it looks like the JS expects an ID, and doesn't handle the case where there isn't one. The following works:

json.dumps([
    {'type': 'paragraph', 'value': '<p>This is a paragraph</p>', 'id': '5670367b-d5fe-4d1f-8e20-2e3f585d0864'}
    {'type': 'paragraph', 'value': '<p>This is another paragraph</p>', 'id': 'ce18d9bc-c0d6-4862-a3c3-756aa622309c'}
])

It would be good if it could handle the case where there is no block ID (as Wagtail does) for initial content - e.g., by just auto-generating one.

Customizable collapsed text?

As I mentioned over on the wagtail queue, it'd be nice if the text that's displayed when a block is collapsed were customizable. It's supposedly possible, but how does it work?

Doesn't start collapsed anymore

One of the older versions started collapsed (only one line for each mainblock) and only would open it up when you click on it.

I jumped to version 1.1.0 and it seems to started opened, which for pages with A LOT of blocks is worse.

Is this a bug, or something I can control?

DateTimeBlock value not updating when using date picker

There appears to be a bug with StreamFields using the DateTimeBlock, where the field values are not updated in the React component when the value is chosen with the date/time picker. As a result, to a user the values appear to be updated on the front-end, but when saving the updated values are not sent to the backend and the new values are lost.

If I manually change the date/time value by typing it in, it does update the value in the component and the values will be saved to the object.

See this attached GIF for a demonstration of the bug:

datetimebug

Custom chooser widgets have an empty state on first load

I've been watching the development of this package with quite some interest. It greatly improves the speed and performance of StreamField, thank you for creating it!

I've been seeing some strange behavior for custom chooser blocks. On the load of a page where values have been specified for a chooser widget, the chooser starts in a blank state . (An of a chooser where this behavior can be seen is in the Wagtail Media package. Please note that we have the same problems with three other custom choosers that we have created.)

The screenshot shows an example of how the problem manifests. The example block has a background video with both a media object and a custom icon class selected:

image

This is what the state should look like:

image

If we disable Wagtail React StreamField by removing the package from the INSTALLED_APPS, it resolves the issue. What is strange is that not all choosers are affected. Built-in choosers, such as the image chooser and page chooser, work as expected.

Do you have any idea what might cause this behavior? Is this a bug in React StreamField or are we failing to implement all of the properties required. Any insight would be appreciated.

customise the structblock form

Really loving the new UI for the streamfields. Fantactic work. It makes editing so much better, however the customisations I had made for a StructBlock are no longer working as they were before the plugin was installed. Not sure if this is an error or not, or perhaps not part of the upgrades to the streamfield. Will this still be possible to do, and if so how?

I was using:

class Meta:
        form_template = 'global_utils/forms/column_form.html'

Just wanted to flag it and ask the question just in case?

Validation errors not rendering correctly within nested streamblock

When using the "SomeContainerBlock" from this gist in a page, I run into an issue regarding the rendering of the validation errors. Steps to reproduce:

  1. add the "SomeContainerBlock" to a page
  2. add a "SomeParagraphBlock" or "SomeImageBlock" inside the container
  3. omit any of the values of this child block (all values are required, so this will cause a validation error)
  4. try to save the page

There will indeed be a validation error, there won't be any indication of what the error is or where in the content it occurred. This only seems to happen when we're nesting a block inside a streamblock. We need to be at least 2 levels deep, blocks added directly into a streamfield don't trigger this behavior

Reordering blocks not saved

I have the following stream field:

description = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.RichTextBlock(icon='pilcrow')),
        ('image', ImageChooserBlock(icon='image', template='department2/blocks/image.html')),
        ('image_carousel', blocks.ListBlock(ImageChooserBlock(), template='department2/blocks/image_carousel.html')),
        ('embedded_video', EmbedBlock(icon="media")),
    ])

When I reorder the top-level blocks (e.g., heading or paragraph) via drag-and-drop or arrows, and then Publish, the reordering is preserved. However, when I reorder the images in the image_carousel, the reordering is not preserved on Publish.

However, when I use the standard wagtail admin (no react-streamfield), it works fine, and reordering is preserved at all levels.

Any ideas?

it is destroying streamforms app

whenever I include "wagtail-react-streamfield" into "installed app", it making the streamfield unavailable, if the streamfields' blocks customized, otherwise no issues happens..!

check that please

Validation error when using nested StructBlocks

The problems is similar to the one I reported earlier. We have the following stucture defined for the 'participants' SteamField in our Event model (similar to #48):

class PersonRoleBlock(BaseBlockMixin, blocks.StructBlock):
    person = SnippetChooserBlock(target_model='members.Profile', required=True, label=_('Member'))
    instrument = SnippetChooserBlock(target_model='members.Instrument', required=False, label=_('Instrument'))
    role = blocks.CharBlock(required=False, label=_('Role (HU)'), help_text=_('If set, it overwrites the instrument'))
  
    class Meta:
        icon = 'user'
        closed = True

class RoleGroupBlock(BaseBlockMixin, blocks.StructBlock):
    title = blocks.CharBlock(required=False)
    participants = blocks.ListBlock(child_block=PersonRoleBlock(), required=True, label=_('Participants'))
    show_role = blocks.BooleanBlock(label=('Show roles/instruments'), required=False)

    class Meta:
        icon = 'user'
        closed = True

# line from the Event model
cast = StreamField(block_types=[
    ('rolegroup', RoleGroupBlock(label=_('Participant Group')))
],  blank=True, null=True)

If the editor adds a PersonRoleBlock element but forgets to select the profile for "person" field in the sub-block, an exception occurs:

'str' object has no attribute 'as_data'

Full stracktrace:

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/urls/__init__.py" in wrapper
  102.             return view_func(request, *args, **kwargs)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/decorators.py" in decorated_view
  34.             return view_func(request, *args, **kwargs)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/views/pages.py" in edit
  545.         'has_unsaved_changes': has_unsaved_changes,

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/shortcuts.py" in render
  36.     content = loader.render_to_string(template_name, context, request, using=using)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader.py" in render_to_string
  62.     return template.render(context, request)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/backends/django.py" in render
  61.             return self.template.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  171.                     return self._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  150.             return compiled_parent._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  62.                 result = block.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  62.                 result = block.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in resolve
  671.                 obj = self.var.resolve(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in resolve
  796.             value = self._resolve_lookup(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in _resolve_lookup
  858.                             current = current()

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py" in render_form_content
  252.         return mark_safe(self.render_as_object() + self.render_missing_fields())

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py" in render_as_object
  220.         return self.render()

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py" in render
  324.             'self': self

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader.py" in render_to_string
  62.     return template.render(context, request)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/backends/django.py" in render
  61.             return self.template.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  171.                     return self._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/defaulttags.py" in render
  209.                     nodelist.append(node.render_annotated(context))

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in resolve
  671.                 obj = self.var.resolve(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in resolve
  796.             value = self._resolve_lookup(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in _resolve_lookup
  858.                             current = current()

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py" in render_as_object
  220.         return self.render()

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py" in render
  324.             'self': self

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader.py" in render_to_string
  62.     return template.render(context, request)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/backends/django.py" in render
  61.             return self.template.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  171.                     return self._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/defaulttags.py" in render
  209.                     nodelist.append(node.render_annotated(context))

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in resolve
  671.                 obj = self.var.resolve(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in resolve
  796.             value = self._resolve_lookup(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in _resolve_lookup
  858.                             current = current()

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/edit_handlers.py" in render_as_object
  482.             'field': self.bound_field,

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader.py" in render_to_string
  62.     return template.render(context, request)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/backends/django.py" in render
  61.             return self.template.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  171.                     return self._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  188.             return template.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  173.                 return self._render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/test/utils.py" in instrumented_test_render
  96.     return self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/loader_tags.py" in render
  53.                 result = self.nodelist.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  937.                 bit = node.render_annotated(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render_annotated
  904.             return self.render(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in render
  987.             output = self.filter_expression.resolve(context)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/django/template/base.py" in resolve
  698.                 new_obj = func(obj, *arg_vals)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail/admin/templatetags/wagtailadmin_tags.py" in render_with_errors
  248.             errors=bound_field.errors

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/widgets.py" in render_with_errors
  94.         streamfield_config = self.get_streamfield_config(value, errors=errors)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/widgets.py" in get_streamfield_config
  89.             'value': self.block_def.prepare_value(value, errors=errors),

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/monkey_patch.py" in inner
  19.             return new_method(*args, **kwargs)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/blocks/stream_block.py" in prepare_value
  70.                                                    errors=child_errors),

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/monkey_patch.py" in inner
  19.             return new_method(*args, **kwargs)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/blocks/struct_block.py" in prepare_value
  74.                 'value': child_block.prepare_value(child_value, errors=errors),

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/monkey_patch.py" in inner
  19.             return new_method(*args, **kwargs)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/blocks/list_block.py" in prepare_value
  64.                                                       errors=child_errors)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/blocks/block.py" in get_instance_html
  33.         non_block_errors = get_non_block_errors(errors)

File "/var/www/virtualenv_wagtail/lib/python3.6/site-packages/wagtail_react_streamfield/widgets.py" in get_non_block_errors
  51.     errors_data = errors.as_data()

Exception Type: AttributeError at /admin/pages/2016/edit/
Exception Value: 'str' object has no attribute 'as_data'

Django: 2.2.1
Wagtail: 2.3.2
React-streamfield: 1.3.4

Block id changes for every page save for block in stream field

Hi,
i noticed this behavior:
Every block inside a stream field on a page is saved with a new id when the page is saved (with or without changes on the page or in the blocks). This also seems to happen when copying a page.
"Regular" wagtail functionality (Wagtail 2.3 and 2.4) leaves a block id untouched after it was created in the same case.

I'm yet unsure if this functionality change might be on purpose or if it might be a bug? Found this while trying to compare block contents via block id after a page was copied.

Versions:
Wagtail 2.3 + wagtail-react-streamfield 0.9.0
Wagtail 2.3 + wagtail-react-streamfield 1.1.1
Wagtail 2.4 + wagtail-react-streamfield 1.1.1

Steps to reproduce:

  1. Create a page with a StreamField and a CharBlock inside like
class TestPage(Page):
    body = StreamField([
        ('text', blocks.CharBlock()),
    ], null=True, blank=True)

    content_panels = Page.content_panels + [
        StreamFieldPanel('body'),
    ]
  1. Create one "text" block and save the page

  2. Save the page again

  3. Compare the content_json for the page revisions created in 2) and 3) - the block ids of "text" should differ

ImageChooserPanel not rendered correctly

When using the latest version of wagtail-react-streamfield (1.3.4), i'm running into the following problem:

I created a custom StructBlock, containing an ImageChooserBlock. This StructBlock is made available in a page's
StreamField.

After adding a block and choosing an image, everything seems fine (the image is rendered in the streamfield panel just as expected). The page saves fine, and the content is ok as well. However, when I edit a page that already contains the block with filled-in image, the image isn't rendered in the panel. The content is fine, and when I remove "wagtail_react_streamfield" from the INSTALLED_APPS, the image does become visible in the admin.

I set up a minimal example of this behavior here

TL;DR: when viewing existing content in the admin, imagechooserblocks aren't rendered correctly

Better ways to control SIMPLE vs COLLAPSIBLE

The current approach to controlling SIMPLE vs COLLAPSIBLE is tedious as described here:
#13 (comment)

In fact it kind of reduces the usefulness of this streamfield if you have to define every block like this to do so. I have over 20 block types (and I'm sure others have more), and some of the ones I use are stock from Wagtail (the Tableblock). The developer experience with this method sucks because I'd have to redefine each. ๐Ÿ˜ž

It would have made far more sense to make COLLAPSIBLE the default, but with all of the blocks open so it effectively starts like the SIMPLE layout. You then have the per block ability to define if you want to default closed, or never be able to close (SIMPLE). You then also allow a StreamField level definition/override which makes all blocks start open or closed, or forces them into either COLLAPSIBLE or SIMPLE.

I don't entirely even see the usefulness of SIMPLE when COLLAPSIBLE but defaulting to open (and the above ways to control that) is effectively SIMPLE but with more control. We should leave SIMPLE for those that really want it, but Wagtail is all about better UX first, and COLLAPSIBLE is better UX.

The entirely collapsible nature of wagtail-condensedinlinepanel was what made it so useful, and I was so happy to see that here and in the early versions of this. I'm sad I missed the discussion around this if there was one, because this 180 to what was the design before 1.0.0 is a bit sad. ๐Ÿ˜ž

In response to #28 and #13

js_initializer error

Getting an error when I try to runserver with wagtail_react_streamfield freshly installed ( following all the directions )

 File "/Users/dan/work/global_portal/global_portal/core/migrations/0002_auto_20180307_0119.py", line 12, in <module>
    class Migration(migrations.Migration):
  File "/Users/dan/work/global_portal/global_portal/core/migrations/0002_auto_20180307_0119.py", line 25, in Migration
    ('service_section', wagtail.core.fields.StreamField((('services', wagtail.core.blocks.ListBlock(global_portal.blocks.ServicesBlock)),))),
  File "/Users/dan/.local/share/virtualenvs/global_portal-c2XRKUcs/lib/python3.6/site-packages/wagtail/core/blocks/list_block.py", line 33, in __init__
    self.child_js_initializer = self.child_block.js_initializer()
  File "/Users/dan/.local/share/virtualenvs/global_portal-c2XRKUcs/lib/python3.6/site-packages/wagtail_react_streamfield/monkey_patch.py", line 18, in inner
    return new_method(*args, **kwargs)
  File "/Users/dan/.local/share/virtualenvs/global_portal-c2XRKUcs/lib/python3.6/site-packages/wagtail_react_streamfield/blocks/struct_block.py", line 21, in js_initializer
    raise RemovedError
wagtail_react_streamfield.exceptions.RemovedError


Chooser fields empty on init

All the chooser fields (ie. ImageChooser, PageChooser, etc.) are empty when initialized for me. I have the app first in my installed apps, so the solution that solved #47 did not solve the problem for me.

Getting the following JS errors, for what it's worth:

Screen Shot 2019-09-13 at 4 27 16 PM

Copying an entire StreamField (wagtail-modeltranslation)

We use wagtail-modeltranslation for internationalizing content on a per-field basis. StreamField content will often contain references that do not need to change between languages, so the workflow for translating a StreamField tends to be:

  1. Create the content in the first language.
  2. Copy the content from the base language's StreamField into a target language's StreamField (Wagtail Modeltranslation adds copy buttons alongside the StreamField label)
  3. Edit text for the new language for CharBlocks and other text fields, while skipping things like references to images, links to internal pages, and so on.

Let's say we have a StreamField named content and two languages, English and French. Modeltranslation means that we end up with the fields content_en and content_fr. At first look, I think it will be possible to emulate the same behaviour that exists in Wagtail Modeltranslation for the old streamfields, adding copy buttons to the DOM that call streamField.init() like this:

window.streamField.init('content_targetlanguage', 'content_sourcelanguage')

Where content_sourcelanguage is the serialized options data used to initialize the field.

I'm poking around to understand the codebase more to work on this, but I'd like to make sure I'm not underestimating the task or totally abusing streamField.init() by using it this way. Hence posting here as opposed to wagtail-modeltranslation.

Some initial questions and findings:

  • The copy function would need to be able to gather the streamfield config and the values as they exists on the client at the time of copying. It looks like it would be workable to take the initial streamfield config (e.g. the blockDefinitions) from one of the <script>...init()...</script>'s, but grab the values from the source field's hidden input.
  • Stripping IDs from the source value appears to ensure that new ones are generated
  • Running init() as above does indeed copy the source to the target successfully, but the streamform elements are rendered twice (one full set followed by a + icon followed by a second full set). This doesn't appear to affect the functioning of the streamfield (changes can be made and saved on the first set). Is there a fundamental reason why this might be happening?
  • Are there potentially other side effects from using streamField.init() this way that I'm not accounting for?

I also just wanted to say congrats on all the hard work, we've been following since the campaign ๐ŸŽ‰

Icon-font not up to date

Looks to me like the icon-font used in Wagtail 2.5.1 is not represented by the wagtail.woff that comes with the plugin. Specifically icons for subscript and superscript of the Draftail-Editor are missing.

Cannot serialise default date value

errorObject of type builtin_function_or_method is not JSON serializable is thrown when defining a block with a default date value e.g:

    start_time = blocks.DateTimeBlock(required=False, default=datetime.now)

Recommended way to init JavaScript?

Wagtail docs suggest js_initializer, but that didn't seem to work.

This worked:

def render_form(self, *args, **kwargs):
    form = super().render_form(*args, **kwargs)
    return form + "<script>jsInitializer()</script>"

What is the recommended way?

Limitations with block naming

Hi,

Thank you for all your work. I use react-streamfield since about 18 month and I built some websites using exotic names containing '+' (plus) or '.' (dots).

It seems that theses names now break react streamfield.

Btw there is no advertising about it. Block._check_name don't refers to plus or dots.

Prior moving to wagtail-2.7, it worked (last known working version from pip : 1.3.5).

(Actually I am not sure if I should report this as a Wagtail bug.)

__str__ method not used when coupled with wagtailmodelchooser

I am using wagtailmodelchooser for a project and am using this package as well. Model chooser fields aren't showing up with a str representation of the object. I removed the react stream fields and am able to see them with the default setup.
Screen Shot 2019-08-08 at 12 56 18 PM
This is how it looks without:
Screen Shot 2019-08-08 at 1 05 15 PM

I can investigate more deeply and potentially create a PR when I get some time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.