diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index 5696e213ad1b576008a189c920cd2ebf49c004b8..bbbd71a2b841d59c2dd3d53a9031514fb4ffdc39 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -231,9 +231,10 @@ def xblock_view_handler(request, package_id, view_name, tag=None, branch=None, v # with the new container view. is_read_only_view = is_container_view context = { + 'runtime_type': 'studio', 'container_view': is_container_view, 'read_only': is_read_only_view, - 'root_xblock': component + 'root_xblock': component, } fragment = get_preview_fragment(request, component, context) diff --git a/cms/djangoapps/contentstore/views/tests/test_item.py b/cms/djangoapps/contentstore/views/tests/test_item.py index e8e3a5092ca395bfd68b8c0c0c85a3fb5e48b6f4..06b067c13abfb0c2b023c3af135cb4fe0999a096 100644 --- a/cms/djangoapps/contentstore/views/tests/test_item.py +++ b/cms/djangoapps/contentstore/views/tests/test_item.py @@ -157,6 +157,22 @@ class GetItem(ItemTest): '<span class="action-button-text">View</span>') ) + def test_split_test(self): + """ + Test that a split_test module renders all of its children in Studio. + """ + root_locator = self._create_vertical() + resp = self.create_xblock(category='split_test', parent_locator=root_locator) + self.assertEqual(resp.status_code, 200) + split_test_locator = self.response_locator(resp) + resp = self.create_xblock(parent_locator=split_test_locator, category='html', boilerplate='announcement.yaml') + self.assertEqual(resp.status_code, 200) + resp = self.create_xblock(parent_locator=split_test_locator, category='html', boilerplate='zooming_image.yaml') + self.assertEqual(resp.status_code, 200) + html, __ = self._get_container_preview(split_test_locator) + self.assertIn('Announcement', html) + self.assertIn('Zooming', html) + class DeleteItem(ItemTest): """Tests for '/xblock' DELETE url.""" diff --git a/common/lib/xmodule/xmodule/split_test_module.py b/common/lib/xmodule/xmodule/split_test_module.py index fad577198d82e783298f3fc19d08c7cba9218cd7..27c3e5621752c3a09de09f074976d58504826dc1 100644 --- a/common/lib/xmodule/xmodule/split_test_module.py +++ b/common/lib/xmodule/xmodule/split_test_module.py @@ -41,7 +41,7 @@ class SplitTestFields(object): @XBlock.needs('user_tags') # pylint: disable=abstract-method -@XBlock.needs('partitions') +@XBlock.wants('partitions') class SplitTestModule(SplitTestFields, XModule): """ Show the user the appropriate child. Uses the ExperimentState @@ -61,7 +61,10 @@ class SplitTestModule(SplitTestFields, XModule): super(SplitTestModule, self).__init__(*args, **kwargs) - self.child_descriptor = self.get_child_descriptors()[0] + self.child_descriptor = None + child_descriptors = self.get_child_descriptors() + if len(child_descriptors) >= 1: + self.child_descriptor = child_descriptors[0] if self.child_descriptor is not None: self.child = self.system.get_module(self.child_descriptor) else: @@ -106,7 +109,9 @@ class SplitTestModule(SplitTestFields, XModule): """ For grading--return just the chosen child. """ - group_id = self.runtime.service(self, 'partitions').get_user_group_for_partition(self.user_partition_id) + group_id = self.get_group_id() + if group_id is None: + return [] # group_id_to_child comes from json, so it has to have string keys str_group_id = str(group_id) @@ -126,6 +131,15 @@ class SplitTestModule(SplitTestFields, XModule): return [child_descriptor] + def get_group_id(self): + """ + Returns the group ID, or None if none is available. + """ + partitions_service = self.runtime.service(self, 'partitions') + if not partitions_service: + return None + return partitions_service.get_user_group_for_partition(self.user_partition_id) + def _staff_view(self, context): """ Render the staff view for a split test module. @@ -155,11 +169,37 @@ class SplitTestModule(SplitTestFields, XModule): fragment.initialize_js('ABTestSelector') return fragment + def studio_preview_view(self, context): + """ + Renders the Studio preview by rendering each child so that they can all be seen and edited. + """ + fragment = Fragment() + contents = [] + + for child in self.descriptor.get_children(): + rendered_child = self.runtime.get_module(child).render('student_view', context) + fragment.add_frag_resources(rendered_child) + + contents.append({ + 'id': child.id, + 'content': rendered_child.content + }) + + fragment.add_content(self.system.render_template('vert_module.html', { + 'items': contents + })) + + return fragment + def student_view(self, context): """ Render the contents of the chosen condition for students, and all the conditions for staff. """ + # When rendering a Studio preview, render all of the block's children + if context and context['runtime_type'] == 'studio': + return self.studio_preview_view(context) + if self.child is None: # raise error instead? In fact, could complain on descriptor load... return Fragment(content=u"<div>Nothing here. Move along.</div>") @@ -197,7 +237,7 @@ class SplitTestModule(SplitTestFields, XModule): @XBlock.needs('user_tags') # pylint: disable=abstract-method -@XBlock.needs('partitions') +@XBlock.wants('partitions') class SplitTestDescriptor(SplitTestFields, SequenceDescriptor): # the editing interface can be the same as for sequences -- just a container module_class = SplitTestModule