diff --git a/problem_builder/mentoring.py b/problem_builder/mentoring.py
index 3cd5b9c7..ae7f7cf3 100644
--- a/problem_builder/mentoring.py
+++ b/problem_builder/mentoring.py
@@ -34,7 +34,7 @@
from xblock.fragment import Fragment
from xblock.validation import ValidationMessage
-from .message import MentoringMessageBlock
+from .message import MentoringMessageBlock, get_message_label
from .mixins import (
_normalize_id, QuestionMixin, MessageParentMixin, StepParentMixin, XBlockWithTranslationServiceMixin
)
@@ -44,9 +44,16 @@
from xblockutils.resources import ResourceLoader
from xblockutils.settings import XBlockWithSettingsMixin, ThemableXBlockMixin
from xblockutils.studio_editable import (
- NestedXBlockSpec, StudioEditableXBlockMixin, StudioContainerXBlockMixin, StudioContainerWithNestedXBlocksMixin,
+ NestedXBlockSpec, StudioEditableXBlockMixin, StudioContainerWithNestedXBlocksMixin,
)
+from problem_builder.answer import AnswerBlock, AnswerRecapBlock
+from problem_builder.mcq import MCQBlock, RatingBlock
+from problem_builder.mrq import MRQBlock
+from problem_builder.plot import PlotBlock
+from problem_builder.slider import SliderBlock
+from problem_builder.table import MentoringTableBlock
+
try:
# Used to detect if we're in the workbench so we can add Font Awesome
@@ -220,7 +227,7 @@ def max_score(self):
return 1.0
-class MentoringBlock(BaseMentoringBlock, StudioContainerXBlockMixin, StepParentMixin):
+class MentoringBlock(BaseMentoringBlock, StudioContainerWithNestedXBlocksMixin, StepParentMixin):
"""
An XBlock providing mentoring capabilities
@@ -321,6 +328,64 @@ class MentoringBlock(BaseMentoringBlock, StudioContainerXBlockMixin, StepParentM
'display_submit', 'feedback_label', 'weight', 'extended_feedback'
)
+ @property
+ def allowed_nested_blocks(self):
+ """
+ Returns a list of allowed nested XBlocks. Each item can be either
+ * An XBlock class
+ * A NestedXBlockSpec
+
+ If XBlock class is used it is assumed that this XBlock is enabled and allows multiple instances.
+ NestedXBlockSpec allows explicitly setting disabled/enabled state, disabled reason (if any) and single/multiple
+ instances
+ """
+ additional_blocks = []
+ try:
+ from xmodule.video_module.video_module import VideoDescriptor
+ additional_blocks.append(NestedXBlockSpec(
+ VideoDescriptor, category='video', label=_(u"Video")
+ ))
+ except ImportError:
+ pass
+ try:
+ from imagemodal import ImageModal
+ additional_blocks.append(NestedXBlockSpec(
+ ImageModal, category='imagemodal', label=_(u"Image Modal")
+ ))
+ except ImportError:
+ pass
+
+ message_block_shims = [
+ NestedXBlockSpec(
+ MentoringMessageBlock,
+ category='pb-message',
+ boilerplate=message_type,
+ label=get_message_label(message_type),
+ )
+ for message_type in (
+ 'completed',
+ 'incomplete',
+ 'max_attempts_reached',
+ )
+ ]
+
+ if self.is_assessment:
+ message_block_shims.append(
+ NestedXBlockSpec(
+ MentoringMessageBlock,
+ category='pb-message',
+ boilerplate='on-assessment-review',
+ label=get_message_label('on-assessment-review'),
+ )
+ )
+
+ return [
+ NestedXBlockSpec(AnswerBlock, boilerplate='studio_default'),
+ MCQBlock, RatingBlock, MRQBlock,
+ NestedXBlockSpec(None, category="html", label=self._("HTML")),
+ AnswerRecapBlock, MentoringTableBlock, PlotBlock, SliderBlock
+ ] + additional_blocks + message_block_shims
+
@property
def is_assessment(self):
""" Checks if mentoring XBlock is in assessment mode """
@@ -817,23 +882,19 @@ def author_edit_view(self, context):
"""
Add some HTML to the author view that allows authors to add child blocks.
"""
- fragment = Fragment(u'
') # This DIV is needed for CSS to apply to the previews
- self.render_children(context, fragment, can_reorder=True, can_add=False)
- fragment.add_content(u'
')
-
- # Show buttons to add review-related child blocks only in assessment mode.
- fragment.add_content(loader.render_template('templates/html/mentoring_add_buttons.html', {
- "show_review": self.is_assessment,
- }))
+ local_context = context.copy()
+ local_context['author_edit_view'] = True
+ fragment = super(MentoringBlock, self).author_edit_view(local_context)
fragment.add_content(loader.render_template('templates/html/mentoring_url_name.html', {
- "url_name": self.url_name
+ 'url_name': self.url_name
}))
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css'))
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder-edit.css'))
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder-tinymce-content.css'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/util.js'))
- fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring_edit.js'))
- fragment.initialize_js('MentoringEditComponents')
+ fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/container_edit.js'))
+ fragment.initialize_js('ProblemBuilderContainerEdit')
+
return fragment
@staticmethod
diff --git a/problem_builder/message.py b/problem_builder/message.py
index 7315c98d..a1bf3942 100644
--- a/problem_builder/message.py
+++ b/problem_builder/message.py
@@ -45,6 +45,7 @@ class MentoringMessageBlock(XBlock, StudioEditableXBlockMixin, XBlockWithTransla
MESSAGE_TYPES = {
"completed": {
"display_name": _(u"Completed"),
+ "studio_label": _(u'Message (Complete)'),
"long_display_name": _(u"Message shown when complete"),
"default": _(u"Great job!"),
"description": _(
@@ -54,6 +55,7 @@ class MentoringMessageBlock(XBlock, StudioEditableXBlockMixin, XBlockWithTransla
},
"incomplete": {
"display_name": _(u"Incomplete"),
+ "studio_label": _(u'Message (Incomplete)'),
"long_display_name": _(u"Message shown when incomplete"),
"default": _(u"Not quite! You can try again, though."),
"description": _(
@@ -64,6 +66,7 @@ class MentoringMessageBlock(XBlock, StudioEditableXBlockMixin, XBlockWithTransla
},
"max_attempts_reached": {
"display_name": _(u"Reached max. # of attempts"),
+ "studio_label": _(u'Message (Max # Attempts)'),
"long_display_name": _(u"Message shown when student reaches max. # of attempts"),
"default": _(u"Sorry, you have used up all of your allowed submissions."),
"description": _(
@@ -74,6 +77,7 @@ class MentoringMessageBlock(XBlock, StudioEditableXBlockMixin, XBlockWithTransla
},
"on-assessment-review": {
"display_name": _(u"Review with attempts left"),
+ "studio_label": _(u'Message (Assessment Review)'),
"long_display_name": _(u"Message shown during review when attempts remain"),
"default": _(
u"Note: if you retake this assessment, only your final score counts. "
@@ -100,6 +104,8 @@ class MentoringMessageBlock(XBlock, StudioEditableXBlockMixin, XBlockWithTransla
},
}
+ has_author_view = True
+
content = String(
display_name=_("Message"),
help=_("Message to display upon completion"),
@@ -189,3 +195,7 @@ class CompletedMentoringMessageShim(object):
class IncompleteMentoringMessageShim(object):
CATEGORY = 'pb-message'
STUDIO_LABEL = _("Message (Incomplete)")
+
+
+def get_message_label(type):
+ return MentoringMessageBlock.MESSAGE_TYPES[type]['studio_label']
diff --git a/problem_builder/questionnaire.py b/problem_builder/questionnaire.py
index 5d338e90..595bb25f 100644
--- a/problem_builder/questionnaire.py
+++ b/problem_builder/questionnaire.py
@@ -32,7 +32,6 @@
from xblockutils.studio_editable import StudioEditableXBlockMixin, StudioContainerXBlockMixin, XBlockWithPreviewMixin
from .choice import ChoiceBlock
-from .mentoring import MentoringBlock
from .message import MentoringMessageBlock
from .mixins import QuestionMixin, XBlockWithTranslationServiceMixin
from .tip import TipBlock
@@ -94,8 +93,10 @@ def student_view(self, context=None):
fragment = Fragment(loader.render_template(template_path, context))
# If we use local_resource_url(self, ...) the runtime may insert many identical copies
- # of questionnaire.[css/js] into the DOM. So we use the mentoring block here if possible
+ # of questionnaire.[css/js] into the DOM. So we use the mentoring block here if possible.
block_with_resources = self.get_parent()
+ from .mentoring import MentoringBlock
+ # We use an inline import here to avoid a circular dependency with the .mentoring module.
if not isinstance(block_with_resources, MentoringBlock):
block_with_resources = self
fragment.add_css_url(self.runtime.local_resource_url(block_with_resources, 'public/css/questionnaire.css'))
diff --git a/problem_builder/templates/html/mentoring_add_buttons.html b/problem_builder/templates/html/mentoring_add_buttons.html
deleted file mode 100644
index e9ac09a0..00000000
--- a/problem_builder/templates/html/mentoring_add_buttons.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{% load i18n %}
-
-
-
-
{% trans "Add New Component" %}
-
-
-