diff --git a/problem_builder/mcq.py b/problem_builder/mcq.py index e658f2ff..55cc78af 100644 --- a/problem_builder/mcq.py +++ b/problem_builder/mcq.py @@ -115,15 +115,13 @@ def submit(self, submission): log.debug(u'MCQ submission result: %s', result) return result - def author_edit_view(self, context): + def get_author_edit_view_fragment(self, context): """ The options for the 1-5 values of the Likert scale aren't child blocks but we want to show them in the author edit view, for clarity. """ fragment = Fragment(u"
{}
".format(self.question)) self.render_children(context, fragment, can_reorder=True, can_add=False) - fragment.add_content(loader.render_template('templates/html/questionnaire_add_buttons.html', {})) - fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/questionnaire-edit.css')) return fragment def validate_field_data(self, validation, data): @@ -194,7 +192,7 @@ def human_readable_choices(self): {"display_name": dn, "value": val} for val, dn in zip(self.FIXED_VALUES, display_names) ] + super(RatingBlock, self).human_readable_choices - def author_edit_view(self, context): + def get_author_edit_view_fragment(self, context): """ The options for the 1-5 values of the Likert scale aren't child blocks but we want to show them in the author edit view, for clarity. @@ -207,6 +205,4 @@ def author_edit_view(self, context): 'accepted_statuses': [None] + [self.describe_choice_correctness(c) for c in "12345"], })) self.render_children(context, fragment, can_reorder=True, can_add=False) - fragment.add_content(loader.render_template('templates/html/questionnaire_add_buttons.html', {})) - fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/questionnaire-edit.css')) return fragment diff --git a/problem_builder/mentoring.py b/problem_builder/mentoring.py index 45184db6..84e685fc 100644 --- a/problem_builder/mentoring.py +++ b/problem_builder/mentoring.py @@ -314,8 +314,9 @@ def student_view(self, context): 'child_content': child_content, 'missing_dependency_url': self.has_missing_dependency and self.next_step_url, })) - fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/mentoring.css')) + fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/vendor/underscore-min.js')) + fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/util.js')) js_file = 'public/js/mentoring_{}_view.js'.format('assessment' if self.is_assessment else 'standard') fragment.add_javascript_url(self.runtime.local_resource_url(self, js_file)) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring.js')) @@ -731,7 +732,7 @@ def author_preview_view(self, context): fragment.add_content(loader.render_template('templates/html/mentoring_url_name.html', { "url_name": self.url_name })) - fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/mentoring_edit.css')) + fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder-edit.css')) self.include_theme_files(fragment) return fragment @@ -746,7 +747,10 @@ def author_edit_view(self, context): fragment.add_content(loader.render_template('templates/html/mentoring_url_name.html', { "url_name": self.url_name })) - fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/mentoring_edit.css')) + 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') return fragment diff --git a/problem_builder/public/css/mentoring_edit.css b/problem_builder/public/css/problem-builder-edit.css similarity index 100% rename from problem_builder/public/css/mentoring_edit.css rename to problem_builder/public/css/problem-builder-edit.css diff --git a/problem_builder/public/css/problem-builder-tinymce-content.css b/problem_builder/public/css/problem-builder-tinymce-content.css new file mode 100644 index 00000000..75c46e9b --- /dev/null +++ b/problem_builder/public/css/problem-builder-tinymce-content.css @@ -0,0 +1,15 @@ +/* Some styling to make clarifications stand out a bit in + studio HTML edit view. */ + +.mce-content-body .pb-clarification { + color: #999; + font-size: 0.75em; +} + +.mce-content-body .pb-clarification::before { + content: "(?)[" +} + +.mce-content-body .pb-clarification::after { + content: "]" +} diff --git a/problem_builder/public/css/mentoring.css b/problem_builder/public/css/problem-builder.css similarity index 95% rename from problem_builder/public/css/mentoring.css rename to problem_builder/public/css/problem-builder.css index a71ac3af..5bef983a 100644 --- a/problem_builder/public/css/mentoring.css +++ b/problem_builder/public/css/problem-builder.css @@ -173,3 +173,11 @@ float: right; display: none; } + +.pb-clarification span.clarification i { + font-style: normal; +} + +.pb-clarification span.clarification i:hover { + color: rgb(0, 159, 230); +} diff --git a/problem_builder/public/js/mentoring.js b/problem_builder/public/js/mentoring.js index d8107055..2541580a 100644 --- a/problem_builder/public/js/mentoring.js +++ b/problem_builder/public/js/mentoring.js @@ -113,6 +113,8 @@ function MentoringBlock(runtime, element) { } } + ProblemBuilderUtil.transformClarifications(element); + if (data.mode === 'standard') { MentoringStandardView(runtime, element, mentoring); } diff --git a/problem_builder/public/js/mentoring_edit.js b/problem_builder/public/js/mentoring_edit.js index 693a609e..b5f545a5 100644 --- a/problem_builder/public/js/mentoring_edit.js +++ b/problem_builder/public/js/mentoring_edit.js @@ -17,5 +17,8 @@ function MentoringEditComponents(runtime, element) { $(this).addClass('disabled'); } }); + + ProblemBuilderUtil.transformClarifications(element); + runtime.listenTo('deleted-child', updateButtons); } diff --git a/problem_builder/public/js/questionnaire_edit.js b/problem_builder/public/js/questionnaire_edit.js new file mode 100644 index 00000000..fb266ad5 --- /dev/null +++ b/problem_builder/public/js/questionnaire_edit.js @@ -0,0 +1,4 @@ +function QuestionnaireEdit(runtime, element) { + 'use strict'; + ProblemBuilderUtil.transformClarifications(element); +} diff --git a/problem_builder/public/js/util.js b/problem_builder/public/js/util.js new file mode 100644 index 00000000..b4d7d1f6 --- /dev/null +++ b/problem_builder/public/js/util.js @@ -0,0 +1,40 @@ +window.ProblemBuilderUtil = { + + transformClarifications: function(element) { + var $element = $(element); + + var transformExisting = function(node) { + $('.pb-clarification', node).each(function() { + var item = $(this); + var content = item.html(); + var clarification = $( + '' + + '' + + '' + + '' + ); + clarification.find('i').attr('data-tooltip', content); + clarification.find('span.sr').html(content); + item.empty().append(clarification); + }); + }; + + // Transform all span.pb-clarifications already existing inside the element. + transformExisting($element); + + // Transform all future span.pb-clarifications using mutation observer. + // It's only needed in the Studio when editing xblock children because the + // block's JS init function isn't called after edits in the Studio. + if (window.MutationObserver) { + var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + Array.prototype.forEach.call(mutation.addedNodes, function(node) { + transformExisting(node); + }); + }) + }); + observer.observe($element[0], {childList: true, subtree: true}); + } + } + +}; diff --git a/problem_builder/questionnaire.py b/problem_builder/questionnaire.py index c3108bec..f35c7a32 100644 --- a/problem_builder/questionnaire.py +++ b/problem_builder/questionnaire.py @@ -167,13 +167,21 @@ def get_submission_display(self, submission): return choice.content return submission + def get_author_edit_view_fragment(self, context): + fragment = super(QuestionnaireAbstractBlock, self).author_edit_view(context) + return fragment + def author_edit_view(self, context): """ Add some HTML to the author view that allows authors to add choices and tips. """ - fragment = super(QuestionnaireAbstractBlock, self).author_edit_view(context) + fragment = self.get_author_edit_view_fragment(context) fragment.add_content(loader.render_template('templates/html/questionnaire_add_buttons.html', {})) + 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/questionnaire-edit.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/questionnaire_edit.js')) + fragment.initialize_js('QuestionnaireEdit') return fragment def validate_field_data(self, validation, data): diff --git a/problem_builder/templates/html/ratingblock.html b/problem_builder/templates/html/ratingblock.html index 0574b5e7..90d04d7b 100644 --- a/problem_builder/templates/html/ratingblock.html +++ b/problem_builder/templates/html/ratingblock.html @@ -15,8 +15,8 @@{{ question }}
+{{ question|safe }}
This is some raw {clarify} HTML code.