Merge pull request #1514 from edx/alex/add_latex_compiler_key
Alex/add latex compiler key
This commit is contained in:
@@ -16,6 +16,9 @@ Blades: Disallow users to enter video url's in http.
|
||||
|
||||
LMS: Improve the acessibility of the forum follow post buttons.
|
||||
|
||||
Blades: Latex problems are now enabled via use_latex_compiler
|
||||
key in course settings. (BLD-426)
|
||||
|
||||
Blades: Fix bug when the speed can only be changed when the video is playing.
|
||||
|
||||
LMS: Change bulk email implementation to use less memory, and to better handle
|
||||
|
||||
@@ -19,11 +19,19 @@ Feature: CMS.Component Adding
|
||||
| Component |
|
||||
| Text |
|
||||
| Announcement |
|
||||
| E-text Written in LaTeX |
|
||||
Then I see HTML components in this order:
|
||||
| Component |
|
||||
| Text |
|
||||
| Announcement |
|
||||
|
||||
Scenario: I can add Latex HTML components
|
||||
Given I am in Studio editing a new unit
|
||||
Given I have enabled latex compiler
|
||||
When I add this type of HTML component:
|
||||
| Component |
|
||||
| E-text Written in LaTeX |
|
||||
Then I see HTML components in this order:
|
||||
| Component |
|
||||
| E-text Written in LaTeX |
|
||||
|
||||
Scenario: I can add Common Problem components
|
||||
@@ -58,9 +66,22 @@ Feature: CMS.Component Adding
|
||||
| Drag and Drop |
|
||||
| Image Mapped Input |
|
||||
| Math Expression Input |
|
||||
| Problem Written in LaTeX |
|
||||
| Problem with Adaptive Hint |
|
||||
|
||||
|
||||
Scenario: I can add Advanced Latex Problem components
|
||||
Given I am in Studio editing a new unit
|
||||
Given I have enabled latex compiler
|
||||
When I add a "<Component>" "Advanced Problem" component
|
||||
Then I see a "<Component>" Problem component
|
||||
# Flush out the database before the next example executes
|
||||
And I reset the database
|
||||
|
||||
Examples:
|
||||
| Component |
|
||||
| Problem Written in LaTeX |
|
||||
| Problem with Adaptive Hint in Latex |
|
||||
|
||||
Scenario: I see a prompt on delete
|
||||
Given I am in Studio editing a new unit
|
||||
And I add a "Discussion" "single step" component
|
||||
|
||||
@@ -22,6 +22,7 @@ def i_see_only_the_html_display_name(step):
|
||||
@step('I have created an E-text Written in LaTeX$')
|
||||
def i_created_etext_in_latex(step):
|
||||
world.create_course_with_unit()
|
||||
step.given('I have enabled latex compiler')
|
||||
world.create_component_instance(
|
||||
step=step,
|
||||
category='html',
|
||||
|
||||
@@ -5,6 +5,7 @@ import json
|
||||
from lettuce import world, step
|
||||
from nose.tools import assert_equal, assert_true # pylint: disable=E0611
|
||||
from common import type_in_codemirror, open_new_course
|
||||
from advanced_settings import change_value
|
||||
from course_import import import_file, go_to_import
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
||||
@@ -159,9 +160,19 @@ def cancel_does_not_save_changes(step):
|
||||
step.given("I see the advanced settings and their expected values")
|
||||
|
||||
|
||||
@step('I have enabled latex compiler')
|
||||
def enable_latex_compiler(step):
|
||||
url = world.browser.url
|
||||
step.given("I select the Advanced Settings")
|
||||
change_value(step, 'use_latex_compiler', True)
|
||||
world.visit(url)
|
||||
world.wait_for_xmodule()
|
||||
|
||||
|
||||
@step('I have created a LaTeX Problem')
|
||||
def create_latex_problem(step):
|
||||
world.create_course_with_unit()
|
||||
step.given('I have enabled latex compiler')
|
||||
world.create_component_instance(
|
||||
step=step,
|
||||
category='problem',
|
||||
|
||||
@@ -193,12 +193,14 @@ def edit_unit(request, location):
|
||||
# add boilerplates
|
||||
if hasattr(component_class, 'templates'):
|
||||
for template in component_class.templates():
|
||||
component_templates[category].append((
|
||||
template['metadata'].get('display_name'),
|
||||
category,
|
||||
template['metadata'].get('markdown') is not None,
|
||||
template.get('template_id')
|
||||
))
|
||||
filter_templates = getattr(component_class, 'filter_templates', None)
|
||||
if not filter_templates or filter_templates(template, course):
|
||||
component_templates[category].append((
|
||||
template['metadata'].get('display_name'),
|
||||
category,
|
||||
template['metadata'].get('markdown') is not None,
|
||||
template.get('template_id')
|
||||
))
|
||||
|
||||
# Check if there are any advanced modules specified in the course policy.
|
||||
# These modules should be specified as a list of strings, where the strings
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<%static:include path="js/metadata-list-entry.underscore" />
|
||||
</script>
|
||||
|
||||
<% showHighLevelSource='source_code' in editable_metadata_fields and editable_metadata_fields['source_code']['explicitly_set'] %>
|
||||
<% showHighLevelSource='source_code' in editable_metadata_fields and editable_metadata_fields['source_code']['explicitly_set'] and enable_latex_compiler %>
|
||||
<% metadata_field_copy = copy.copy(editable_metadata_fields) %>
|
||||
## Delete 'source_code' field (if it exists) so metadata editor view does not attempt to render it.
|
||||
% if 'source_code' in editable_metadata_fields:
|
||||
|
||||
@@ -158,6 +158,11 @@ class CapaFields(object):
|
||||
# TODO: someday it should be possible to not duplicate this definition here
|
||||
# and in inheritance.py
|
||||
)
|
||||
use_latex_compiler = Boolean(
|
||||
help="Enable LaTeX templates?",
|
||||
default=False,
|
||||
scope=Scope.settings
|
||||
)
|
||||
|
||||
|
||||
class CapaModule(CapaFields, XModule):
|
||||
@@ -1174,10 +1179,23 @@ class CapaDescriptor(CapaFields, RawDescriptor):
|
||||
metadata_translations = dict(RawDescriptor.metadata_translations)
|
||||
metadata_translations['attempts'] = 'max_attempts'
|
||||
|
||||
@classmethod
|
||||
def filter_templates(cls, template, course):
|
||||
"""
|
||||
Filter template that contains 'latex' from templates.
|
||||
|
||||
Show them only if use_latex_compiler is set to True in
|
||||
course settings.
|
||||
"""
|
||||
return (not 'latex' in template['template_id'] or course.use_latex_compiler)
|
||||
|
||||
def get_context(self):
|
||||
_context = RawDescriptor.get_context(self)
|
||||
_context.update({'markdown': self.markdown,
|
||||
'enable_markdown': self.markdown is not None})
|
||||
_context.update({
|
||||
'markdown': self.markdown,
|
||||
'enable_markdown': self.markdown is not None,
|
||||
'enable_latex_compiler': self.use_latex_compiler,
|
||||
})
|
||||
return _context
|
||||
|
||||
# VS[compat]
|
||||
@@ -1193,9 +1211,14 @@ class CapaDescriptor(CapaFields, RawDescriptor):
|
||||
@property
|
||||
def non_editable_metadata_fields(self):
|
||||
non_editable_fields = super(CapaDescriptor, self).non_editable_metadata_fields
|
||||
non_editable_fields.extend([CapaDescriptor.due, CapaDescriptor.graceperiod,
|
||||
CapaDescriptor.force_save_button, CapaDescriptor.markdown,
|
||||
CapaDescriptor.text_customization])
|
||||
non_editable_fields.extend([
|
||||
CapaDescriptor.due,
|
||||
CapaDescriptor.graceperiod,
|
||||
CapaDescriptor.force_save_button,
|
||||
CapaDescriptor.markdown,
|
||||
CapaDescriptor.text_customization,
|
||||
CapaDescriptor.use_latex_compiler,
|
||||
])
|
||||
return non_editable_fields
|
||||
|
||||
# Proxy to CapaModule for access to any of its attributes
|
||||
|
||||
@@ -7,7 +7,7 @@ from lxml import etree
|
||||
from path import path
|
||||
|
||||
from pkg_resources import resource_string
|
||||
from xblock.fields import Scope, String
|
||||
from xblock.fields import Scope, String, Boolean
|
||||
from xmodule.editing_module import EditingDescriptor
|
||||
from xmodule.html_checker import check_html
|
||||
from xmodule.stringify import stringify_children
|
||||
@@ -30,6 +30,11 @@ class HtmlFields(object):
|
||||
)
|
||||
data = String(help="Html contents to display for this module", default=u"", scope=Scope.content)
|
||||
source_code = String(help="Source code for LaTeX documents. This feature is not well-supported.", scope=Scope.settings)
|
||||
use_latex_compiler = Boolean(
|
||||
help="Enable LaTeX templates?",
|
||||
default=False,
|
||||
scope=Scope.settings
|
||||
)
|
||||
|
||||
|
||||
class HtmlModule(HtmlFields, XModule):
|
||||
@@ -82,6 +87,16 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
|
||||
nc.append(candidate[:-4] + '.html')
|
||||
return candidates + nc
|
||||
|
||||
@classmethod
|
||||
def filter_templates(cls, template, course):
|
||||
"""
|
||||
Filter template that contains 'latex' from templates.
|
||||
|
||||
Show them only if use_latex_compiler is set to True in
|
||||
course settings.
|
||||
"""
|
||||
return (not 'latex' in template['template_id'] or course.use_latex_compiler)
|
||||
|
||||
def get_context(self):
|
||||
"""
|
||||
an override to add in specific rendering context, in this case we need to
|
||||
@@ -90,7 +105,10 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
|
||||
_context = EditingDescriptor.get_context(self)
|
||||
# Add some specific HTML rendering context when editing HTML modules where we pass
|
||||
# the root /c4x/ url for assets. This allows client-side substitutions to occur.
|
||||
_context.update({'base_asset_url': StaticContent.get_base_url_path_for_course_assets(self.location) + '/'})
|
||||
_context.update({
|
||||
'base_asset_url': StaticContent.get_base_url_path_for_course_assets(self.location) + '/',
|
||||
'enable_latex_compiler': self.use_latex_compiler,
|
||||
})
|
||||
return _context
|
||||
|
||||
# NOTE: html descriptors are special. We do not want to parse and
|
||||
@@ -191,6 +209,12 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
|
||||
elt.set("filename", relname)
|
||||
return elt
|
||||
|
||||
@property
|
||||
def non_editable_metadata_fields(self):
|
||||
non_editable_fields = super(HtmlDescriptor, self).non_editable_metadata_fields
|
||||
non_editable_fields.append(HtmlDescriptor.use_latex_compiler)
|
||||
return non_editable_fields
|
||||
|
||||
|
||||
class AboutFields(object):
|
||||
display_name = String(
|
||||
|
||||
@@ -47,6 +47,10 @@ class InheritanceMixin(XBlockMixin):
|
||||
help="String customization substitutions for particular locations",
|
||||
scope=Scope.settings
|
||||
)
|
||||
use_latex_compiler = Boolean(
|
||||
help="Enable LaTeX templates?",
|
||||
default=False,
|
||||
scope=Scope.settings)
|
||||
|
||||
|
||||
def compute_inherited_metadata(descriptor):
|
||||
|
||||
@@ -1,51 +1,6 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: Problem with Adaptive Hint
|
||||
source_code: |
|
||||
\subsection{Problem With Adaptive Hint}
|
||||
|
||||
% Adaptive hints are messages provided to students which depend on
|
||||
% student input. These hints are produced using a script embedded
|
||||
% within the problem (written in Python).
|
||||
%
|
||||
% Here is an example. This example uses LaTeX as a high-level
|
||||
% soure language for the problem. The problem can also be coded
|
||||
% directly in XML.
|
||||
|
||||
This problem demonstrates a question with hints, based on using the
|
||||
{\tt hintfn} method.
|
||||
|
||||
\begin{edXscript}
|
||||
def test_str(expect, ans):
|
||||
print expect, ans
|
||||
ans = ans.strip("'")
|
||||
ans = ans.strip('"')
|
||||
return expect == ans.lower()
|
||||
|
||||
def hint_fn(answer_ids, student_answers, new_cmap, old_cmap):
|
||||
aid = answer_ids[0]
|
||||
ans = str(student_answers[aid]).lower()
|
||||
print 'hint_fn called, ans=', ans
|
||||
hint = ''
|
||||
if 'java' in ans:
|
||||
hint = 'that is only good for drinking'
|
||||
elif 'perl' in ans:
|
||||
hint = 'not that rich'
|
||||
elif 'pascal' in ans:
|
||||
hint = 'that is a beatnick language'
|
||||
elif 'fortran' in ans:
|
||||
hint = 'those were the good days'
|
||||
elif 'clu' in ans:
|
||||
hint = 'you must be invariant'
|
||||
if hint:
|
||||
hint = "<font color='blue'>Hint: {0}</font>".format(hint)
|
||||
new_cmap.set_hint_and_mode(aid,hint,'always')
|
||||
\end{edXscript}
|
||||
|
||||
What is the best programming language that exists today? You may
|
||||
enter your answer in upper or lower case, with or without quotes.
|
||||
|
||||
\edXabox{type="custom" cfn='test_str' expect='python' hintfn='hint_fn'}
|
||||
markdown: !!null
|
||||
data: |
|
||||
<problem>
|
||||
@@ -61,7 +16,7 @@ data: |
|
||||
ans = ans.strip("'")
|
||||
ans = ans.strip('"')
|
||||
return expect == ans.lower()
|
||||
|
||||
|
||||
def hint_fn(answer_ids, student_answers, new_cmap, old_cmap):
|
||||
aid = answer_ids[0]
|
||||
ans = str(student_answers[aid]).lower()
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: Problem with Adaptive Hint in Latex
|
||||
source_code: |
|
||||
\subsection{Problem With Adaptive Hint}
|
||||
|
||||
% Adaptive hints are messages provided to students which depend on
|
||||
% student input. These hints are produced using a script embedded
|
||||
% within the problem (written in Python).
|
||||
%
|
||||
% Here is an example. This example uses LaTeX as a high-level
|
||||
% soure language for the problem. The problem can also be coded
|
||||
% directly in XML.
|
||||
|
||||
This problem demonstrates a question with hints, based on using the
|
||||
{\tt hintfn} method.
|
||||
|
||||
\begin{edXscript}
|
||||
def test_str(expect, ans):
|
||||
print expect, ans
|
||||
ans = ans.strip("'")
|
||||
ans = ans.strip('"')
|
||||
return expect == ans.lower()
|
||||
|
||||
def hint_fn(answer_ids, student_answers, new_cmap, old_cmap):
|
||||
aid = answer_ids[0]
|
||||
ans = str(student_answers[aid]).lower()
|
||||
print 'hint_fn called, ans=', ans
|
||||
hint = ''
|
||||
if 'java' in ans:
|
||||
hint = 'that is only good for drinking'
|
||||
elif 'perl' in ans:
|
||||
hint = 'not that rich'
|
||||
elif 'pascal' in ans:
|
||||
hint = 'that is a beatnick language'
|
||||
elif 'fortran' in ans:
|
||||
hint = 'those were the good days'
|
||||
elif 'clu' in ans:
|
||||
hint = 'you must be invariant'
|
||||
if hint:
|
||||
hint = "<font color='blue'>Hint: {0}</font>".format(hint)
|
||||
new_cmap.set_hint_and_mode(aid,hint,'always')
|
||||
\end{edXscript}
|
||||
|
||||
What is the best programming language that exists today? You may
|
||||
enter your answer in upper or lower case, with or without quotes.
|
||||
|
||||
\edXabox{type="custom" cfn='test_str' expect='python' hintfn='hint_fn'}
|
||||
markdown: !!null
|
||||
data: |
|
||||
<problem>
|
||||
<text>
|
||||
<p>
|
||||
<h4>Problem With Adaptive Hint</h4>
|
||||
</p>
|
||||
<p>
|
||||
This problem demonstrates a question with hints, based on using the <tt class="tt">hintfn</tt> method. </p>
|
||||
<script type="text/python" system_path="python_lib">
|
||||
def test_str(expect, ans):
|
||||
print expect, ans
|
||||
ans = ans.strip("'")
|
||||
ans = ans.strip('"')
|
||||
return expect == ans.lower()
|
||||
|
||||
def hint_fn(answer_ids, student_answers, new_cmap, old_cmap):
|
||||
aid = answer_ids[0]
|
||||
ans = str(student_answers[aid]).lower()
|
||||
print 'hint_fn called, ans=', ans
|
||||
hint = ''
|
||||
if 'java' in ans:
|
||||
hint = 'that is only good for drinking'
|
||||
elif 'perl' in ans:
|
||||
hint = 'not that rich'
|
||||
elif 'pascal' in ans:
|
||||
hint = 'that is a beatnick language'
|
||||
elif 'fortran' in ans:
|
||||
hint = 'those were the good days'
|
||||
elif 'clu' in ans:
|
||||
hint = 'you must be invariant'
|
||||
if hint:
|
||||
hint = "<font color='blue'>Hint: {0}</font>".format(hint)
|
||||
new_cmap.set_hint_and_mode(aid,hint,'always')
|
||||
</script>
|
||||
<p>
|
||||
What is the best programming language that exists today? You may enter your answer in upper or lower case, with or without quotes. </p>
|
||||
<p>
|
||||
<customresponse cfn="test_str" expect="python">
|
||||
<textline correct_answer="python"/>
|
||||
<hintgroup hintfn="hint_fn"/>
|
||||
</customresponse>
|
||||
</p>
|
||||
</text>
|
||||
</problem>
|
||||
Reference in New Issue
Block a user