From b5bf4b7500adfad718db952503a94f7dc90030b3 Mon Sep 17 00:00:00 2001
From: Alexander Kryklia
Date: Thu, 24 Oct 2013 17:13:34 +0300
Subject: [PATCH] Enable latex problems via key in course.settings.
BLD-426
---
CHANGELOG.rst | 3 +
...ings.feature => advanced_settings.feature} | 0
...anced-settings.py => advanced_settings.py} | 0
.../contentstore/features/component.feature | 25 ++++-
.../contentstore/features/html-editor.py | 1 +
.../contentstore/features/problem-editor.py | 11 +++
.../contentstore/views/component.py | 14 +--
cms/templates/widgets/metadata-edit.html | 2 +-
common/lib/xmodule/xmodule/capa_module.py | 33 ++++++-
common/lib/xmodule/xmodule/html_module.py | 28 +++++-
.../xmodule/modulestore/inheritance.py | 4 +
.../templates/problem/problem_with_hint.yaml | 47 +---------
.../problem/problem_with_hint_in_latex.yaml | 93 +++++++++++++++++++
13 files changed, 199 insertions(+), 62 deletions(-)
rename cms/djangoapps/contentstore/features/{advanced-settings.feature => advanced_settings.feature} (100%)
rename cms/djangoapps/contentstore/features/{advanced-settings.py => advanced_settings.py} (100%)
create mode 100644 common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index e6d6540c14a8..6dcd6cd48fe2 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -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
diff --git a/cms/djangoapps/contentstore/features/advanced-settings.feature b/cms/djangoapps/contentstore/features/advanced_settings.feature
similarity index 100%
rename from cms/djangoapps/contentstore/features/advanced-settings.feature
rename to cms/djangoapps/contentstore/features/advanced_settings.feature
diff --git a/cms/djangoapps/contentstore/features/advanced-settings.py b/cms/djangoapps/contentstore/features/advanced_settings.py
similarity index 100%
rename from cms/djangoapps/contentstore/features/advanced-settings.py
rename to cms/djangoapps/contentstore/features/advanced_settings.py
diff --git a/cms/djangoapps/contentstore/features/component.feature b/cms/djangoapps/contentstore/features/component.feature
index 95de94c4bd6f..e2cc4bc3321d 100644
--- a/cms/djangoapps/contentstore/features/component.feature
+++ b/cms/djangoapps/contentstore/features/component.feature
@@ -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 "" "Advanced Problem" component
+ Then I see a "" 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
diff --git a/cms/djangoapps/contentstore/features/html-editor.py b/cms/djangoapps/contentstore/features/html-editor.py
index f00db67c071d..4a6d3bdefeb5 100644
--- a/cms/djangoapps/contentstore/features/html-editor.py
+++ b/cms/djangoapps/contentstore/features/html-editor.py
@@ -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',
diff --git a/cms/djangoapps/contentstore/features/problem-editor.py b/cms/djangoapps/contentstore/features/problem-editor.py
index 380845897308..758ac299bed4 100644
--- a/cms/djangoapps/contentstore/features/problem-editor.py
+++ b/cms/djangoapps/contentstore/features/problem-editor.py
@@ -5,6 +5,7 @@
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',
diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py
index 44d892e1f9d7..f51789739c76 100644
--- a/cms/djangoapps/contentstore/views/component.py
+++ b/cms/djangoapps/contentstore/views/component.py
@@ -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
diff --git a/cms/templates/widgets/metadata-edit.html b/cms/templates/widgets/metadata-edit.html
index 70a2df3400fb..4ce5f3bfeb4b 100644
--- a/cms/templates/widgets/metadata-edit.html
+++ b/cms/templates/widgets/metadata-edit.html
@@ -29,7 +29,7 @@
<%static:include path="js/metadata-list-entry.underscore" />
-<% 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:
diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py
index 586464b0589d..27184bb46b73 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -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 @@ def backcompat_paths(cls, path):
@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
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index 5b3ca5661ab6..25cebe8e420f 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -7,7 +7,7 @@
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 @@ def backcompat_paths(cls, path):
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 @@ def get_context(self):
_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 @@ def definition_to_xml(self, resource_fs):
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(
diff --git a/common/lib/xmodule/xmodule/modulestore/inheritance.py b/common/lib/xmodule/xmodule/modulestore/inheritance.py
index a518034e610f..8962447ec0ba 100644
--- a/common/lib/xmodule/xmodule/modulestore/inheritance.py
+++ b/common/lib/xmodule/xmodule/modulestore/inheritance.py
@@ -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):
diff --git a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml
index aa1000a93a4f..f9a171b3e1af 100644
--- a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml
+++ b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml
@@ -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 = "Hint: {0}".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: |
@@ -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()
diff --git a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml
new file mode 100644
index 000000000000..223d16ae9d38
--- /dev/null
+++ b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml
@@ -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 = "Hint: {0}".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 With Adaptive Hint
+
+
+ This problem demonstrates a question with hints, based on using the hintfn method.
+
+
+ What is the best programming language that exists today? You may enter your answer in upper or lower case, with or without quotes.
+
+
+
+
+
+
+
+