diff --git a/client/src/components/ContentBlock.vue b/client/src/components/ContentBlock.vue
index 5c541820..9da7b3dc 100644
--- a/client/src/components/ContentBlock.vue
+++ b/client/src/components/ContentBlock.vue
@@ -3,19 +3,20 @@
{{instrumentLabel}}
-
{{contentBlock.title}}
+
{{contentBlock.title}}
-
@@ -23,7 +24,7 @@
-
+
@@ -41,6 +42,7 @@
import InfogramBlock from '@/components/content-blocks/InfogramBlock';
import GeniallyBlock from '@/components/content-blocks/GeniallyBlock';
import SubtitleBlock from '@/components/content-blocks/SubtitleBlock';
+ import ContentListBlock from '@/components/content-blocks/ContentListBlock';
import Assignment from '@/components/content-blocks/assignment/Assignment';
import Solution from '@/components/content-blocks/Solution';
import AddContentBlockButton from '@/components/AddContentBlockButton';
@@ -59,6 +61,7 @@
export default {
props: ['contentBlock', 'parent'],
+ name: 'content-block',
components: {
'text_block': TextBlock,
@@ -72,6 +75,7 @@
'infogram_block': InfogramBlock,
'genially_block': GeniallyBlock,
'subtitle': SubtitleBlock,
+ 'content_list': ContentListBlock,
Solution,
Assignment,
Task,
@@ -93,6 +97,59 @@
}
return `Instrument - ${instruments[contentType]}`
+ },
+ canEditContentBlock() {
+ return this.contentBlock.mine && !this.contentBlock.indent;
+ },
+ contentBlocksWithContentLists() {
+ /*
+ collects all conent_list_items in content_lists:
+ {
+ text_block,
+ content_list_item: [contents...],
+ content_list_item: [contents...],
+ text_block
+ } becomes
+ {
+ text_block,
+ content_list: [content_list_item: [contents...], content_list_item: [contents...]],
+ text_block
+ }
+ if there's only a single content_list_item it should not be displayed as list like so
+ {
+ text_block,
+ content_list_item: [text_block, image_block],
+ } becomes
+ {
+ text_block,
+ text_block,
+ image_block
+ }
+ */
+ let contentList = [];
+ let newContent = this.contentBlock.contents.reduce((newContents, content, index) => {
+ // collect content_list_items
+ if (content.type === 'content_list_item') {
+ contentList = [...contentList, content]
+ if (index === this.contentBlock.contents.length - 1) { // content is last element of contents array
+ return [...newContents, ...this.createContentListOrBlocks(contentList)];
+ }
+ return newContents
+ } else {
+ // handle all other items and reset current content_list if necessary
+ if (contentList.length !== 0) {
+ newContents = [...newContents, ...this.createContentListOrBlocks(contentList), content];
+ contentList = [];
+ return newContents;
+ } else {
+ return [...newContents, content]
+ }
+ }
+ }, [])
+
+ return Object.assign({}, this.contentBlock, {
+ contents: newContent
+ });
}
},
@@ -125,9 +182,20 @@
}
}
});
- }
- },
+ },
+ createContentListOrBlocks(contentList) {
+ // if list contains only one item, return blocks
+ if (contentList.length === 1) {
+ return contentList[0].value;
+ }
+ return [{
+ type: 'content_list',
+ contents: contentList,
+ id: contentList[0].id
+ }];
+ },
+ },
data() {
return {
showVisibility: false
diff --git a/client/src/components/content-blocks/ContentListBlock.vue b/client/src/components/content-blocks/ContentListBlock.vue
new file mode 100644
index 00000000..663e02dd
--- /dev/null
+++ b/client/src/components/content-blocks/ContentListBlock.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
diff --git a/client/src/components/content-blocks/SubtitleBlock.vue b/client/src/components/content-blocks/SubtitleBlock.vue
index b3ebd13b..c642fc51 100644
--- a/client/src/components/content-blocks/SubtitleBlock.vue
+++ b/client/src/components/content-blocks/SubtitleBlock.vue
@@ -11,6 +11,7 @@
diff --git a/server/api/graphene_wagtail.py b/server/api/graphene_wagtail.py
index 1a870941..ff87dc5c 100644
--- a/server/api/graphene_wagtail.py
+++ b/server/api/graphene_wagtail.py
@@ -18,59 +18,67 @@ class GenericStreamFieldType(Scalar):
@staticmethod
def serialize(stream_value):
stream_data = stream_value.stream_data
-
- for d in stream_data:
- if isinstance(d, dict):
- _type = d['type']
- if _type == 'image_block':
- _value = d['value']
- value = {
- # 'value': _value,
- # 'id': d['id'],
- 'path': Image.objects.get(id=_value).file.url
- }
- d['value'] = value
- if _type == 'assignment':
- _value = d['value']
- assignment_id = _value['assignment_id']
- try:
- assignment = Assignment.objects.get(pk=assignment_id)
- value = {
- 'title': assignment.title,
- 'assignment': assignment.assignment,
- 'id': to_global_id('AssignmentNode', assignment.pk)
- }
- d['value'] = value
- except Assignment.DoesNotExist:
- logger.error('Assignment {} does not exist'.format(assignment_id))
- if _type == 'basic_knowledge' or _type == 'instrument':
- _value = d['value']
- basic_knowledge = BasicKnowledge.objects.get(pk=_value['basic_knowledge'])
- _value.update({
- 'slug': basic_knowledge.slug
- })
- d['value'] = _value
-
- # value = dict(d['value'])
- # if 'document' in value:
- # value['document'] = Document.objects.get(id=value['document']).file.url
- # if 'image' in value:
- # value['image'] = Image.objects.get(id=value['image']).file.url
-
- # else:
- # _type = d[0]
- # value = dict(d[1])
- # if 'document' in value:
- # value['document'] = value['document'].file.url
- # if 'image' in value:
- # value['image'] = value['image'].file.url
-
- return stream_data
+ return augment_fields(stream_data)
# by_api = stream_value.stream_block.get_api_representation(stream_value)
# return by_api
+def augment_fields(stream_data):
+ for data in stream_data:
+ if isinstance(data, dict):
+ _type = data['type']
+ if _type == 'image_block':
+ _value = data['value']
+ value = {
+ # 'value': _value,
+ # 'id': d['id'],
+ 'path': Image.objects.get(id=_value).file.url
+ }
+ data['value'] = value
+ if _type == 'assignment':
+ _value = data['value']
+ assignment_id = _value['assignment_id']
+ try:
+ assignment = Assignment.objects.get(pk=assignment_id)
+ value = {
+ 'title': assignment.title,
+ 'assignment': assignment.assignment,
+ 'id': to_global_id('AssignmentNode', assignment.pk)
+ }
+ data['value'] = value
+ except Assignment.DoesNotExist:
+ logger.error('Assignment {} does not exist'.format(assignment_id))
+ if _type == 'basic_knowledge' or _type == 'instrument':
+ _value = data['value']
+ basic_knowledge = BasicKnowledge.objects.get(pk=_value['basic_knowledge'])
+ _value.update({
+ 'slug': basic_knowledge.slug
+ })
+ data['value'] = _value
+
+ # value = dict(d['value'])
+ # if 'document' in value:
+ # value['document'] = Document.objects.get(id=value['document']).file.url
+ # if 'image' in value:
+ # value['image'] = Image.objects.get(id=value['image']).file.url
+
+ # else:
+ # _type = d[0]
+ # value = dict(d[1])
+ # if 'document' in value:
+ # value['document'] = value['document'].file.url
+ # if 'image' in value:
+ # value['image'] = value['image'].file.url
+
+ if _type == 'content_list_item':
+ item_data = data['value']
+ data['value'] = augment_fields(item_data)
+
+ return stream_data
+
+
@convert_django_field.register(StreamField)
def convert_stream_field(field, registry=None):
return GenericStreamFieldType(description=field.help_text, required=not field.null)
+
diff --git a/server/books/models/contentblock.py b/server/books/models/contentblock.py
index 9044abd7..e59427e3 100644
--- a/server/books/models/contentblock.py
+++ b/server/books/models/contentblock.py
@@ -2,6 +2,7 @@ import logging
from django.db import models
from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList, StreamFieldPanel
+from wagtail.core.blocks import StreamBlock
from wagtail.core.fields import StreamField
from wagtail.images.blocks import ImageChooserBlock
@@ -34,7 +35,7 @@ class ContentBlock(StrictHierarchyPage):
visible_for = models.ManyToManyField(SchoolClass, related_name='visible_content_blocks')
user_created = models.BooleanField(default=False)
- contents = StreamField([
+ content_blocks = [
('text_block', TextBlock()),
('basic_knowledge', BasicKnowledgeBlock()),
('assignment', AssignmentBlock()),
@@ -46,8 +47,11 @@ class ContentBlock(StrictHierarchyPage):
('document_block', DocumentBlock()),
('infogram_block', InfogramBlock()),
('genially_block', GeniallyBlock()),
- ('subtitle', SubtitleBlock()),
- ], null=True, blank=True)
+ ('subtitle', SubtitleBlock())
+ ]
+
+ content_list_item = StreamBlock(content_blocks)
+ contents = StreamField(content_blocks + [('content_list_item', content_list_item)], null=True, blank=True)
type = models.CharField(
max_length=100,