diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py
index c1338d6230..68650e9bc1 100644
--- a/cms/djangoapps/contentstore/views/component.py
+++ b/cms/djangoapps/contentstore/views/component.py
@@ -23,7 +23,6 @@ from xblock.exceptions import NoSuchHandlerError
from xblock.fields import Scope
from xblock.plugin import PluginMissingError
from xblock.runtime import Mixologist
-from xmodule.x_module import prefer_xmodules
from lms.lib.xblock.runtime import unquote_slashes
@@ -310,13 +309,20 @@ def container_handler(request, tag=None, package_id=None, branch=None, version_g
old_location, course, xblock, __ = _get_item_in_course(request, locator)
except ItemNotFoundError:
return HttpResponseBadRequest()
- parent_xblock = get_parent_xblock(xblock)
+
+ ancestor_xblocks = []
+ parent = get_parent_xblock(xblock)
+ while parent and parent.category != 'sequential':
+ ancestor_xblocks.append(parent)
+ parent = get_parent_xblock(parent)
+
+ ancestor_xblocks.reverse()
return render_to_response('container.html', {
'context_course': course,
'xblock': xblock,
'xblock_locator': locator,
- 'parent_xblock': parent_xblock,
+ 'ancestor_xblocks': ancestor_xblocks,
})
else:
return HttpResponseBadRequest("Only supports html requests")
diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py
index d9734773b0..667bf91a0d 100644
--- a/cms/djangoapps/contentstore/views/item.py
+++ b/cms/djangoapps/contentstore/views/item.py
@@ -206,12 +206,10 @@ def xblock_view_handler(request, package_id, view_name, tag=None, branch=None, v
elif view_name == 'student_view' and component.has_children:
# For non-leaf xblocks on the unit page, show the special rendering
# which links to the new container page.
- course_location = loc_mapper().translate_locator_to_location(locator, True)
- course = store.get_item(course_location)
- html = render_to_string('unit_container_xblock_component.html', {
- 'course': course,
+ html = render_to_string('container_xblock_component.html', {
'xblock': component,
- 'locator': locator
+ 'locator': locator,
+ 'reordering_enabled': True,
})
return JsonResponse({
'html': html,
diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py
index 8307c88d64..b3e4f0562e 100644
--- a/cms/djangoapps/contentstore/views/preview.py
+++ b/cms/djangoapps/contentstore/views/preview.py
@@ -179,6 +179,8 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False):
}
if xblock.category == 'vertical':
template = 'studio_vertical_wrapper.html'
+ elif xblock.location != context.get('root_xblock').location and xblock.has_children:
+ template = 'container_xblock_component.html'
else:
template = 'studio_xblock_wrapper.html'
html = render_to_string(template, template_context)
diff --git a/cms/djangoapps/contentstore/views/tests/test_container.py b/cms/djangoapps/contentstore/views/tests/test_container.py
index b1a6faf96f..766b86f8f3 100644
--- a/cms/djangoapps/contentstore/views/tests/test_container.py
+++ b/cms/djangoapps/contentstore/views/tests/test_container.py
@@ -26,8 +26,44 @@ class ContainerViewTestCase(CourseTestCase):
category="video", display_name="My Video")
def test_container_html(self):
- url = xblock_studio_url(self.child_vertical)
+ self._test_html_content(
+ self.child_vertical,
+ expected_section_tag='',
+ expected_breadcrumbs=(
+ r'Unit\s*'
+ r'Child Vertical'),
+ )
+
+ def test_container_on_container_html(self):
+ """
+ Create the scenario of an xblock with children (non-vertical) on the container page.
+ This should create a container page that is a child of another container page.
+ """
+ xblock_with_child = ItemFactory.create(parent_location=self.child_vertical.location,
+ category="wrapper", display_name="Wrapper")
+ ItemFactory.create(parent_location=xblock_with_child.location,
+ category="html", display_name="Child HTML")
+ self._test_html_content(
+ xblock_with_child,
+ expected_section_tag='',
+ expected_breadcrumbs=(
+ r'Unit\s*'
+ r'Child Vertical\s*'
+ r'Wrapper'),
+ )
+
+ def _test_html_content(self, xblock, expected_section_tag, expected_breadcrumbs):
+ """
+ Get the HTML for a container page and verify the section tag is correct
+ and the breadcrumbs trail is correct.
+ """
+ url = xblock_studio_url(xblock, self.course)
resp = self.client.get_html(url)
self.assertEqual(resp.status_code, 200)
html = resp.content
- self.assertIn('', html)
+ self.assertIn(expected_section_tag, html)
+ # Verify the navigation link at the top of the page is correct.
+ self.assertRegexpMatches(html, expected_breadcrumbs)
diff --git a/cms/djangoapps/contentstore/views/tests/test_item.py b/cms/djangoapps/contentstore/views/tests/test_item.py
index 3aa3f15ad9..2b225b9d8e 100644
--- a/cms/djangoapps/contentstore/views/tests/test_item.py
+++ b/cms/djangoapps/contentstore/views/tests/test_item.py
@@ -132,6 +132,31 @@ class GetItem(ItemTest):
# Verify that the Studio element wrapper has been added
self.assertIn('level-element', html)
+ def test_get_container_nested_container_fragment(self):
+ """
+ Test the case of the container page containing a link to another container page.
+ """
+ # Add a wrapper with child beneath a child vertical
+ root_locator = self._create_vertical()
+
+ resp = self.create_xblock(parent_locator=root_locator, category="wrapper")
+ self.assertEqual(resp.status_code, 200)
+ wrapper_locator = self.response_locator(resp)
+
+ resp = self.create_xblock(parent_locator=wrapper_locator, category='problem', boilerplate='multiplechoice.yaml')
+ self.assertEqual(resp.status_code, 200)
+
+ # Get the preview HTML and verify the View -> link is present.
+ html, __ = self._get_container_preview(root_locator)
+ self.assertIn('wrapper-xblock', html)
+ self.assertRegexpMatches(
+ html,
+ # The instance of the wrapper class will have an auto-generated ID (wrapperxxx). Allow anything
+ # for the 3 characters after wrapper.
+ (r'"/container/MITx.999.Robot_Super_Course/branch/published/block/wrapper.{3}" class="action-button">\s*'
+ 'View')
+ )
+
class DeleteItem(ItemTest):
"""Tests for '/xblock' DELETE url."""
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index f921e2c6a7..4fbe6e6091 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -334,11 +334,12 @@ p, ul, ol, dl {
.navigation-link {
@extend %cont-truncated;
display: inline-block;
- max-width: 150px;
+ max-width: 250px;
&.navigation-current {
@extend %ui-disabled;
color: $gray;
+ max-width: 250px;
&:before {
color: $gray;
diff --git a/cms/static/sass/elements/_xblocks.scss b/cms/static/sass/elements/_xblocks.scss
index 1fccbf9cb8..6ab90b0e66 100644
--- a/cms/static/sass/elements/_xblocks.scss
+++ b/cms/static/sass/elements/_xblocks.scss
@@ -55,7 +55,7 @@
}
// UI: xblock is collapsible
-.wrapper-xblock.is-collapsible {
+.wrapper-xblock.is-collapsible, .wrapper-xblock.xblock-type-container {
[class^="icon-"] {
font-style: normal;
diff --git a/cms/templates/container.html b/cms/templates/container.html
index 39ef7cfd13..83855250ed 100644
--- a/cms/templates/container.html
+++ b/cms/templates/container.html
@@ -16,7 +16,7 @@ from django.utils.translation import ugettext as _
<%
xblock_info = {
'id': str(xblock_locator),
- 'display-name': xblock.display_name,
+ 'display-name': xblock.display_name_with_default,
'category': xblock.category,
};
%>
@@ -47,14 +47,16 @@ xblock_info = {
diff --git a/cms/templates/unit_container_xblock_component.html b/cms/templates/container_xblock_component.html
similarity index 72%
rename from cms/templates/unit_container_xblock_component.html
rename to cms/templates/container_xblock_component.html
index 3440626dd9..cd91f8b50f 100644
--- a/cms/templates/unit_container_xblock_component.html
+++ b/cms/templates/container_xblock_component.html
@@ -7,12 +7,12 @@ from contentstore.views.helpers import xblock_studio_url
-
+ ## We currently support reordering only on the unit page.
+ % if reordering_enabled:
+
+ % endif
diff --git a/cms/templates/studio_vertical_wrapper.html b/cms/templates/studio_vertical_wrapper.html
index 774b49bf95..226811d790 100644
--- a/cms/templates/studio_vertical_wrapper.html
+++ b/cms/templates/studio_vertical_wrapper.html
@@ -8,7 +8,7 @@
${_('Expand or Collapse')}
- ${xblock.display_name | h}
+ ${xblock.display_name_with_default | h}