Merge pull request #2247 from jazkarta/pluggable-problem-types
Make problem types pluggable.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: Announcement
|
||||
data: |
|
||||
<ol>
|
||||
<li>
|
||||
<h2> September 21 </h2>
|
||||
<section class='update-description'>
|
||||
<section class='primary'>
|
||||
<p> Words of encouragement! This is a short note that most students will read. </p>
|
||||
<p class='author'>Anant Agarwal (6.002x Principal Instructor)</p>
|
||||
</section>
|
||||
<p><h3>Primary versus Secondary Updates:</h3> Unfortunately, the internet throws a lot of text at students, and they
|
||||
do not read everything that they are given. However, many students <em>do</em> read all that they are
|
||||
given, and so detailed explainations in this section will benefit the most concientious.
|
||||
Any essential information should be extremely quickly summarized in the primary section for skimmers.</p>
|
||||
<p><h3>Star Forum Poster</h3>
|
||||
Students appreciate knowing that the course staff is reading what they post, and one of several ways
|
||||
that you can do this is by acknowledging the star posters in your announcements.
|
||||
</p>
|
||||
</section>
|
||||
</li>
|
||||
</ol>
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: Anonymous User ID
|
||||
data: |
|
||||
<p>Your explanatory text here.</p>
|
||||
<p><a href="https://YOUR_UNIVERSITY.qualtrics.com/SE/?SID=SV_###############&a=%%USER_ID%%" target="_blank">YOUR_LINK_TEXT</a></p>
|
||||
|
||||
<!-- You can include %%USER_ID%% to include an anonymized user ID in your outside services so that you can relate them later.
|
||||
|
||||
This example is a Qualtrics template:
|
||||
- Replace the "###############" with your Survey ID.
|
||||
- Also replace "YOUR_UNIVERSITY" with your qualtrics ID.
|
||||
- Finally, replace "YOUR_LINK_TEXT" with your link text.
|
||||
- If you wish to embed your survey into the courseware instead of opening a new tab, replace the above HTML with what is provided below.
|
||||
|
||||
<p>Your explanatory text here.</p>
|
||||
<iframe src="https://YOUR_UNIVERSITY.qualtrics.com/SE/?SID=SV_###############&a=%%USER_ID%%" height="1000" width="800" />
|
||||
|
||||
-->
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: E-text Written in LaTeX
|
||||
source_code: |
|
||||
\subsection{Example of E-text in LaTeX}
|
||||
|
||||
It is very convenient to write complex equations in LaTeX.
|
||||
|
||||
\begin{equation}
|
||||
x = \frac{-b\pm\sqrt{b^2-4*a*c}}{2a}
|
||||
\end{equation}
|
||||
|
||||
Seize the moment.
|
||||
|
||||
data: |
|
||||
<html>
|
||||
<h2>Example: E-text page</h2>
|
||||
<p>
|
||||
It is very convenient to write complex equations in LaTeX.
|
||||
</p>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: Zooming Image
|
||||
data: |
|
||||
<h2>ZOOMING DIAGRAMS</h2>
|
||||
<p>Some edX classes use extremely large, extremely detailed graphics. To make it easier to understand we can offer two versions of those graphics, with the zoomed section showing when you click on the main view.</p>
|
||||
<p>The example below is from <a href="https://www.edx.org/course/mit/7-00x/introduction-biology-secret-life/1014" target="_blank">7.00x: Introduction to Biology</a> and shows a subset of the biochemical reactions that cells carry out. </p>
|
||||
<p>You can view the chemical structures of the molecules by clicking on them. The magnified view also lists the enzymes involved in each step.</p>
|
||||
|
||||
<div class="zooming-image-place" style="position: relative;">
|
||||
<a class="loupe" href="https://studio.edx.org/c4x/edX/DemoX/asset/pathways_detail_01.png">
|
||||
<img alt="magnify" src="https://studio.edx.org/c4x/edX/DemoX/asset/pathways_overview_01.png" />
|
||||
</a>
|
||||
<div class="script_placeholder" data-src="https://studio.edx.org/c4x/edX/DemoX/asset/jquery.loupeAndLightbox.js" />
|
||||
</div>
|
||||
<script type="text/javascript">// <![CDATA[
|
||||
JavascriptLoader.executeModuleScripts($('.zooming-image-place').eq(0), function() {
|
||||
$('.loupe').loupeAndLightbox({
|
||||
width: 350,
|
||||
height: 350,
|
||||
lightbox: false
|
||||
});
|
||||
});
|
||||
// ]]></script>
|
||||
<div id="ap_listener_added"></div>
|
||||
|
||||
56
common/lib/xmodule/xmodule/tests/test_resource_templates.py
Normal file
56
common/lib/xmodule/xmodule/tests/test_resource_templates.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Tests for xmodule.x_module.ResourceTemplates
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from xmodule.x_module import ResourceTemplates
|
||||
|
||||
|
||||
class ResourceTemplatesTests(unittest.TestCase):
|
||||
"""
|
||||
Tests for xmodule.x_module.ResourceTemplates
|
||||
"""
|
||||
def test_templates(self):
|
||||
expected = set([
|
||||
'latex_html.yaml',
|
||||
'zooming_image.yaml',
|
||||
'announcement.yaml',
|
||||
'anon_user_id.yaml'])
|
||||
got = set((t['template_id'] for t in TestClass.templates()))
|
||||
self.assertEqual(expected, got)
|
||||
|
||||
def test_templates_no_suchdir(self):
|
||||
self.assertEqual(len(TestClass2.templates()), 0)
|
||||
|
||||
def test_get_template(self):
|
||||
self.assertEqual(
|
||||
TestClass.get_template('latex_html.yaml')['template_id'],
|
||||
'latex_html.yaml')
|
||||
|
||||
|
||||
class TestClass(ResourceTemplates):
|
||||
"""
|
||||
Derives from the class under test for testing purposes.
|
||||
|
||||
Since `ResourceTemplates` is intended to be used as a mixin, we need to
|
||||
derive a class from it in order to fill in some data it's expecting to find
|
||||
in its mro.
|
||||
"""
|
||||
template_packages = [__name__]
|
||||
|
||||
@classmethod
|
||||
def get_template_dir(cls):
|
||||
return 'templates/test'
|
||||
|
||||
|
||||
class TestClass2(TestClass):
|
||||
"""
|
||||
Like TestClass, but `get_template_dir` returns a directory that doesn't
|
||||
exist.
|
||||
|
||||
See `TestClass`.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_template_dir(cls):
|
||||
return 'foo'
|
||||
@@ -6,7 +6,12 @@ import yaml
|
||||
from functools import partial
|
||||
from lxml import etree
|
||||
from collections import namedtuple
|
||||
from pkg_resources import resource_listdir, resource_string, resource_isdir
|
||||
from pkg_resources import (
|
||||
resource_exists,
|
||||
resource_listdir,
|
||||
resource_string,
|
||||
resource_isdir,
|
||||
)
|
||||
from webob import Response
|
||||
from webob.multidict import MultiDict
|
||||
|
||||
@@ -14,7 +19,7 @@ from xblock.core import XBlock
|
||||
from xblock.fields import Scope, Integer, Float, List, XBlockMixin, String
|
||||
from xblock.fragment import Fragment
|
||||
from xblock.plugin import default_select
|
||||
from xblock.runtime import Runtime, MemoryIdManager
|
||||
from xblock.runtime import Runtime
|
||||
from xmodule.fields import RelativeTime
|
||||
|
||||
from xmodule.errortracker import exc_info_to_str
|
||||
@@ -508,6 +513,8 @@ class ResourceTemplates(object):
|
||||
Gets the templates associated w/ a containing cls. The cls must have a 'template_dir_name' attribute.
|
||||
It finds the templates as directly in this directory under 'templates'.
|
||||
"""
|
||||
template_packages = [__name__]
|
||||
|
||||
@classmethod
|
||||
def templates(cls):
|
||||
"""
|
||||
@@ -520,14 +527,17 @@ class ResourceTemplates(object):
|
||||
templates = []
|
||||
dirname = cls.get_template_dir()
|
||||
if dirname is not None:
|
||||
for template_file in resource_listdir(__name__, dirname):
|
||||
if not template_file.endswith('.yaml'):
|
||||
log.warning("Skipping unknown template file %s", template_file)
|
||||
for pkg in cls.template_packages:
|
||||
if not resource_isdir(pkg, dirname):
|
||||
continue
|
||||
template_content = resource_string(__name__, os.path.join(dirname, template_file))
|
||||
template = yaml.safe_load(template_content)
|
||||
template['template_id'] = template_file
|
||||
templates.append(template)
|
||||
for template_file in resource_listdir(pkg, dirname):
|
||||
if not template_file.endswith('.yaml'):
|
||||
log.warning("Skipping unknown template file %s", template_file)
|
||||
continue
|
||||
template_content = resource_string(pkg, os.path.join(dirname, template_file))
|
||||
template = yaml.safe_load(template_content)
|
||||
template['template_id'] = template_file
|
||||
templates.append(template)
|
||||
|
||||
return templates
|
||||
|
||||
@@ -555,15 +565,13 @@ class ResourceTemplates(object):
|
||||
"""
|
||||
dirname = cls.get_template_dir()
|
||||
if dirname is not None:
|
||||
try:
|
||||
template_content = resource_string(__name__, os.path.join(dirname, template_id))
|
||||
except IOError:
|
||||
return None
|
||||
template = yaml.safe_load(template_content)
|
||||
template['template_id'] = template_id
|
||||
return template
|
||||
else:
|
||||
return None
|
||||
path = os.path.join(dirname, template_id)
|
||||
for pkg in cls.template_packages:
|
||||
if resource_exists(pkg, path):
|
||||
template_content = resource_string(pkg, path)
|
||||
template = yaml.safe_load(template_content)
|
||||
template['template_id'] = template_id
|
||||
return template
|
||||
|
||||
|
||||
def prefer_xmodules(identifier, entry_points):
|
||||
|
||||
Reference in New Issue
Block a user