Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions problem_builder/answer.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,23 @@ def get_model_object(self, name=None):
)
return answer_data

@property
def student_input(self):
if self.name:
return self.get_model_object().student_input
return ''

@XBlock.json_handler
def answer_value(self, data, suffix=''):
""" Current value of the answer, for refresh by client """
return {'value': self.student_input}

@XBlock.json_handler
def refresh_html(self, data, suffix=''):
""" Complete HTML view of the XBlock, for refresh by client """
frag = self.mentoring_view({})
return {'html': frag.content}

def validate_field_data(self, validation, data):
"""
Validate this block's field data.
Expand Down Expand Up @@ -277,12 +294,6 @@ class AnswerRecapBlock(AnswerMixin, StudioEditableXBlockMixin, XBlock):

css_path = 'public/css/answer.css'

@property
def student_input(self):
if self.name:
return self.get_model_object().student_input
return ''

def mentoring_view(self, context=None):
""" Render this XBlock within a mentoring block. """
context = context.copy() if context else {}
Expand All @@ -308,6 +319,8 @@ def mentoring_view(self, context=None):

fragment = Fragment(html)
fragment.add_css_url(self.runtime.local_resource_url(self, self.css_path))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/answer_recap.js'))
fragment.initialize_js('AnswerRecapBlock')
return fragment

def student_view(self, context=None):
Expand Down
10 changes: 8 additions & 2 deletions problem_builder/mentoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,10 +759,16 @@ def get_content_titles(self):
"""
By default, each Sequential block in a course ("Subsection" in Studio parlance) will
display the display_name of each descendant in a tooltip above the content. We don't
want that - we only want to display the mentoring block as a whole as one item.
want that - we only want to display one title for this mentoring block as a whole.
Otherwise things like "Choice (yes) (Correct)" will appear in the tooltip.

If this block has no title set, don't display any title. Then, if this is the only block
in the unit, the unit's title will be used. (Why isn't it always just used?)
"""
return [self.display_name]
has_explicitly_set_title = self.fields['display_name'].is_set_on(self)
if has_explicitly_set_title:
return [self.display_name]
return []

@staticmethod
def workbench_scenarios():
Expand Down
24 changes: 24 additions & 0 deletions problem_builder/public/js/answer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ function AnswerBlock(runtime, element) {
if (completed === 'True' && this.mode === 'standard') {
checkmark.addClass('checkmark-correct icon-ok fa-check');
}

// In the LMS, the HTML of multiple units can be loaded at once,
// and the user can flip among them. If that happens, the answer in
// our HTML may be out of date.
this.refreshAnswer();
},

submit: function() {
Expand Down Expand Up @@ -69,6 +74,25 @@ function AnswerBlock(runtime, element) {
}
}
return true;
},

refreshAnswer: function() {
$.ajax({
type: 'POST',
url: runtime.handlerUrl(element, 'answer_value'),
data: '{}',
dataType: 'json',
success: function(data) {
// Update the answer to the latest, unless the user has made an edit
var newAnswer = data.value;
var $textarea = $(':input', element);
var currentAnswer = $textarea.val();
var origAnswer = $('.orig-student-answer', element).text();
if (currentAnswer == origAnswer && currentAnswer != newAnswer) {
$textarea.val(newAnswer);
}
},
});
}
};
}
22 changes: 22 additions & 0 deletions problem_builder/public/js/answer_recap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function AnswerRecapBlock(runtime, element) {
return {
init: function(options) {
// In the LMS, the HTML of multiple units can be loaded at once,
// and the user can flip among them. If that happens, the answer in
// our HTML may be out of date.
this.refreshAnswer();
},

refreshAnswer: function() {
$.ajax({
type: 'POST',
url: runtime.handlerUrl(element, 'refresh_html'),
data: '{}',
dataType: 'json',
success: function(data) {
$(element).html(data.html);
}
});
}
};
}
1 change: 1 addition & 0 deletions problem_builder/templates/html/answer_editable.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
class="answer editable" cols="50" rows="10" name="input"
data-min_characters="{{ self.min_characters }}"
>{{ self.student_input }}</textarea>
<div style="display: none;" class="orig-student-answer">{{ self.student_input }}</div> <!-- To detect edits -->
<span class="answer-checkmark fa icon-2x"></span>
</div>
2 changes: 1 addition & 1 deletion problem_builder/templates/html/answer_read_only.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% load i18n %}
<div class="xblock-answer" data-completed="{{ student_input|yesno:"true,false" }}">
<div class="xblock-answer">
{% if not hide_header %}<h3 class="question-title">{{ title }}</h3>{% endif %}
{% if description %}<p>{{ description|safe }}</p>{% endif %}
<blockquote class="answer read_only">
Expand Down
16 changes: 16 additions & 0 deletions problem_builder/tests/unit/test_mentoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from problem_builder.mentoring import _default_theme_config


@ddt.ddt
class TestMentoringBlock(unittest.TestCase):
def test_sends_progress_event_when_rendered_student_view_with_display_submit_false(self):
block = MentoringBlock(MagicMock(), DictFieldData({
Expand All @@ -31,6 +32,21 @@ def test_does_not_send_progress_event_when_rendered_student_view_with_display_su

self.assertFalse(patched_runtime.publish.called)

@ddt.data(True, False)
def test_get_content_titles(self, has_title_set):
"""
Test that we don't send a title to the LMS for the sequential's tooltips when no title
is set
"""
if has_title_set:
data = {'display_name': 'Custom Title'}
expected = ['Custom Title']
else:
data = {}
expected = []
block = MentoringBlock(MagicMock(), DictFieldData(data), Mock())
self.assertEqual(block.get_content_titles(), expected)


@ddt.ddt
class TestMentoringBlockTheming(unittest.TestCase):
Expand Down