Convert Problem Block Mako Templates to Django Templates (#37570)

* fix: convert mako to django templates for problem block

* fix: pylint issues
This commit is contained in:
Irtaza Akram
2025-12-09 19:29:06 +05:00
committed by GitHub
parent c3e85426cb
commit 99c6e901d9
38 changed files with 664 additions and 747 deletions

View File

@@ -319,6 +319,7 @@ MAKO_TEMPLATE_DIRS_BASE = [
OPENEDX_ROOT / 'core' / 'djangoapps' / 'dark_lang' / 'templates',
OPENEDX_ROOT / 'core' / 'lib' / 'license' / 'templates',
CMS_ROOT / 'djangoapps' / 'pipeline_js' / 'templates',
XMODULE_ROOT / 'capa' / 'templates',
]
CONTEXT_PROCESSORS = (

View File

@@ -1,169 +0,0 @@
<%page expression_filter="h"/>
<%!
from django.utils.translation import ngettext, gettext as _
from openedx.core.djangolib.markup import HTML, Text
%>
<%namespace name='static' file='static_content.html'/>
<h3 class="hd hd-3 problem-header" id="${ short_id }-problem-title" aria-describedby="${ id }-problem-progress" tabindex="-1">
${ problem['name'] }
</h3>
<div class="problem-progress" id="${ id }-problem-progress"></div>
<div class="problem">
${ HTML(problem['html']) }
<div class="action">
<input type="hidden" name="problem_id" value="${ problem['name'] }" />
% if demand_hint_possible:
<div class="problem-hint">
<%include file="problem_notifications.html" args="
notification_name='hint',
notification_type='problem-hint',
notification_icon='fa-question',
notification_message=''"
/>
</div>
% endif
<div class="problem-action-buttons-wrapper">
% if demand_hint_possible:
<span class="problem-action-button-wrapper">
<button type="button" class="hint-button problem-action-btn btn-link btn-small" data-value="${_('Hint')}" ${'' if should_enable_next_hint else 'disabled'}>${_('Hint')}</button>
</span>
% endif
% if save_button:
<span class="problem-action-button-wrapper">
<button type="button" class="save problem-action-btn btn-link btn-small" data-value="${_('Save')}">
<span aria-hidden="true">${_('Save')}</span>
<span class="sr">${_("Save your answer")}</span>
</button>
</span>
% endif
% if attempts_used and reset_button:
<span class="problem-action-button-wrapper">
<button type="button" class="reset problem-action-btn btn-link btn-small" data-value="${_('Reset')}"><span aria-hidden="true">${_('Reset')}</span><span class="sr">${_("Reset your answer")}</span></button>
</span>
% endif
% if answer_available:
<span class="problem-action-button-wrapper">
<button type="button" class="show problem-action-btn btn-link btn-small" aria-describedby="${ short_id }-problem-title"><span class="show-label">${_('Show answer')}</span></button>
</span>
% endif
</div>
<div class="submit-attempt-container">
<button type="button" class="submit btn-brand" data-submitting="${ submit_button_submitting }" data-value="${ submit_button }" data-should-enable-submit-button="${ should_enable_submit_button }" aria-describedby="submission_feedback_${short_id}" ${'' if should_enable_submit_button else 'disabled'}>
<span class="submit-label">${ submit_button }</span>
</button>
% if submit_disabled_cta:
% if submit_disabled_cta.get('event_data'):
<button class="submit-cta-link-button btn-link btn-small" onclick="emit_event(${submit_disabled_cta['event_data']})">
${submit_disabled_cta['link_name']}
</button>
<span class="submit-cta-description" tabindex="0" role="note" aria-label="description">
<span data-tooltip="${submit_disabled_cta['description']}" data-tooltip-show-on-click="true"
class="fa fa-info-circle fa-lg" aria-hidden="true">
</span>
</span>
<span class="sr">(${submit_disabled_cta['description']})</span>
% else:
<form class="submit-cta" method="post" action="${submit_disabled_cta.get('link')}">
% if submit_disabled_cta.get('link'):
<input type="hidden" id="csrf_token" name="csrfmiddlewaretoken" value="${csrf_token}">
% for form_name, form_value in submit_disabled_cta['form_values'].items():
<input type="hidden" name="${form_name}" value="${form_value}">
% endfor
<button class="submit-cta-link-button btn-link btn-small">
${submit_disabled_cta['link_name']}
</button>
% endif
<span class="submit-cta-description" tabindex="0" role="note" aria-label="description">
<span data-tooltip="${submit_disabled_cta['description']}" data-tooltip-show-on-click="true"
class="fa fa-info-circle fa-lg" aria-hidden="true">
</span>
</span>
<span class="sr">(${submit_disabled_cta['description']})</span>
</form>
% endif
% endif
<div class="submission-feedback ${'cta-enabled' if submit_disabled_cta else ''}" id="submission_feedback_${short_id}">
## When attempts are not 0, the CTA above will contain a message about the number of used attempts
% if attempts_allowed and (not submit_disabled_cta or attempts_used == 0):
${ngettext("You have used {num_used} of {num_total} attempt", "You have used {num_used} of {num_total} attempts", attempts_allowed).format(num_used=attempts_used, num_total=attempts_allowed)}
% endif
% if grading_method:
<div>${Text(_("Grading method: {grading_method}")).format(grading_method=grading_method)}</div>
% endif
<span class="sr">${_("Some problems have options such as save, reset, hints, or show answer. These options follow the Submit button.")}</span>
</div>
</div>
</div>
<%include file="problem_notifications.html" args="
notification_type='warning',
notification_icon='fa-exclamation-circle',
notification_name='gentle-alert',
notification_message=''"
/>
% if answer_notification_type:
% if 'correct' == answer_notification_type:
<%include file="problem_notifications.html" args="
notification_type='success',
notification_icon='fa-check',
notification_name='submit',
is_hidden=False,
notification_message=answer_notification_message"
/>
% endif
% if 'incorrect' == answer_notification_type:
<%include file="problem_notifications.html" args="
notification_type='error',
notification_icon='fa-close',
notification_name='submit',
is_hidden=False,
notification_message=answer_notification_message"
/>
% endif
% if 'partially-correct' == answer_notification_type:
<%include file="problem_notifications.html" args="
notification_type='success',
notification_icon='fa-asterisk',
notification_name='submit',
is_hidden=False,
notification_message=answer_notification_message"
/>
% endif
% if 'submitted' == answer_notification_type:
<%include file="problem_notifications.html" args="
notification_type='general',
notification_icon='fa-info-circle',
notification_name='submit',
is_hidden=False,
notification_message=answer_notification_message"
/>
% endif
% endif
<%include file="problem_notifications.html" args="
notification_type='warning',
notification_icon='fa-save',
notification_name='save',
notification_message=save_message,
is_hidden=not has_saved_answers"
/>
<%
notification_message=_('Answers are displayed within the problem')
%>
<%include file="problem_notifications.html" args="
notification_type='general',
notification_icon='fa-info-circle',
notification_name='show-answer',
notification_message=notification_message,
is_hidden=True"
/>
</div>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>

View File

@@ -1,13 +0,0 @@
<div id="problem_${element_id}" class="problems-wrapper" role="group"
aria-labelledby="${element_id}-problem-title"
data-problem-id="${id}" data-url="${ajax_url}"
data-problem-score="${current_score}"
data-problem-total-possible="${total_possible}"
data-attempts-used="${attempts_used}"
data-content="${content | h}"
data-graded="${graded}">
<p class="loading-spinner">
<i class="fa fa-spinner fa-pulse fa-2x fa-fw"></i>
<span class="sr">Loading&hellip;</span>
</p>
</div>

View File

@@ -1,19 +0,0 @@
<%page expression_filter="h" args="notification_name, notification_type, notification_icon,
notification_message, should_enable_next_hint, is_hidden=True"/>
<%! from django.utils.translation import gettext as _ %>
<div class="notification ${notification_type} ${'notification-'}${notification_name}
${'' if not is_hidden else 'is-hidden' }"
tabindex="-1">
<span class="icon fa ${notification_icon}" aria-hidden="true"></span>
<span class="notification-message" aria-describedby="${ short_id }-problem-title">${notification_message}
</span>
<div class="notification-btn-wrapper">
% if notification_name == 'hint':
<button type="button" class="btn btn-default btn-small notification-btn hint-button">
${_('Next Hint')}
</button>
% endif
<button type="button" class="btn btn-default btn-small notification-btn review-btn sr">${_('Review')}</button>
</div>
</div>

View File

@@ -1476,6 +1476,7 @@ class DjangoTemplateLinter(BaseLinter):
django_trans_missing_escape='django-trans-missing-escape',
django_trans_invalid_escape_filter='django-trans-invalid-escape-filter',
django_trans_escape_variable_mismatch='django-trans-escape-variable-mismatch',
django_trans_escape_filter_parse_error='django-trans-escape-filter-parse-error',
django_blocktrans_missing_escape_filter='django-blocktrans-missing-escape-filter',
django_blocktrans_parse_error='django-blocktrans-parse-error',
django_blocktrans_escape_filter_parse_error='django-blocktrans-escape-filter-parse-error',

View File

@@ -8,6 +8,7 @@
"django-html-interpolation-missing-safe-filter": 0,
"django-trans-escape-variable-mismatch": 0,
"django-trans-invalid-escape-filter": 0,
"django-trans-escape-filter-parse-error": 0,
"django-trans-missing-escape": 0,
"javascript-concat-html": 2,
"javascript-escape": 1,

View File

@@ -10,8 +10,7 @@ import sys
from io import BytesIO
from calc import UndefinedVariable
from mako.lookup import TemplateLookup
from path import Path as path
from django.template.loader import get_template
from xmodule.capa.capa_problem import LoncapaProblem
@@ -21,14 +20,13 @@ log = logging.getLogger("capa.checker")
class DemoSystem(object): # lint-amnesty, pylint: disable=missing-class-docstring
def __init__(self):
self.lookup = TemplateLookup(directories=[path(__file__).dirname() / "templates"])
self.DEBUG = True
def render_template(self, template_filename, dictionary):
"""
Render the specified template with the given dictionary of context data.
"""
return self.lookup.get_template(template_filename).render(**dictionary)
return get_template(template_filename).render(dictionary)
def main(): # lint-amnesty, pylint: disable=missing-function-docstring

View File

@@ -18,7 +18,7 @@ Module containing the problem elements which render into input objects
- formulaequationinput
- chemicalequationinput
These are matched by *.html files templates/*.html which are mako templates with the
These are matched by *.html files templates/*.html which are django templates with the
actual html.
Each input type takes the xml tree as 'element', the previous answer as 'value', and the

View File

@@ -1,62 +1,62 @@
<%! from openedx.core.djangolib.markup import HTML %>
{% load static %}
<div class="annotation-input">
<div class="script_placeholder" data-src="${STATIC_URL}js/capa/annotationinput.js"/>
<div class="script_placeholder" data-src="{% static 'js/capa/annotationinput.js' %}"/>
<div class="annotation-header">
${title}
{{ title|safe }}
% if return_to_annotation:
{% if return_to_annotation %}
<a class="annotation-return" href="javascript:void(0)">Return to Annotation</a><br/>
% endif
{% endif %}
</div>
<div class="annotation-body">
<div class="block block-highlight">${text}</div>
<div class="block block-comment">${comment}</div>
<div class="block block-highlight">{{ text|safe }}</div>
<div class="block block-comment">{{ comment|safe }}</div>
<div class="block">${comment_prompt}</div>
<textarea class="comment" id="input_${id}_comment" name="input_${id}_comment" aria-describedby="answer_${id}">${comment_value|h}</textarea>
<div class="block">{{ comment_prompt|safe }}</div>
<textarea class="comment" id="input_{{ id }}_comment" name="input_{{ id }}_comment" aria-describedby="answer_{{ id }}">{{ comment_value|safe }}</textarea>
<div class="block" id="label_${id}">${tag_prompt}</div>
<div class="block" id="label_{{ id }}">{{ tag_prompt|safe }}</div>
<ul class="tags">
% for option in options:
{% for option in options %}
<li>
% if has_options_value:
% if all(c == status.classname for c in (option['choice'], status)):
<span class="tag-status ${status.classname}" aria-describedby="input_${id}_comment">
<%include file="status_span.html" args="status=status"/>
{% if has_options_value %}
{% if option.choice == status.classname and status == status.classname %}
<span class="tag-status {{ status.classname }}" aria-describedby="input_{{ id }}_comment">
{% include "status_span.html" with status=status %}
</span>
% endif
% endif
{% endif %}
{% endif %}
<span class="tag
% if option['id'] in options_value:
{% if option.id in options_value %}
selected
% endif
" data-id="${option['id']}">
${option['description']}
{% endif %}
" data-id="{{ option.id }}">
{{ option.description|safe }}
</span>
</li>
% endfor
{% endfor %}
</ul>
% if debug:
{% if debug %}
<div class="debug-value">
Rendered with value:<br/>
<pre>${value|h}</pre>
<pre>{{ value|safe }}</pre>
Current input value:<br/>
<input type="text" class="value" name="input_${id}" id="input_${id}" value="${value|h}" />
<input type="text" class="value" name="input_{{ id }}" id="input_{{ id }}" value="{{ value }}" />
</div>
% else:
<input type="hidden" class="value" name="input_${id}" id="input_${id}" value="${value|h}" />
% endif
{% else %}
<input type="hidden" class="value" name="input_{{ id }}" id="input_{{ id }}" value="{{ value }}" />
{% endif %}
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
<p id="answer_${id}" class="answer answer-annotation"></p>
<p id="answer_{{ id }}" class="answer answer-annotation"></p>
</div>
</div>
% if msg:
<span class="message" aria-describedby="label_${id}" tabindex="-1">${HTML(msg)}</span>
% endif
{% if msg %}
<span class="message" aria-describedby="label_{{ id }}" tabindex="-1">{{ msg|safe }}</span>
{% endif %}

View File

@@ -1,22 +1,21 @@
<%! from xmodule.capa.util import remove_markup %>
<div id="chemicalequationinput_${id}" class="chemicalequationinput">
<div class="script_placeholder" data-src="${previewer}"/>
<div id="chemicalequationinput_{{ id }}" class="chemicalequationinput">
<div class="script_placeholder" data-src="{{ previewer }}"/>
<div class="${status.classname}">
<div class="{{ status.classname }}">
<input type="text" name="input_${id}" id="input_${id}" aria-label="${remove_markup(response_data['label'])}"
aria-describedby="answer_${id}" data-input-id="${id}" value="${value|h}"
% if size:
size="${size}"
% endif
<input type="text" name="input_{{ id }}" id="input_{{ id }}" aria-label="{{ response_data.label|striptags }}"
aria-describedby="answer_{{ id }}" data-input-id="{{ id }}" value="{{ value }}"
{% if size %}
size="{{ size }}"
{% endif %}
/>
<p class="indicator-container">
${value|h}
<%include file="status_span.html" args="status=status, status_id=id"/>
{{ value }}
{% include "status_span.html" with status=status status_id=id %}
</p>
<div id="input_${id}_preview" class="equation"></div>
<p id="answer_${id}" class="answer"></p>
<div id="input_{{ id }}_preview" class="equation"></div>
<p id="answer_{{ id }}" class="answer"></p>
</div>
</div>

View File

@@ -1,64 +1,46 @@
<%page expression_filter="h"/>
<%!
from openedx.core.djangolib.markup import HTML
%>
<%
def is_radio_input(choice_id):
return input_type == 'radio' and ((isinstance(value, str) and (choice_id == value)) or (
not isinstance(value, str) and choice_id in value
))
%>
<div class="choicegroup capa_inputtype" id="inputtype_${id}">
<fieldset ${describedby_html}>
% if response_data['label']:
<legend id="${id}-legend" class="response-fieldset-legend field-group-hd">${response_data['label']}</legend>
% endif
% for description_id, description_text in response_data['descriptions'].items():
<p class="question-description" id="${description_id}">${description_text}</p>
% endfor
% for choice_id, choice_label in choices:
<%
label_class = 'response-label field-label label-inline'
input_class = 'field-input input-' + input_type
input_checked = ''
if is_radio_input(choice_id) or (input_type != 'radio' and choice_id in value):
input_class += ' submitted'
if status.classname and not show_correctness == 'never':
label_class += ' choicegroup_' + status.classname
%>
<div class="choicegroup capa_inputtype" id="inputtype_{{ id }}">
<fieldset {{ describedby_html }}>
{% if response_data.label %}
<legend id="{{ id }}-legend" class="response-fieldset-legend field-group-hd">{{ response_data.label }}</legend>
{% endif %}
{% for description_id, description_text in response_data.descriptions.items %}
<p class="question-description" id="{{ description_id }}">{{ description_text|safe }}</p>
{% endfor %}
{% for choice_id, choice_label in choices %}
<div class="field">
<input type="${input_type}" name="input_${id}${name_array_suffix}" id="input_${id}_${choice_id}"
class="${input_class}" value="${choice_id}"
## If the student selected this choice...
% if is_radio_input(choice_id):
<input type="{{ input_type }}" name="input_{{ id }}{{ name_array_suffix }}" id="input_{{ id }}_{{ choice_id }}"
class="field-input input-{{ input_type }}{% if input_type == 'radio' and choice_id == value or input_type != 'radio' and choice_id in value %} submitted{% endif %}" value="{{ choice_id }}"
{# If the student selected this choice... #}
{% if input_type == 'radio' and choice_id == value or input_type != 'radio' and choice_id in value %}
checked="true"
% elif input_type != 'radio' and choice_id in value:
{% elif input_type != 'radio' and choice_id in value %}
checked="true"
% endif
/><label id="${id}-${choice_id}-label" for="input_${id}_${choice_id}"
class="${label_class}"
${describedby_html}
{% endif %}
/><label id="{{ id }}-{{ choice_id }}-label" for="input_{{ id }}_{{ choice_id }}"
class="response-label field-label label-inline{% if choice_id in value and status.classname and show_correctness != 'never' %} choicegroup_{{ status.classname }}{% endif %}"
{{ describedby_html }}
>
<div>
${HTML(choice_label)}
{{ choice_label|safe }}
</div>
</label>
</div>
% endfor
<span id="answer_${id}"></span>
{% endfor %}
<span id="answer_{{ id }}"></span>
</fieldset>
<div class="indicator-container">
% if show_correctness != 'never':
<%include file="status_span.html" args="status=status, status_id=id"/>
% else:
<%include file="status_span.html" args="status=status, status_id=id, hide_correctness=True"/>
% endif
{% if show_correctness != 'never' %}
{% include "status_span.html" with status=status status_id=id %}
{% else %}
{% include "status_span.html" with status=status status_id=id hide_correctness=True %}
{% endif %}
</div>
% if show_correctness == "never" and (value or status not in ['unsubmitted']):
<div class="capa_alert">${submitted_message}</div>
%endif
% if msg:
<span class="message" aria-describedby="${id}-legend" tabindex="-1">${HTML(msg)}</span>
% endif
{% if show_correctness == "never" %}
{% if value or status != "unsubmitted" %}
<div class="capa_alert">{{ submitted_message|safe }}</div>
{% endif %}
{% endif %}
{% if msg %}
<span class="message" aria-describedby="{{ id }}-legend" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
</div>

View File

@@ -1,70 +1,72 @@
<%! from xmodule.capa.util import remove_markup
from django.utils.translation import gettext as _
from openedx.core.djangolib.markup import HTML
%>
{% load i18n %}
{% load static %}
<% element_checked = False %>
% for choice_id, _ in choices:
<% choice_id = choice_id %>
%if choice_id in value:
<% element_checked = True %>
%endif
% endfor
<section id="choicetextinput_${id}" class="choicetextinput">
<div class="choicetextgroup capa_inputtype" id="inputtype_${id}">
<div class="script_placeholder" data-src="${STATIC_URL}js/capa/choicetextinput.js"/>
{% with element_checked=False %}
{% for choice_id, _ in choices %}
{% if choice_id in value %}
{% with element_checked=True %}
{% endwith %}
{% endif %}
{% endfor %}
<section id="choicetextinput_{{ id }}" class="choicetextinput">
<div class="choicetextgroup capa_inputtype" id="inputtype_{{ id }}">
<div class="script_placeholder" data-src="{% static 'js/capa/choicetextinput.js' %}"/>
<fieldset aria-label="${remove_markup(response_data['label'])}">
% for choice_id, choice_description in choices:
<% choice_id = choice_id %>
<section id="forinput${choice_id}"
% if input_type == 'radio' and choice_id in value :
% if status.classname:
class="choicetextgroup_${status.classname}"
% endif
% endif
<fieldset aria-label="{{ response_data.label|striptags }}">
{% for choice_id, choice_description in choices %}
<section id="forinput{{ choice_id }}"
{% if input_type == 'radio' and choice_id in value %}
{% if status.classname %}
class="choicetextgroup_{{ status.classname }}"
{% endif %}
{% endif %}
>
<input class="ctinput" type="${input_type}" name="choiceinput_${id}" id="${choice_id}" value="${choice_id}"
<input class="ctinput" type="{{ input_type }}" name="choiceinput_{{ id }}" id="{{ choice_id }}" value="{{ choice_id }}"
% if choice_id in value:
{% if choice_id in value %}
checked="true"
% endif
{% endif %}
/>
% for content_node in choice_description:
% if content_node['type'] == 'text':
{% for content_node in choice_description %}
{% if content_node.type == 'text' %}
<span class="mock_label">
${content_node['contents']}
{{ content_node.contents }}
</span>
% else:
<% my_id = content_node.get('contents','') %>
<% my_val = value.get(my_id,'') %>
<input class="ctinput" type="text" name="${content_node['contents']}" id="${content_node['contents']}" value="${my_val|h}"/>
%endif
{% else %}
{% with my_id=content_node.contents|default:'' %}
{% with my_val=value.my_id|default:'' %}
<input class="ctinput" type="text" name="{{ content_node.contents }}" id="{{ content_node.contents }}" value="{{ my_val }}"/>
{% endwith %}
{% endwith %}
{% endif %}
<span class="mock_label">
${content_node['tail_text']}
{{ content_node.tail_text }}
</span>
% endfor
<p id="answer_${choice_id}" class="answer"></p>
{% endfor %}
<p id="answer_{{ choice_id }}" class="answer"></p>
</section>
% endfor
<span id="answer_${id}"></span>
{% endfor %}
<span id="answer_{{ id }}"></span>
</fieldset>
<input class= "choicetextvalue" type="hidden" name="input_${id}{}" id="input_${id}" value="${value|h}" />
<input class= "choicetextvalue" type="hidden" name="input_{{ id }}{}" id="input_{{ id }}" value="{{ value }}" />
<div class="indicator-container">
% if input_type == 'checkbox' or not element_checked:
<%include file="status_span.html" args="status=status, status_id=id"/>
% endif
{% if input_type == 'checkbox' or not value or status.classname == 'incomplete' or status.classname == 'unsubmitted' or status.classname == 'unanswered' %}
{% include "status_span.html" with status=status status_id=id %}
{% endif %}
</div>
% if show_correctness == "never" and (value or status not in ['unsubmitted']):
<div class="capa_alert">${_(submitted_message)}</div>
%endif
% if msg:
<span class="message" tabindex="-1">${HTML(msg)}</span>
% endif
{% if show_correctness == "never" %}
{% if value or status != "unsubmitted" %}
<div class="capa_alert">{{ submitted_message }}</div>
{% endif %}
{% endif %}
{% if msg %}
<span class="message" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
</div>
</section>
{% endwith %}

View File

@@ -1,5 +1,5 @@
<span class="clarification" tabindex="0" role="note" aria-label="Clarification">
<span data-tooltip="${clarification | h}" data-tooltip-show-on-click="true"
<span data-tooltip="{{ clarification }}" data-tooltip-show-on-click="true"
class="fa fa-info-circle" aria-hidden="true"></span>
<span class="sr">(${clarification})</span>
<span class="sr">({{ clarification }})</span>
</span>

View File

@@ -1,50 +1,46 @@
<%page expression_filter="h"/>
<%!
from django.utils.translation import gettext as _
from openedx.core.djangolib.markup import HTML
%>
<div id="textbox_${id}" class="capa_inputtype textbox cminput">
% if response_data['label']:
<label class="problem-group-label" for="cm-textarea-${id}">${response_data['label']}</label>
% else:
<label class="sr problem-group-label" for="cm-textarea-${id}">${_('Code Editor')}</label>
% endif
<textarea rows="${rows}" cols="${cols}" name="input_${id}"
aria-label="${aria_label}"
aria-describedby="answer_${id}"
id="input_${id}"
{% load i18n %}
<div id="textbox_{{ id }}" class="capa_inputtype textbox cminput">
{% if response_data.label %}
<label class="problem-group-label" for="cm-textarea-{{ id }}">{{ response_data.label }}</label>
{% else %}
<label class="sr problem-group-label" for="cm-textarea-{{ id }}">{% trans "Code Editor" as editor_label %}{{ editor_label|force_escape }}</label>
{% endif %}
<textarea rows="{{ rows }}" cols="{{ cols }}" name="input_{{ id }}"
aria-label="{{ aria_label }}"
aria-describedby="answer_{{ id }}"
id="input_{{ id }}"
tabindex="0"
data-mode="${mode}"
data-tabsize="${tabsize}"
% if linenumbers:
data-mode="{{ mode }}"
data-tabsize="{{ tabsize }}"
{% if linenumbers %}
data-linenums="true"
% endif
% if hidden:
{% endif %}
{% if hidden %}
style="display:none;"
% endif
>${value}</textarea>
<span class="cm-editor-exit-message capa-message" id="cm-editor-exit-message-${id}">
${code_mirror_exit_message}
{% endif %}
>{{ value }}</textarea>
<span class="cm-editor-exit-message capa-message" id="cm-editor-exit-message-{{ id }}">
{{ code_mirror_exit_message }}
</span>
<div class="grader-status" tabindex="-1">
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
% if status == 'queued':
<span style="display:none;" class="xqueue" id="${id}">${queue_len}</span>
% endif
{% if status == 'queued' %}
<span style="display:none;" class="xqueue" id="{{ id }}">{{ queue_len }}</span>
{% endif %}
% if hidden:
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
{% if hidden %}
<div style="display:none;" name="{{ hidden }}" inputid="input_{{ id }}" />
{% endif %}
<p class="debug">${status.display_name}</p>
<p class="debug">{{ status.display_name }}</p>
</div>
<span id="answer_${id}"></span>
<span id="answer_{{ id }}"></span>
<div class="external-grader-message">
${HTML(msg)}
{{ msg|safe }}
</div>
</div>

View File

@@ -1,6 +1,5 @@
<%! from openedx.core.djangolib.markup import HTML %>
<section id="inputtype_${id}" class="capa_inputtype" >
<div class="crystalography_problem" style="width:${width};height:${height}"></div>
<section id="inputtype_{{ id }}" class="capa_inputtype" >
<div class="crystalography_problem" style="width:{{ width }};height:{{ height }}"></div>
<div class="input_lattice">
Lattice: <select></select>
@@ -10,21 +9,21 @@
<div class="script_placeholder" data-src="/static/js/sylvester.js"></div>
<div class="script_placeholder" data-src="/static/js/crystallography.js"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<div class="status ${status.classname}" id="status_${id}">
% endif
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="status {{ status.classname }}" id="status_{{ id }}">
{% endif %}
<input type="text" name="input_${id}" aria-describedby="answer_${id}" id="input_${id}" value="${value|h}" style="display:none;"/>
<input type="text" name="input_{{ id }}" aria-describedby="answer_{{ id }}" id="input_{{ id }}" value="{{ value }}" style="display:none;"/>
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
<p id="answer_${id}" class="answer"></p>
<p id="answer_{{ id }}" class="answer"></p>
% if msg:
<span class="message" tabindex="-1">${HTML(msg)}</span>
% endif
{% if msg %}
<span class="message" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
</section>

View File

@@ -1,19 +1,19 @@
<section id="designprotein2dinput_${id}" class="designprotein2dinput">
<section id="designprotein2dinput_{{ id }}" class="designprotein2dinput">
<div class="script_placeholder" data-src="/static/js/capa/protex/protex.nocache.js?raw"/>
<div class="script_placeholder" data-src="${applet_loader}"/>
<div class="script_placeholder" data-src="{{ applet_loader }}"/>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="{{ status.classname }}" id="status_{{ id }}">
{% endif %}
<div id="protex_container"></div>
<input type="hidden" name="target_shape" id="target_shape" value ="${target_shape}"></input>
<input type="hidden" name="input_${id}" id="input_${id}" aria-describedby="answer_${id}" value="${value|h}"/>
<input type="hidden" name="target_shape" id="target_shape" value ="{{ target_shape }}"></input>
<input type="hidden" name="input_{{ id }}" id="input_{{ id }}" aria-describedby="answer_{{ id }}" value="{{ value }}"/>
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
<p id="answer_${id}" class="answer"></p>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<p id="answer_{{ id }}" class="answer"></p>
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
</section>

View File

@@ -1,34 +1,34 @@
<%! from openedx.core.djangolib.markup import HTML %>
<div id="inputtype_${id}" class="capa_inputtype">
<div class="drag_and_drop_problem_div" id="drag_and_drop_div_${id}"
data-plain-id="${id}">
{% load static %}
<div id="inputtype_{{ id }}" class="capa_inputtype">
<div class="drag_and_drop_problem_div" id="drag_and_drop_div_{{ id }}"
data-plain-id="{{ id }}">
</div>
<div class="drag_and_drop_problem_json" id="drag_and_drop_json_${id}"
style="display:none;">${drag_and_drop_json}</div>
<div class="drag_and_drop_problem_json" id="drag_and_drop_json_{{ id }}"
style="display:none;">{{ drag_and_drop_json|safe }}</div>
<div class="script_placeholder" data-src="${STATIC_URL}js/capa/drag_and_drop.js"></div>
<div class="script_placeholder" data-src="{% static 'js/capa/drag_and_drop.js' %}"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="{{ status.classname }}" id="status_{{ id }}">
{% endif %}
<input type="text" name="input_${id}" id="input_${id}" aria-describedby="answer_${id}" value="${value|h}"
<input type="text" name="input_{{ id }}" id="input_{{ id }}" aria-describedby="answer_{{ id }}" value="{{ value }}"
style="display:none;"/>
<p class="indicator-container drag-and-drop--status" aria-describedby="input_${id}">
<%include file="status_span.html" args="status=status, status_id=id"/>
<p class="indicator-container drag-and-drop--status" aria-describedby="input_{{ id }}">
{% include "status_span.html" with status=status status_id=id %}
</p>
<p id="answer_${id}" class="answer"></p>
<p id="answer_{{ id }}" class="answer"></p>
% if msg:
<span class="message" tabindex="-1">${HTML(msg)}</span>
% endif
{% if msg %}
<span class="message" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
</div>

View File

@@ -1,23 +1,23 @@
<section id="editageneinput_${id}" class="editageneinput">
<section id="editageneinput_{{ id }}" class="editageneinput">
<div class="script_placeholder" data-src="/static/js/capa/genex/genex.nocache.js?raw"/>
<div class="script_placeholder" data-src="${applet_loader}"/>
<div class="script_placeholder" data-src="{{ applet_loader }}"/>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<div class="${status.classname}">
% endif
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="{{ status.classname }}">
{% endif %}
<div id="genex_container"></div>
<input type="hidden" name="genex_dna_sequence" id="genex_dna_sequence" value ="${genex_dna_sequence}"></input>
<input type="hidden" name="genex_problem_number" id="genex_problem_number" value ="${genex_problem_number}"></input>
<input type="hidden" name="input_${id}" aria-describedby="answer_${id}" id="input_${id}" value="${value|h}"/>
<input type="hidden" name="genex_dna_sequence" id="genex_dna_sequence" value ="{{ genex_dna_sequence }}"></input>
<input type="hidden" name="genex_problem_number" id="genex_problem_number" value ="{{ genex_problem_number }}"></input>
<input type="hidden" name="input_{{ id }}" aria-describedby="answer_{{ id }}" id="input_{{ id }}" value="{{ value }}"/>
<p class="indicator-container" aria-describedby="input_${id}">
<%include file="status_span.html" args="status=status, status_id=id"/>
<p class="indicator-container" aria-describedby="input_{{ id }}">
{% include "status_span.html" with status=status status_id=id %}
</p>
<p id="answer_${id}" class="answer"></p>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<p id="answer_{{ id }}" class="answer"></p>
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
</section>

View File

@@ -1,28 +1,28 @@
<section id="editamoleculeinput_${id}" class="editamoleculeinput">
<div class="script_placeholder" data-src="${applet_loader}"/>
<section id="editamoleculeinput_{{ id }}" class="editamoleculeinput">
<div class="script_placeholder" data-src="{{ applet_loader }}"/>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<div class="${status.classname}">
% endif
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="{{ status.classname }}">
{% endif %}
<div id="applet_${id}" class="applet" data-molfile-src="${file}" style="display:block;width:500px;height:400px">
<div id="applet_{{ id }}" class="applet" data-molfile-src="{{ file }}" style="display:block;width:500px;height:400px">
</div>
<br/>
<input type="hidden" name="input_${id}" id="input_${id}" aria-describedby="answer_${id}" value="${value|h}"/>
<input type="hidden" name="input_{{ id }}" id="input_{{ id }}" aria-describedby="answer_{{ id }}" value="{{ value }}"/>
<button id="reset_${id}" class="reset">Reset</button>
<button id="reset_{{ id }}" class="reset">Reset</button>
<p id="answer_${id}" class="answer"></p>
<p id="answer_{{ id }}" class="answer"></p>
<p class="indicator-container" aria-describedby="input_${id}">
<%include file="status_span.html" args="status=status, status_id=id"/>
<p class="indicator-container" aria-describedby="input_{{ id }}">
{% include "status_span.html" with status=status status_id=id %}
</p>
<div class="error_message" style="padding: 5px 5px 5px 5px; background-color:#FA6666; height:60px;width:400px; display: none"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
</section>

View File

@@ -1,14 +1,13 @@
<%! from openedx.core.djangolib.markup import HTML %>
<section id="filesubmission_${id}" class="filesubmission">
<section id="filesubmission_{{ id }}" class="filesubmission">
<div class="grader-status file">
<span class="${status.classname}" id="status_${id}">${status.display_name}</span>
% if status == 'queued':
<span style="display:none;" class="xqueue" id="${id}">${queue_len}</span>
% endif
<p class="debug">${status}</p>
<span class="{{ status.classname }}" id="status_{{ id }}">{{ status.display_name }}</span>
{% if status == 'queued' %}
<span style="display:none;" class="xqueue" id="{{ id }}">{{ queue_len }}</span>
{% endif %}
<p class="debug">{{ status }}</p>
<input type="file" name="input_${id}" id="input_${id}" value="${value}" multiple="multiple" data-required_files="${required_files|h}" data-allowed_files="${allowed_files|h}" aria-label="${response_data['label']}"/>
<input type="file" name="input_{{ id }}" id="input_{{ id }}" value="{{ value }}" multiple="multiple" data-required_files="{{ required_files }}" data-allowed_files="{{ allowed_files }}" aria-label="{{ response_data.label }}"/>
</div>
<div class="message" tabindex="-1">${HTML(msg)}</div>
<div class="message" tabindex="-1">{{ msg|safe }}</div>
</section>

View File

@@ -1,36 +1,34 @@
<%page expression_filter="h"/>
<%! from openedx.core.djangolib.markup import HTML %>
<% doinline = 'style="display:inline-block;vertical-align:top"' if inline else "" %>
<div id="formulaequationinput_${id}" class="inputtype formulaequationinput" ${doinline | n, decode.utf8}>
<div class="${status.classname}">
% if response_data['label']:
<label class="problem-group-label" for="input_${id}" id="label_${id}">${response_data['label']}</label>
% endif
% for description_id, description_text in response_data['descriptions'].items():
<p class="question-description" id="${description_id}">${description_text}</p>
% endfor
<input type="text" name="input_${id}" id="input_${id}"
data-input-id="${id}" value="${value}"
${describedby_html}
% if size:
size="${size}"
% endif
{% load static %}
<div id="formulaequationinput_{{ id }}" class="inputtype formulaequationinput" {% if inline %}style="display:inline-block;vertical-align:top"{% endif %}>
<div class="{{ status.classname }}">
{% if response_data.label %}
<label class="problem-group-label" for="input_{{ id }}" id="label_{{ id }}">{{ response_data.label }}</label>
{% endif %}
{% for description_id, description_text in response_data.descriptions.items %}
<p class="question-description" id="{{ description_id }}">{{ description_text }}</p>
{% endfor %}
<input type="text" name="input_{{ id }}" id="input_{{ id }}"
data-input-id="{{ id }}" value="{{ value }}"
{{ describedby_html }}
{% if size %}
size="{{ size }}"
{% endif %}
/>
<span class="trailing_text" id="trailing_text_${id}">${trailing_text}</span>
<span class="trailing_text" id="trailing_text_{{ id }}">{{ trailing_text }}</span>
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
<p id="answer_${id}" class="answer"></p>
<p id="answer_{{ id }}" class="answer"></p>
<div id="input_${id}_preview" class="equation">
<div id="input_{{ id }}_preview" class="equation">
\(\)
<img src="${STATIC_URL}images/spinner.gif" class="loading" alt="Loading"/>
<img src="{% static 'images/spinner.gif' %}" class="loading" alt="Loading"/>
</div>
</div>
<div class="script_placeholder" data-src="${previewer}"/>
<div class="script_placeholder" data-src="{{ previewer }}"/>
% if msg:
<span class="message" aria-describedby="label_${id}" tabindex="-1">${HTML(msg)}</span>
% endif
{% if msg %}
<span class="message" aria-describedby="label_{{ id }}" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
</div>

View File

@@ -1,35 +1,35 @@
<%page expression_filter="h"/>
<div class="imageinput capa_inputtype" id="inputtype_${id}">
{% load static %}
<div class="imageinput capa_inputtype" id="inputtype_{{ id }}">
<input
type="hidden"
class="imageinput"
src="${src}"
name="input_${id}"
id="input_${id}"
value="${value}"
src="{{ src }}"
name="input_{{ id }}"
id="input_{{ id }}"
value="{{ value }}"
/>
<div style="position:relative;">
<div
id="imageinput_${id}"
id="imageinput_{{ id }}"
style="
background-image: url('${src}');
width: ${width}px;
height: ${height}px;
background-image: url('{{ src }}');
width: {{ width }}px;
height: {{ height }}px;
position: relative;
left: 0;
top: 0;"
>
<img
src="${STATIC_URL}images/green-pointer.png"
id="cross_${id}"
style="position: absolute; top: ${gy}px; left: ${gx}px;"
src="{% static 'images/green-pointer.png' %}"
id="cross_{{ id }}"
style="position: absolute; top: {{ gy }}px; left: {{ gx }}px;"
alt="Selection indicator"
/>
</div>
<div
data-width="${width}"
data-height="${height}"
id="answer_${id}"
data-width="{{ width }}"
data-height="{{ height }}"
id="answer_{{ id }}"
style="
position: absolute;
left: 0;
@@ -38,8 +38,8 @@
</div>
<script type="text/javascript" charset="utf-8">
(new ImageInput('${id | n, decode.utf8}'));
(new ImageInput('{{ id }}'));
</script>
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
</div>

View File

@@ -1,59 +1,57 @@
<%page expression_filter="h"/>
<%! from openedx.core.djangolib.markup import HTML %>
<div id="inputtype_${id}" class="jsinput"
data="${gradefn}"
% if saved_state:
data-stored="${saved_state}"
% endif
% if initial_state:
data-initial-state="${initial_state}"
% endif
% if get_statefn:
data-getstate="${get_statefn}"
% endif
% if set_statefn:
data-setstate="${set_statefn}"
% endif
% if sop:
data-sop="${sop}"
% endif
<div id="inputtype_{{ id }}" class="jsinput"
data="{{ gradefn }}"
{% if saved_state %}
data-stored="{{ saved_state }}"
{% endif %}
{% if initial_state %}
data-initial-state="{{ initial_state }}"
{% endif %}
{% if get_statefn %}
data-getstate="{{ get_statefn }}"
{% endif %}
{% if set_statefn %}
data-setstate="{{ set_statefn }}"
{% endif %}
{% if sop %}
data-sop="{{ sop }}"
{% endif %}
data-processed="false"
>
<div class="script_placeholder" data-src="${jschannel_loader}"/>
<div class="script_placeholder" data-src="${jsinput_loader}"/>
% if status in ['unsubmitted', 'submitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<div class="${status.classname}">
% endif
<div class="script_placeholder" data-src="{{ jschannel_loader }}"/>
<div class="script_placeholder" data-src="{{ jsinput_loader }}"/>
{% if status == 'unsubmitted' or status == 'submitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="{{ status.classname }}">
{% endif %}
<iframe name="iframe_${id}"
id="iframe_${id}"
<iframe name="iframe_{{ id }}"
id="iframe_{{ id }}"
sandbox="allow-scripts allow-popups allow-same-origin allow-forms allow-pointer-lock allow-downloads"
seamless="seamless"
frameborder="0"
src="${html_file}"
height="${height}"
width="${width}"
title="${title}"
src="{{ html_file }}"
height="{{ height }}"
width="{{ width }}"
title="{{ title }}"
/>
<input type="hidden" name="input_${id}" id="input_${id}"
<input type="hidden" name="input_{{ id }}" id="input_{{ id }}"
waitfor=""
value="${value}"/>
value="{{ value }}"/>
<br/>
<p id="answer_${id}" class="answer"></p>
<p id="answer_{{ id }}" class="answer"></p>
<div class="indicator-container">
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
</div>
<div class="error_message" style="padding: 5px 5px 5px 5px; background-color:#FA6666; height:60px;width:400px; display: none"></div>
% if status in ['unsubmitted', 'submitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
{% if status == 'unsubmitted' or status == 'submitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
% if msg:
<span class="message" tabindex="-1">${HTML(msg)}</span>
% endif
{% if msg %}
<span class="message" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
</div>

View File

@@ -1,8 +1,8 @@
<section class="math-string">
% if isinline:
<span>[mathjaxinline]${mathstr}[/mathjaxinline]</span>
% else:
<span>[mathjax]${mathstr}[/mathjax]</span>
% endif
<span>${tail}</span>
{% if isinline %}
<span>[mathjaxinline]{{ mathstr }}[/mathjaxinline]</span>
{% else %}
<span>[mathjax]{{ mathstr }}[/mathjax]</span>
{% endif %}
<span>{{ tail|safe }}</span>
</section>

View File

@@ -1,51 +1,50 @@
<%page expression_filter="h"/>
<section id="textbox_${id}" class="capa_inputtype cminput">
<div class="script_placeholder" data-src="${matlab_editor_js}"></div>
<section id="textbox_{{ id }}" class="capa_inputtype cminput">
<div class="script_placeholder" data-src="{{ matlab_editor_js }}"></div>
<textarea
rows="${rows}"
cols="${cols}"
name="input_${id}"
aria-describedby="answer_${id}"
id="input_${id}"
data-tabsize="${tabsize}"
rows="{{ rows }}"
cols="{{ cols }}"
name="input_{{ id }}"
aria-describedby="answer_{{ id }}"
id="input_{{ id }}"
data-tabsize="{{ tabsize }}"
data-mode="octave"
% if linenumbers:
{% if linenumbers %}
data-linenums="true"
% endif
% if hidden:
{% endif %}
{% if hidden %}
style="display:none;"
% endif
>${value}</textarea>
{% endif %}
>{{ value }}</textarea>
<div class="grader-status" tabindex="-1">
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
% if status == 'queued':
<span style="display:none;" class="xqueue" id="${id}">${queue_len}</span>
% endif
{% if status == 'queued' %}
<span style="display:none;" class="xqueue" id="{{ id }}">{{ queue_len }}</span>
{% endif %}
% if hidden:
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
{% if hidden %}
<div style="display:none;" name="{{ hidden }}" inputid="input_{{ id }}" />
{% endif %}
<p class="debug">${status.display_name}</p>
<p class="debug">{{ status.display_name }}</p>
</div>
<span id="answer_${id}"></span>
<span id="answer_{{ id }}"></span>
<div class="external-grader-message" aria-live="polite">
${msg|n, decode.utf8}
{{ msg|safe }}
</div>
<div class="ungraded-matlab-result" aria-live="polite">
${queue_msg|n, decode.utf8}
{{ queue_msg|safe }}
</div>
% if button_enabled:
{% if button_enabled %}
<div class="plot-button">
<input type="button" class="save" name="plot-button" id="plot_${id}" value="Run Code" />
<input type="button" class="save" name="plot-button" id="plot_{{ id }}" value="Run Code" />
</div>
%endif
{% endif %}
<script type="text/javascript">
$(function(){
@@ -67,7 +66,7 @@
var plot = function(event) {
var problem_elt = $(event.target).closest('.problems-wrapper');
url = $(event.target).closest('.problems-wrapper').data('url');
input_id = "${id|n, decode.utf8}";
input_id = "{{ id|safe }}";
// save the codemirror text to the textarea
// since there could be multiple codemirror instances on the page,
@@ -75,7 +74,7 @@
$('.CodeMirror').each(function(i, el){
el.CodeMirror.save();
});
var input = $("#input_${id|n, decode.utf8}");
var input = $("#input_{{ id|safe }}");
// pull out the coded text
submission = input.val();
@@ -134,7 +133,7 @@
// save the answer
$.postWithPrefix(url + '/problem_save', answer, save_callback);
};
$('#plot_${id|n, decode.utf8}').click(plot);
$('#plot_{{ id|safe }}').click(plot);
});
</script>

View File

@@ -1,32 +1,28 @@
<%page expression_filter="h"/>
<%! from openedx.core.djangolib.markup import HTML %>
<% doinline = "inline" if inline else "" %>
<div class="inputtype option-input {% if inline %}inline{% endif %}">
{% if response_data.label %}
<label class="problem-group-label" for="input_{{ id }}" id="label_{{ id }}">{{ response_data.label }}</label>
{% endif %}
<div class="inputtype option-input ${doinline}">
% if response_data['label']:
<label class="problem-group-label" for="input_${id}" id="label_${id}">${response_data['label']}</label>
% endif
{% for description_id, description_text in response_data.descriptions.items %}
<p class="question-description" id="{{ description_id }}">{{ description_text|safe }}</p>
{% endfor %}
% for description_id, description_text in response_data['descriptions'].items():
<p class="question-description" id="${description_id}">${description_text}</p>
% endfor
<select name="input_${id}" id="input_${id}" ${describedby_html}>
<option value="option_${id}_dummy_default">${default_option_text}</option>
% for option_id, option_description in options:
<option value="${option_id}"
% if (option_id == value or option_id == answervariable):
<select name="input_{{ id }}" id="input_{{ id }}" {{ describedby_html }}>
<option value="option_{{ id }}_dummy_default">{{ default_option_text }}</option>
{% for option_id, option_description in options %}
<option value="{{ option_id }}"
{% if option_id == value or option_id == answervariable %}
selected="true"
% endif
> ${option_description}</option>
% endfor
{% endif %}
> {{ option_description }}</option>
{% endfor %}
</select>
<div class="indicator-container">
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
</div>
<p class="answer" id="answer_${id}"></p>
% if msg:
<span class="message" aria-describedby="label_${id}" tabindex="-1">${HTML(msg)}</span>
% endif
<p class="answer" id="answer_{{ id }}"></p>
{% if msg %}
<span class="message" aria-describedby="label_{{ id }}" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
</div>

View File

@@ -0,0 +1,123 @@
{% load i18n %}
<h3 class="hd hd-3 problem-header" id="{{ short_id }}-problem-title" aria-describedby="{{ id }}-problem-progress" tabindex="-1">
{{ problem.name }}
</h3>
<div class="problem-progress" id="{{ id }}-problem-progress"></div>
<div class="problem">
{{ problem.html|safe }}
<div class="action">
<input type="hidden" name="problem_id" value="{{ problem.name }}" />
{% if demand_hint_possible %}
<div class="problem-hint">
{% include "problem_notifications.html" with notification_name='hint' notification_type='problem-hint' notification_icon='fa-question' notification_message='' %}
</div>
{% endif %}
<div class="problem-action-buttons-wrapper">
{% if demand_hint_possible %}
<span class="problem-action-button-wrapper">
<button type="button" class="hint-button problem-action-btn btn-link btn-small" data-value="{% trans 'Hint' as hint_val %}{{ hint_val|force_escape }}" {% if not should_enable_next_hint %}disabled{% endif %}>{% trans "Hint" as hint_text %}{{ hint_text|force_escape }}</button>
</span>
{% endif %}
{% if save_button %}
<span class="problem-action-button-wrapper">
<button type="button" class="save problem-action-btn btn-link btn-small" data-value="{% trans 'Save' as save_val %}{{ save_val|force_escape }}">
<span aria-hidden="true">{% trans "Save" as save_text %}{{ save_text|force_escape }}</span>
<span class="sr">{% trans "Save your answer" as save_sr %}{{ save_sr|force_escape }}</span>
</button>
</span>
{% endif %}
{% if attempts_used and reset_button %}
<span class="problem-action-button-wrapper">
<button type="button" class="reset problem-action-btn btn-link btn-small" data-value="{% trans 'Reset' as reset_val %}{{ reset_val|force_escape }}"><span aria-hidden="true">{% trans "Reset" as reset_text %}{{ reset_text|force_escape }}</span><span class="sr">{% trans "Reset your answer" as reset_sr %}{{ reset_sr|force_escape }}</span></button>
</span>
{% endif %}
{% if answer_available %}
<span class="problem-action-button-wrapper">
<button type="button" class="show problem-action-btn btn-link btn-small" aria-describedby="{{ short_id }}-problem-title"><span class="show-label">{% trans "Show answer" as show_ans %}{{ show_ans|force_escape }}</span></button>
</span>
{% endif %}
</div>
<div class="submit-attempt-container">
<button type="button" class="submit btn-brand" data-submitting="{{ submit_button_submitting }}" data-value="{{ submit_button }}" data-should-enable-submit-button="{{ should_enable_submit_button }}" aria-describedby="submission_feedback_{{ short_id }}"{% if not should_enable_submit_button %}disabled{% endif %}>
<span class="submit-label">{{ submit_button }}</span>
</button>
{% if submit_disabled_cta %}
{% if submit_disabled_cta.event_data %}
<button class="submit-cta-link-button btn-link btn-small" onclick="emit_event('{{ submit_disabled_cta.event_data }}')">
{{ submit_disabled_cta.link_name }}
</button>
<span class="submit-cta-description" tabindex="0" role="note" aria-label="description">
<span data-tooltip="{{ submit_disabled_cta.description }}" data-tooltip-show-on-click="true"
class="fa fa-info-circle fa-lg" aria-hidden="true">
</span>
</span>
<span class="sr">({{ submit_disabled_cta.description }})</span>
{% else %}
<form class="submit-cta" method="post" action="{{ submit_disabled_cta.link }}">
{% if submit_disabled_cta.link %}
<input type="hidden" id="csrf_token" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
{% for form_name, form_value in submit_disabled_cta.form_values.items %}
<input type="hidden" name="{{ form_name }}" value="{{ form_value }}">
{% endfor %}
<button class="submit-cta-link-button btn-link btn-small">
{{ submit_disabled_cta.link_name }}
</button>
{% endif %}
<span class="submit-cta-description" tabindex="0" role="note" aria-label="description">
<span data-tooltip="{{ submit_disabled_cta.description }}" data-tooltip-show-on-click="true"
class="fa fa-info-circle fa-lg" aria-hidden="true">
</span>
</span>
<span class="sr">({{ submit_disabled_cta.description }})</span>
</form>
{% endif %}
{% endif %}
<div class="submission-feedback {% if submit_disabled_cta %}cta-enabled{% endif %}" id="submission_feedback_{{ short_id }}">
{% comment %} When attempts are not 0, the CTA above will contain a message about the number of used attempts {% endcomment %}
{% if attempts_allowed and not submit_disabled_cta or attempts_allowed and attempts_used == 0 %}
{% filter force_escape %}{% blocktrans count num_total=attempts_allowed %}You have used {{ attempts_used }} of {{ num_total }} attempt.{% plural %}You have used {{ attempts_used }} of {{ num_total }} attempts{% endblocktrans %}{% endfilter %}
{% endif %}
{% if grading_method %}
<div>{% trans "Grading method:" as grading_text %}{{ grading_text|force_escape }} {{ grading_method }}</div>
{% endif %}
<span class="sr">{% trans "Some problems have options such as save, reset, hints, or show answer. These options follow the Submit button." as options_sr %}{{ options_sr|force_escape }}</span>
</div>
</div>
</div>
{% include "problem_notifications.html" with notification_type='warning' notification_icon='fa-exclamation-circle' notification_name='gentle-alert' notification_message='' %}
{% if answer_notification_type %}
{% if answer_notification_type == 'correct' %}
{% include "problem_notifications.html" with notification_type='success' notification_icon='fa-check' notification_name='submit' is_hidden=False notification_message=answer_notification_message %}
{% endif %}
{% if answer_notification_type == 'incorrect' %}
{% include "problem_notifications.html" with notification_type='error' notification_icon='fa-close' notification_name='submit' is_hidden=False notification_message=answer_notification_message %}
{% endif %}
{% if answer_notification_type == 'partially-correct' %}
{% include "problem_notifications.html" with notification_type='success' notification_icon='fa-asterisk' notification_name='submit' is_hidden=False notification_message=answer_notification_message %}
{% endif %}
{% if answer_notification_type == 'submitted' %}
{% include "problem_notifications.html" with notification_type='general' notification_icon='fa-info-circle' notification_name='submit' is_hidden=False notification_message=answer_notification_message %}
{% endif %}
{% endif %}
{% if has_saved_answers %}
{% include "problem_notifications.html" with notification_type='warning' notification_icon='fa-save' notification_name='save' notification_message=save_message is_hidden=False %}
{% else %}
{% include "problem_notifications.html" with notification_type='warning' notification_icon='fa-save' notification_name='save' notification_message=save_message is_hidden=True %}
{% endif %}
{# xss-lint: disable=django-trans-missing-escape #}
{% trans "Answers are displayed within the problem" as notification_message %}
{% with notification_message=notification_message|force_escape %}
{% include "problem_notifications.html" with notification_type='general' notification_icon='fa-info-circle' notification_name='show-answer' notification_message=notification_message is_hidden=True %}
{% endwith %}
</div>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>

View File

@@ -0,0 +1,13 @@
<div id="problem_{{ element_id }}" class="problems-wrapper" role="group"
aria-labelledby="{{ element_id }}-problem-title"
data-problem-id="{{ id }}" data-url="{{ ajax_url }}"
data-problem-score="{{ current_score }}"
data-problem-total-possible="{{ total_possible }}"
data-attempts-used="{{ attempts_used }}"
data-content="{{ content }}"
data-graded="{{ graded }}">
<p class="loading-spinner">
<i class="fa fa-spinner fa-pulse fa-2x fa-fw"></i>
<span class="sr">Loading&hellip;</span>
</p>
</div>

View File

@@ -0,0 +1,17 @@
{% load i18n %}
<div class="notification {{ notification_type }} notification-{{ notification_name }}
{% if is_hidden != False %}is-hidden{% endif %}"
tabindex="-1">
<span class="icon fa {{ notification_icon }}" aria-hidden="true"></span>
<span class="notification-message" aria-describedby="{{ short_id }}-problem-title">{{ notification_message }}
</span>
<div class="notification-btn-wrapper">
{% if notification_name == 'hint' %}
<button type="button" class="btn btn-default btn-small notification-btn hint-button">
{% trans "Next Hint" as next_hint_text %}{{ next_hint_text|force_escape }}
</button>
{% endif %}
<button type="button" class="btn btn-default btn-small notification-btn review-btn sr">{% trans "Review" as review_text %}{{ review_text|force_escape }}</button>
</div>
</div>

View File

@@ -1,24 +1,23 @@
<%! from xmodule.capa.util import remove_markup %>
<div>
<div class="script_placeholder" data-src="${setup_script}"/>
<div class="script_placeholder" data-src="{{ setup_script }}"/>
<input type="hidden"
class="schematic"
height="${height}"
width="${width}"
parts="${parts}"
analyses="${analyses}"
name="input_${id}"
id="input_${id}"
aria-label="${remove_markup(response_data['label'])}"
aria-describedby="answer_${id}"
value="${value|h}"
initial_value="${initial_value|h}"
submit_analyses="${submit_analyses|h}"
height="{{ height }}"
width="{{ width }}"
parts="{{ parts }}"
analyses="{{ analyses }}"
name="input_{{ id }}"
id="input_{{ id }}"
aria-label="{{ response_data.label|striptags }}"
aria-describedby="answer_{{ id }}"
value="{{ value }}"
initial_value="{{ initial_value }}"
submit_analyses="{{ submit_analyses }}"
/>
<span id="answer_${id}"></span>
<span id="answer_{{ id }}"></span>
<div class="indicator-container">
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
</div>
</div>

View File

@@ -1,4 +1,3 @@
<%page expression_filter="h"/>
<div class="solution-span">
<span id="solution_${id}"></span>
<span id="solution_{{ id }}"></span>
</div>

View File

@@ -1,13 +1,11 @@
<%page expression_filter="h" args="status, status_id='', hide_correctness=False"/>
% if status_id == '':
<span class="status ${'' if hide_correctness == True else status.classname}"
data-tooltip="${'' if hide_correctness == True else status.display_tooltip}">
% else:
<span class="status ${'' if hide_correctness == True else status.classname}" id="status_${status_id}"
data-tooltip="${'' if hide_correctness == True else status.display_tooltip}">
% endif
% if hide_correctness == False:
<span class="sr">${status.display_name}</span><span class="status-icon" aria-hidden="true"></span>
% endif
{% if status_id == '' %}
<span class="status {% if hide_correctness == True %}{% else %}{{ status.classname }}{% endif %}"
data-tooltip="{% if hide_correctness == True %}{% else %}{{ status.display_tooltip }}{% endif %}">
{% else %}
<span class="status {% if hide_correctness == True %}{% else %}{{ status.classname }}{% endif %}" id="status_{{ status_id }}"
data-tooltip="{% if hide_correctness == True %}{% else %}{{ status.display_tooltip }}{% endif %}">
{% endif %}
{% if not hide_correctness %}
<span class="sr">{{ status.display_name }}</span><span class="status-icon" aria-hidden="true"></span>
{% endif %}
</span>

View File

@@ -1,53 +1,49 @@
<%page expression_filter="h"/>
<%! from openedx.core.djangolib.markup import HTML %>
<% doinline = "inline" if inline else "" %>
<div id="inputtype_{{ id }}" {% if do_math and inline %} class="text-input-dynamath capa_inputtype inline textline" {% elif do_math %} class="text-input-dynamath capa_inputtype textline" {% elif inline %} class=" capa_inputtype inline textline" {% else %} class=" capa_inputtype textline" {% endif %}>
{% if preprocessor is not None %}
<div class="text-input-dynamath_data {% if inline %}inline{% endif %}" data-preprocessor="{{ preprocessor.class_name }}"/>
<div class="script_placeholder" data-src="{{ preprocessor.script_src }}"/>
{% endif %}
<div id="inputtype_${id}" class="${'text-input-dynamath' if do_math else ''} capa_inputtype ${doinline} textline">
% if preprocessor is not None:
<div class="text-input-dynamath_data ${doinline}" data-preprocessor="${preprocessor['class_name']}"/>
<div class="script_placeholder" data-src="${preprocessor['script_src']}"/>
% endif
{% if status == 'unsubmitted' or status == 'submitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="{{ status.classname }} {% if inline %}inline{% endif %}">
{% endif %}
% if status in ('unsubmitted', 'submitted', 'correct', 'incorrect', 'partially-correct', 'incomplete'):
<div class="${status.classname} ${doinline}">
% endif
{% if hidden %}
<div style="display:none;" name="{{ hidden }}" inputid="input_{{ id }}" />
{% endif %}
% if hidden:
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
{% if response_data.label %}
<label class="problem-group-label" for="input_{{ id }}" id="label_{{ id }}">{{ response_data.label }}</label>
{% endif %}
% if response_data['label']:
<label class="problem-group-label" for="input_${id}" id="label_${id}">${response_data['label']}</label>
% endif
% for description_id, description_text in response_data['descriptions'].items():
<p class="question-description" id="${description_id}">${description_text}</p>
% endfor
<input type="text" class="mw-100 ${'math' if do_math else ''}" name="input_${id}" id="input_${id}" ${describedby_html} value="${value}"
% if size:
size="${size}"
% endif
% if hidden:
{% for description_id, description_text in response_data.descriptions.items %}
<p class="question-description" id="{{ description_id }}">{{ description_text|safe }}</p>
{% endfor %}
<input type="text" class="mw-100 {% if do_math %}math{% endif %}" name="input_{{ id }}" id="input_{{ id }}" {{ describedby_html }} value="{{ value }}"
{% if size %}
size="{{ size }}"
{% endif %}
{% if hidden %}
style="display:none;"
% endif
{% endif %}
/>
<span class="trailing_text" id="trailing_text_${id}">${trailing_text}</span>
<span class="trailing_text" id="trailing_text_{{ id }}">{{ trailing_text }}</span>
<%include file="status_span.html" args="status=status, status_id=id"/>
{% include "status_span.html" with status=status status_id=id %}
<p id="answer_${id}" class="answer"></p>
<p id="answer_{{ id }}" class="answer"></p>
% if do_math:
<div id="display_${id}" class="equation">`{::}`</div>
<textarea style="display:none" id="input_${id}_dynamath" name="input_${id}_dynamath"></textarea>
% endif
{% if do_math %}
<div id="display_{{ id }}" class="equation">`{::}`</div>
<textarea style="display:none" id="input_{{ id }}_dynamath" name="input_{{ id }}_dynamath"></textarea>
{% endif %}
% if status in ('unsubmitted', 'submitted', 'correct', 'incorrect', 'partially-correct', 'incomplete'):
{% if status == 'unsubmitted' or status == 'submitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
% if msg:
<span class="message" aria-describedby="label_${id}" tabindex="-1">${HTML(msg)}</span>
% endif
{% if msg %}
<span class="message" aria-describedby="label_{{ id }}" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
</div>

View File

@@ -1,35 +1,34 @@
<%! from openedx.core.djangolib.markup import HTML %>
<section id="inputtype_${id}" class="capa_inputtype" >
<section id="inputtype_{{ id }}" class="capa_inputtype" >
<table><tr><td height='600'>
<div id="vsepr_div_${id}" style="position:relative;" data-molecules="${molecules}" data-geometries="${geometries}">
<canvas id="vsepr_canvas_${id}" width="${width}" height="${height}">
<div id="vsepr_div_{{ id }}" style="position:relative;" data-molecules="{{ molecules }}" data-geometries="{{ geometries }}">
<canvas id="vsepr_canvas_{{ id }}" width="{{ width }}" height="{{ height }}">
</canvas>
</div>
</td><td valign ='top'>
<select class="molecule_select" id="molecule_select_${id}" size="18">
<select class="molecule_select" id="molecule_select_{{ id }}" size="18">
</select>
</td></tr></table>
<div class="script_placeholder" data-src="/static/js/vsepr/vsepr.js"></div>
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
<div class="{{ status.classname }}" id="status_{{ id }}">
{% endif %}
<input type="text" name="input_${id}" id="input_${id}" aria-describedby="answer_${id}" value="${value|h}"
<input type="text" name="input_{{ id }}" id="input_{{ id }}" aria-describedby="answer_{{ id }}" value="{{ value }}"
style="display:none;"
/>
<p class="status">
<span class="sr">${status.display_name}</span>
<span class="sr">{{ status.display_name }}</span>
</p>
<p id="answer_${id}" class="answer"></p>
<p id="answer_{{ id }}" class="answer"></p>
% if msg:
<span class="message" tabindex="-1">${HTML(msg)}</span>
% endif
% if status in ['unsubmitted', 'correct', 'incorrect', 'partially-correct', 'incomplete']:
{% if msg %}
<span class="message" tabindex="-1">{{ msg|safe }}</span>
{% endif %}
{% if status == 'unsubmitted' or status == 'correct' or status == 'incorrect' or status == 'partially-correct' or status == 'incomplete' %}
</div>
% endif
{% endif %}
</section>

View File

@@ -8,8 +8,7 @@ import xml.sax.saxutils as saxutils
from unittest.mock import MagicMock, Mock
import fs.osfs
from mako.lookup import TemplateLookup
from path import Path
from django.template.loader import get_template as django_get_template
from xmodule.capa.capa_problem import LoncapaProblem, LoncapaSystem
from xmodule.capa.inputtypes import Status
@@ -21,16 +20,14 @@ def get_template(template_name):
"""
Return template for a capa inputtype.
"""
return TemplateLookup(
directories=[Path(__file__).dirname().dirname() / "templates"], default_filters=["decode.utf8"]
).get_template(template_name)
return django_get_template(template_name)
def capa_render_template(template, context):
"""
Render template for a capa inputtype.
"""
return get_template(template).render_unicode(**context)
return get_template(template).render(context)
def tst_render_template(template, context): # pylint: disable=unused-argument

View File

@@ -1,13 +1,13 @@
"""
Tests for the logic in input type mako templates.
~Tests for the logic in input type Django templates.
"""
import json
import traceback
import unittest
from collections import OrderedDict
from lxml import etree
from mako import exceptions
from six.moves import range
from openedx.core.djangolib.markup import HTML
@@ -18,7 +18,7 @@ from xmodule.stringify import stringify_children
class TemplateError(Exception):
"""
Error occurred while rendering a Mako template.
Error occurred while rendering a Django template.
"""
pass # lint-amnesty, pylint: disable=unnecessary-pass
@@ -57,10 +57,8 @@ class TemplateTestCase(unittest.TestCase):
context_dict.setdefault("STATIC_URL", "/dummy-static/")
try:
xml_str = capa_render_template(self.TEMPLATE_NAME, context_dict)
except:
raise TemplateError( # lint-amnesty, pylint: disable=raise-missing-from
exceptions.text_error_template().render()
)
except Exception as exc:
raise TemplateError(f"<pre>{traceback.format_exc()}</pre>") from exc
# Attempt to construct an XML tree from the template
# This makes it easy to use XPath to make assertions, rather
@@ -232,7 +230,7 @@ class TemplateTestCase(unittest.TestCase):
class ChoiceGroupTemplateTest(TemplateTestCase):
"""
Test mako template for `<choicegroup>` input.
Test django template for `<choicegroup>` input.
"""
TEMPLATE_NAME = "choicegroup.html"
@@ -462,7 +460,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
class TextlineTemplateTest(TemplateTestCase):
"""
Test mako template for `<textline>` input.
Test django template for `<textline>` input.
"""
TEMPLATE_NAME = "textline.html"
@@ -641,7 +639,7 @@ class FormulaEquationInputTemplateTest(TemplateTestCase):
class AnnotationInputTemplateTest(TemplateTestCase):
"""
Test mako template for `<annotationinput>` input.
Test django template for `<annotationinput>` input.
"""
TEMPLATE_NAME = "annotationinput.html"
@@ -766,7 +764,7 @@ class AnnotationInputTemplateTest(TemplateTestCase):
class MathStringTemplateTest(TemplateTestCase):
"""
Test mako template for `<mathstring>` input.
Test django template for `<mathstring>` input.
"""
TEMPLATE_NAME = "mathstring.html"
@@ -806,7 +804,7 @@ class MathStringTemplateTest(TemplateTestCase):
class OptionInputTemplateTest(TemplateTestCase):
"""
Test mako template for `<optioninput>` input.
Test django template for `<optioninput>` input.
"""
TEMPLATE_NAME = "optioninput.html"
@@ -866,7 +864,7 @@ class OptionInputTemplateTest(TemplateTestCase):
class DragAndDropTemplateTest(TemplateTestCase):
"""
Test mako template for `<draganddropinput>` input.
Test django template for `<draganddropinput>` input.
"""
TEMPLATE_NAME = "drag_and_drop_input.html"
@@ -911,7 +909,7 @@ class DragAndDropTemplateTest(TemplateTestCase):
class ChoiceTextGroupTemplateTest(TemplateTestCase):
"""Test mako template for `<choicetextgroup>` input"""
"""Test django template for `<choicetextgroup>` input"""
TEMPLATE_NAME = "choicetext.html"
VALUE_DICT = {
@@ -1093,7 +1091,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
class ChemicalEquationTemplateTest(TemplateTestCase):
"""Test mako template for `<chemicalequationinput>` input"""
"""Test django template for `<chemicalequationinput>` input"""
TEMPLATE_NAME = "chemicalequationinput.html"
@@ -1114,7 +1112,7 @@ class ChemicalEquationTemplateTest(TemplateTestCase):
class SchematicInputTemplateTest(TemplateTestCase):
"""Test mako template for `<schematic>` input"""
"""Test django template for `<schematic>` input"""
TEMPLATE_NAME = "schematicinput.html"
@@ -1145,7 +1143,7 @@ class SchematicInputTemplateTest(TemplateTestCase):
class CodeinputTemplateTest(TemplateTestCase):
"""
Test mako template for `<textbox>` input
Test django template for `<textbox>` input
"""
TEMPLATE_NAME = "codeinput.html"

View File

@@ -18,6 +18,7 @@ import traceback
import nh3
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.template.loader import render_to_string
from django.utils.encoding import smart_str
from django.utils.functional import cached_property
from lxml import etree
@@ -399,6 +400,7 @@ class _BuiltInProblemBlock(
"""
Return the studio view.
"""
# Not converting this to django template since this method is deprecated.
fragment = Fragment(
self.runtime.service(self, "mako").render_cms_template(self.mako_template, self.get_context())
)
@@ -896,7 +898,7 @@ class _BuiltInProblemBlock(
get_python_lib_zip=sandbox_service.get_python_lib_zip,
DEBUG=self.debug,
i18n=self.runtime.service(self, "i18n"),
render_template=self.runtime.service(self, "mako").render_template,
render_template=render_to_string,
resources_fs=self.runtime.resources_fs,
seed=seed, # Why do we do this if we have self.seed?
xqueue=None if is_studio else XQueueService(self),
@@ -992,7 +994,7 @@ class _BuiltInProblemBlock(
"""
curr_score, total_possible = self.get_display_progress()
return self.runtime.service(self, "mako").render_lms_template(
return render_to_string(
"problem_ajax.html",
{
"element_id": self.location.html_id(),
@@ -1339,7 +1341,7 @@ class _BuiltInProblemBlock(
"submit_disabled_cta": submit_disabled_ctas[0] if submit_disabled_ctas else None,
}
html = self.runtime.service(self, "mako").render_lms_template("problem.html", context)
html = render_to_string("problem.html", context)
if encapsulate:
html = HTML('<div id="problem_{id}" class="problem" data-url="{ajax_url}">{html}</div>').format(
@@ -1647,7 +1649,7 @@ class _BuiltInProblemBlock(
return {
"answers": new_answers,
"correct_status_html": self.runtime.service(self, "mako").render_lms_template(
"correct_status_html": render_to_string(
"status_span.html", {"status": Status("correct", self.runtime.service(self, "i18n").gettext)}
),
}

View File

@@ -2277,9 +2277,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
assert html is not None
# assert that we got here without exploding
def test_get_problem_html(self):
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(render_template=render_template)
@patch("xmodule.capa_block.render_to_string")
def test_get_problem_html(self, render_template):
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create()
# We've tested the show/hide button logic in other tests,
# so here we hard-wire the values
@@ -2337,11 +2338,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
</demandhint>
</problem>"""
def test_demand_hint(self):
@patch("xmodule.capa_block.render_to_string")
def test_demand_hint(self, render_template):
# HTML generation is mocked out to be meaningless here, so instead we check
# the context dict passed into HTML generation.
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(xml=self.demand_xml, render_template=render_template)
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create(xml=self.demand_xml)
block.get_problem_html() # ignoring html result
context = render_template.call_args[0][1]
assert context["demand_hint_possible"]
@@ -2360,7 +2362,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
assert result["hint_index"] == 0
assert result["should_enable_next_hint"]
def test_single_demand_hint(self):
@patch("xmodule.capa_block.render_to_string")
def test_single_demand_hint(self, render_template):
"""
Test the hint button enabled state when there is just a single hint.
"""
@@ -2378,8 +2381,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
<hint>Only demand hint</hint>
</demandhint>
</problem>"""
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(xml=test_xml, render_template=render_template)
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create(xml=test_xml)
block.get_problem_html() # ignoring html result
context = render_template.call_args[0][1]
assert context["demand_hint_possible"]
@@ -2390,7 +2393,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
assert result["hint_index"] == 0
assert not result["should_enable_next_hint"]
def test_image_hint(self):
@patch("xmodule.capa_block.render_to_string")
def test_image_hint(self, render_template):
"""
Test the hint button shows an image without the static url.
"""
@@ -2410,8 +2414,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.</hint>
</demandhint>
</problem>"""
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(xml=test_xml, render_template=render_template)
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create(xml=test_xml)
block.get_problem_html() # ignoring html result
context = render_template.call_args[0][1]
assert context["demand_hint_possible"]
@@ -2449,14 +2453,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
intersection = set(block2.input_state.keys()).intersection(set(block1.input_state.keys()))
assert len(intersection) == 0
def test_get_problem_html_error(self):
@patch("xmodule.capa_block.render_to_string")
def test_get_problem_html_error(self, render_template):
"""
In production, when an error occurs with the problem HTML
rendering, a "dummy" problem is created with an error
message to display to the user.
"""
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(render_template=render_template)
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create()
# Save the original problem so we can compare it later
original_problem = block.lcp
@@ -2478,12 +2483,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
# Expect that the block has created a new dummy problem with the error
assert original_problem != block.lcp
def test_get_problem_html_error_preview(self):
@patch("xmodule.capa_block.render_to_string")
def test_get_problem_html_error_preview(self, render_template):
"""
Test the html response when an error occurs with DEBUG off in Studio.
"""
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(render_template=render_template)
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create()
# Simulate throwing an exception when the capa problem
# is asked to render itself as HTML
@@ -2503,12 +2509,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
assert error_msg in context["problem"]["html"]
@override_settings(DEBUG=True)
def test_get_problem_html_error_w_debug(self):
@patch("xmodule.capa_block.render_to_string")
def test_get_problem_html_error_w_debug(self, render_template):
"""
Test the html response when an error occurs with DEBUG on
"""
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(render_template=render_template)
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create()
# Simulate throwing an exception when the capa problem
# is asked to render itself as HTML
@@ -2823,12 +2830,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
"",
" ",
)
def test_problem_no_display_name(self, display_name):
@patch("xmodule.capa_block.render_to_string")
def test_problem_no_display_name(self, display_name, render_template):
"""
Verify that if problem display name is not provided then a default name is used.
"""
render_template = Mock(return_value="<div>Test Template HTML</div>")
block = CapaFactory.create(display_name=display_name, render_template=render_template)
render_template.return_value = "<div>Test Template HTML</div>"
block = CapaFactory.create(display_name=display_name)
block.get_problem_html()
render_args, _ = render_template.call_args
context = render_args[1]