diff --git a/runestone/activecode/activecode.py b/runestone/activecode/activecode.py
index a230879ce..8000cc6ad 100644
--- a/runestone/activecode/activecode.py
+++ b/runestone/activecode/activecode.py
@@ -37,6 +37,9 @@ def setup(app):
app.add_directive('activecode', ActiveCode)
app.add_directive('actex', ActiveExercise)
app.add_role('textfield',textfield_role)
+ app.add_config_value('activecode_div_class', "runestone explainer ac_section alert alert-warning", 'html')
+ app.add_config_value('activecode_hide_load_history', False, 'html')
+
app.add_stylesheet('activecode.css')
app.add_javascript('jquery.highlight.js')
@@ -59,14 +62,14 @@ def setup(app):
TEMPLATE_START = """
-
+
"""
TEMPLATE_END = """
@@ -158,6 +161,11 @@ class ActiveCode(RunestoneIdDirective):
print("hello world")
====
print("Hidden code, such as unit tests come after the four = signs")
+
+config values (conf.py):
+
+- activecode_div_class - custom CSS class of the component's outermost div
+- activecode_hide_load_history - if True, hide the load history button
"""
required_arguments = 1
optional_arguments = 1
@@ -320,6 +328,12 @@ def run(self):
else:
self.options['gradebutton'] = "data-gradebutton=true"
+ self.options['divclass'] = env.config.activecode_div_class
+ if env.config.activecode_hide_load_history:
+ self.options['hidehistory'] = 'data-hidehistory=true'
+ else:
+ self.options['hidehistory'] = ''
+
if self.content:
if '====' in self.content:
idx = self.content.index('====')
diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js
index 97b40343e..8f769b807 100755
--- a/runestone/activecode/js/activecode.js
+++ b/runestone/activecode/js/activecode.js
@@ -36,6 +36,7 @@ ActiveCode.prototype.init = function(opts) {
this.includes = $(orig).data('include');
this.hidecode = $(orig).data('hidecode');
this.chatcodes = $(orig).data('chatcodes');
+ this.hidehistory = $(orig).data('hidehistory');
this.runButton = null;
this.enabledownload = $(orig).data('enabledownload');
this.downloadButton = null;
@@ -178,7 +179,7 @@ ActiveCode.prototype.createControls = function () {
$(butt).attr("type","button")
}
- if (! this.hidecode) {
+ if (!this.hidecode && !this.hidehistory) {
var butt = document.createElement("button");
$(butt).text($.i18n("msg_activecode_load_history"));
$(butt).addClass("btn btn-default");
diff --git a/runestone/assess/assess.py b/runestone/assess/assess.py
index 22eb2f003..7aa714188 100644
--- a/runestone/assess/assess.py
+++ b/runestone/assess/assess.py
@@ -32,6 +32,8 @@ def setup(app):
app.add_directive('qnum', QuestionNumber)
app.add_directive('timed', TimedDirective)
+ app.add_config_value('mchoice_div_class', 'runestone alert alert-warning', 'html')
+
#app.add_javascript('assess.js')
app.add_javascript('mchoice.js')
app.add_javascript('timedmc.js')
@@ -45,6 +47,7 @@ def setup(app):
app.add_node(FeedbackBulletList, html=(visit_feedback_bullet_node, depart_feedback_bullet_node))
app.add_node(FeedbackListItem, html=(visit_feedback_list_item, depart_feedback_list_item))
+
class AddButton(RunestoneIdDirective):
diff --git a/runestone/assess/js/mchoice.js b/runestone/assess/js/mchoice.js
index 295e3e59f..cf90fda31 100644
--- a/runestone/assess/js/mchoice.js
+++ b/runestone/assess/js/mchoice.js
@@ -137,7 +137,7 @@ MultipleChoice.prototype.createMCForm = function () {
MultipleChoice.prototype.renderMCContainer = function () {
this.containerDiv = document.createElement("div");
$(this.containerDiv).html(this.question);
- $(this.containerDiv).addClass("alert alert-warning");
+ $(this.containerDiv).addClass(this.origElem.getAttribute("class"));
this.containerDiv.id = this.divid;
};
diff --git a/runestone/assess/multiplechoice.py b/runestone/assess/multiplechoice.py
index f1d30a913..9c7fdcd1f 100644
--- a/runestone/assess/multiplechoice.py
+++ b/runestone/assess/multiplechoice.py
@@ -144,6 +144,10 @@ class MChoice(Assessment):
- ... and so on.
- Up to 26 answers and feedback pairs may be provided.
+
+ config values (conf.py):
+
+ - mchoice_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 1
@@ -176,7 +180,7 @@ def run(self):
super(MChoice, self).run()
TEMPLATE_START = '''
-
+
'''
@@ -198,7 +202,8 @@ def run(self):
mcNode.template_end = TEMPLATE_END
self.state.nested_parse(self.content, self.content_offset, mcNode)
-
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.mchoice_div_class
# Expected _`structure`, with assigned variable names and transformations made:
#
# .. code-block::
diff --git a/runestone/clickableArea/clickable.py b/runestone/clickableArea/clickable.py
index 6a8fe194f..37871a39b 100644
--- a/runestone/clickableArea/clickable.py
+++ b/runestone/clickableArea/clickable.py
@@ -29,9 +29,10 @@ def setup(app):
app.add_node(ClickableAreaNode, html=(visit_ca_node, depart_ca_node))
+ app.add_config_value('clickable_div_class', "runestone alert alert-warning", 'html')
TEMPLATE = """
-
+
%(question)s%(feedback)s%(clickcode)s
"""
TEMPLATE_END = """
@@ -97,6 +98,11 @@ class ClickableArea(RunestoneIdDirective):
:incorrect: An array of the indices of the incorrect elements--same format as the correct elements.
--Content--
+
+
+config values (conf.py):
+
+- clickable_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 0
@@ -151,4 +157,8 @@ def run(self):
if "iscode" not in self.options:
self.state.nested_parse(self.content, self.content_offset, clickNode)
+
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.clickable_div_class
+
return [clickNode]
diff --git a/runestone/clickableArea/js/clickable.js b/runestone/clickableArea/js/clickable.js
index d78507367..899af3c5e 100644
--- a/runestone/clickableArea/js/clickable.js
+++ b/runestone/clickableArea/js/clickable.js
@@ -90,7 +90,7 @@ ClickableArea.prototype.renderNewElements = function () {
// wrapper function for generating everything
this.containerDiv = document.createElement("div");
this.containerDiv.appendChild(this.question);
- $(this.containerDiv).addClass("alert alert-warning");
+ $(this.containerDiv).addClass(this.origElem.getAttribute("class"));
this.newDiv = document.createElement("div");
var newContent = $(this.origElem).html();
diff --git a/runestone/codelens/visualizer.py b/runestone/codelens/visualizer.py
index 758951494..70f38090e 100644
--- a/runestone/codelens/visualizer.py
+++ b/runestone/codelens/visualizer.py
@@ -35,10 +35,12 @@ def setup(app):
app.add_javascript('pytutor.js')
app.add_javascript('codelens.js')
+ app.add_config_value('codelens_div_class', "alert alert-warning cd_section", 'html')
+
VIS = '''
-
+
'''
@@ -164,6 +166,11 @@ class Codelens(RunestoneIdDirective):
x = 0
for i in range(10):
x = x + i
+
+
+config values (conf.py):
+
+- codelens_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 1
@@ -206,6 +213,9 @@ def js_var_finalizer(input_code, output_trace):
CUMULATIVE_MODE = False
self.JS_VARNAME = self.options['divid'] + '_trace'
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.codelens_div_class
+
if 'showoutput' not in self.options:
self.options['embedded'] = 'true' # to set embeddedmode to true
else:
diff --git a/runestone/common/project_template/conf.tmpl b/runestone/common/project_template/conf.tmpl
index c4c271098..8792eaf5c 100644
--- a/runestone/common/project_template/conf.tmpl
+++ b/runestone/common/project_template/conf.tmpl
@@ -231,3 +231,21 @@ html_show_sourcelink = False
# Output file base name for HTML help builder.
htmlhelp_basename = 'PythonCoursewareProjectdoc'
+# Config values for specific Runestone components
+#
+#activecode_div_class = 'runestone explainer ac_section alert alert-warning'
+#activecode_hide_load_history = False
+#mchoice_div_class = 'runestone alert alert-warning'
+#clickable_div_class = 'runestone alert alert-warning'
+#codelens_div_class = 'alert alert-warning cd_section'
+#dragndrop_div_class = 'runestone'
+#fitb_div_class = 'runestone'
+#parsons_div_class = 'runestone'
+#poll_div_class = 'alert alert-warning'
+#shortanswer_div_class = 'journal alert alert-warning'
+#shortanswer_optional_div_class = 'journal alert alert-success'
+#showeval_div_class = 'runestone explainer alert alert-warning'
+#tabbed_div_class = alert alert-warning'
+
+
+
diff --git a/runestone/dragndrop/dragndrop.py b/runestone/dragndrop/dragndrop.py
index c84305211..da447a26b 100644
--- a/runestone/dragndrop/dragndrop.py
+++ b/runestone/dragndrop/dragndrop.py
@@ -30,9 +30,11 @@ def setup(app):
app.add_node(DragNDropNode, html=(visit_dnd_node, depart_dnd_node))
+ app.add_config_value('dragndrop_div_class', 'runestone', 'html')
+
TEMPLATE_START = """
-
+
%(question)s
%(feedback)s
@@ -106,6 +108,10 @@ class DragNDrop(RunestoneIdDirective):
etc. (up to 20 matches)
The question goes here.
+
+config values (conf.py):
+
+- dragndrop_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 0
@@ -158,7 +164,8 @@ def run(self):
source = '\n'
self.options['question'] = source
-
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.dragndrop_div_class
dndNode = DragNDropNode(self.options, rawsource=self.block_text)
dndNode.source, dndNode.line = self.state_machine.get_source_and_line(self.lineno)
diff --git a/runestone/fitb/fitb.py b/runestone/fitb/fitb.py
index 6ab14d03a..a2f185222 100644
--- a/runestone/fitb/fitb.py
+++ b/runestone/fitb/fitb.py
@@ -34,6 +34,8 @@ def setup(app):
app.add_node(FITBNode, html=(visit_fitb_node, depart_fitb_node))
app.add_node(BlankNode, html=(visit_blank_node, depart_blank_node))
app.add_node(FITBFeedbackNode, html=(visit_fitb_feedback_node, depart_fitb_feedback_node))
+ app.add_config_value('fitb_div_class', 'runestone', 'html')
+
class FITBNode(nodes.General, nodes.Element, RunestoneNode):
def __init__(self, content, **kwargs):
@@ -99,6 +101,10 @@ class FillInTheBlank(RunestoneIdDirective):
- :2: Right on! Numbers can be given in decimal, hex (0x10 == 16), octal (0o10 == 8), binary (0b10 == 2), or using scientific notation (1e1 == 10), both here and by the user when answering the question.
:2 1: Close.... (The second number is a tolerance, so this matches 1 or 3.)
:x: Nope. (As earlier, this matches anything.)
+
+ config values (conf.py):
+
+ - fitb_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 0
@@ -121,7 +127,7 @@ def run(self):
super(FillInTheBlank, self).run()
TEMPLATE_START = '''
-
+
'''
@@ -142,6 +148,8 @@ def run(self):
fitbNode.template_end = TEMPLATE_END
self.state.nested_parse(self.content, self.content_offset, fitbNode)
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.fitb_div_class
# Expected _`structure`, with assigned variable names and transformations made:
#
diff --git a/runestone/parsons/parsons.py b/runestone/parsons/parsons.py
index 2f067c9e9..beff32d96 100755
--- a/runestone/parsons/parsons.py
+++ b/runestone/parsons/parsons.py
@@ -30,10 +30,10 @@ def setup(app):
app.add_javascript('lib/hammer.min.js')
app.add_javascript('parsons.js')
app.add_javascript('timedparsons.js')
-
+ app.add_config_value('parsons_div_class', 'runestone', 'html')
TEMPLATE = '''
-
+
%(qnumber)s: %(instructions)s%(code)s
@@ -87,7 +87,9 @@ def findmax(alist):
return curmax
+config values (conf.py):
+- parsons_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 1
@@ -139,9 +141,11 @@ def findmax(alist):
super(ParsonsProblem, self).run()
addQuestionToDB(self)
+ env = self.state.document.settings.env
self.options['qnumber'] = self.getNumber()
self.options['instructions'] = ""
self.options['code'] = self.content
+ self.options['divclass'] = env.config.parsons_div_class
if 'numbered' in self.options:
self.options['numbered'] = ' data-numbered="' + self.options['numbered'] + '"' #' data-numbered="true"'
diff --git a/runestone/poll/js/poll.js b/runestone/poll/js/poll.js
index 342363822..65f5f8d9f 100644
--- a/runestone/poll/js/poll.js
+++ b/runestone/poll/js/poll.js
@@ -67,7 +67,7 @@ Poll.prototype.renderPoll = function() {
this.resultsDiv = document.createElement("div");
this.containerDiv.id = this.divid + "_container";
- $(this.containerDiv).addClass("alert alert-warning");
+ $(this.containerDiv).addClass(this.origElem.getAttribute("class"));
$(this.pollForm).text(this.question);
$(this.pollForm).attr({
diff --git a/runestone/poll/poll.py b/runestone/poll/poll.py
index d9a765842..1ea6acb8e 100644
--- a/runestone/poll/poll.py
+++ b/runestone/poll/poll.py
@@ -29,10 +29,11 @@ def setup(app):
app.add_stylesheet('poll.css')
app.add_node(PollNode, html=(visit_poll_node, depart_poll_node))
+ app.add_config_value('poll_div_class', 'alert alert-warning', 'html')
TEMPLATE_START = """
-
%(question)s
+%(question)s
"""
TEMPLATE_OPTION = """
@@ -88,6 +89,12 @@ class Poll(RunestoneIdDirective):
:option_1: Mode 2--Implements the "Choose one of these options" type method of poll.
:option_2: Option 2
:option_3: Option 3 ...etc...(Up to 10 options in mode 2)
+
+
+
+config values (conf.py):
+
+- poll_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 0
@@ -136,6 +143,9 @@ def run(self):
else:
self.options["comment"] = ""
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.poll_div_class
+
poll_node = PollNode(self.options, rawsource=self.block_text)
poll_node.source, poll_node.line = self.state_machine.get_source_and_line(self.lineno)
return [poll_node]
diff --git a/runestone/shortanswer/js/shortanswer.js b/runestone/shortanswer/js/shortanswer.js
index 9e8ea0206..886108773 100644
--- a/runestone/shortanswer/js/shortanswer.js
+++ b/runestone/shortanswer/js/shortanswer.js
@@ -44,12 +44,7 @@ ShortAnswer.prototype.init = function (opts) {
ShortAnswer.prototype.renderHTML = function() {
this.containerDiv = document.createElement("div");
this.containerDiv.id = this.divid;
- if (this.optional) {
- $(this.containerDiv).addClass("journal alert alert-success");
- } else {
- $(this.containerDiv).addClass("journal alert alert-warning");
- }
-
+ $(this.containerDiv).addClass(this.origElem.getAttribute("class"));
this.newForm = document.createElement("form");
this.newForm.id = this.divid + "_journal";
this.newForm.name = this.newForm.id;
diff --git a/runestone/shortanswer/shortanswer.py b/runestone/shortanswer/shortanswer.py
index 79a2c296e..132a04f7a 100755
--- a/runestone/shortanswer/shortanswer.py
+++ b/runestone/shortanswer/shortanswer.py
@@ -27,11 +27,12 @@ def setup(app):
app.add_node(JournalNode, html=(visit_journal_node, depart_journal_node))
app.add_javascript('shortanswer.js')
app.add_javascript('timed_shortanswer.js')
-
+ app.add_config_value('shortanswer_div_class', 'journal alert alert-warning', 'html')
+ app.add_config_value('shortanswer_optional_div_class', 'journal alert alert-success', 'html')
TEXT = """
-%(qnum)s: %(content)s
+
"""
@@ -59,6 +60,11 @@ class JournalDirective(Assessment):
:optional:
text of the question goes here
+
+
+config values (conf.py):
+
+- shortanswer_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1 # the div id
optional_arguments = 0
@@ -81,4 +87,10 @@ def run(self):
journal_node = JournalNode(self.options, rawsource=self.block_text)
journal_node.source, journal_node.line = self.state_machine.get_source_and_line(self.lineno)
+ env = self.state.document.settings.env
+ if self.options['optional']:
+ self.options['divclass'] = env.config.shortanswer_optional_div_class
+ else:
+ self.options['divclass'] = env.config.shortanswer_div_class
+
return [journal_node]
diff --git a/runestone/showeval/showeval.py b/runestone/showeval/showeval.py
index c42128841..3cb06cd49 100644
--- a/runestone/showeval/showeval.py
+++ b/runestone/showeval/showeval.py
@@ -26,8 +26,10 @@ def setup(app):
app.add_javascript('showEval.js')
app.add_stylesheet('showEval.css')
+ app.add_config_value('showeval_div_class', 'runestone explainer alert alert-warning', 'html')
+
CODE = """\
-
+
%(preReqLines)s
@@ -57,6 +59,11 @@ class ShowEval(RunestoneIdDirective):
more {{code}}{{what code becomes in step 1}}
more {{what code becomes in step 1}}{{what code becomes in step2}} ##Optional comment for step 2
as many steps as you want {{the first double braces}}{{animate into the second}} wherever.
+
+
+config values (conf.py):
+
+- showeval_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1
optional_arguments = 0
@@ -99,6 +106,9 @@ def run(self):
self.options['preReqLines'] = ''
self.options['steps'] = []
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.showeval_div_class
+
step = False
count = 0
for line in self.content:
diff --git a/runestone/tabbedStuff/js/tabbedstuff.js b/runestone/tabbedStuff/js/tabbedstuff.js
index 48cc4fe08..755e71d50 100644
--- a/runestone/tabbedStuff/js/tabbedstuff.js
+++ b/runestone/tabbedStuff/js/tabbedstuff.js
@@ -74,7 +74,7 @@ TabbedStuff.prototype.findActiveTab = function () { // Checks to see if user
TabbedStuff.prototype.createTabContainer = function () { // First create a container div
this.replacementDiv = document.createElement("div");
this.replacementDiv.id = this.divid;
- $(this.replacementDiv).addClass("alert alert-warning");
+ $(this.replacementDiv).addClass(this.origElem.getAttribute("class"));
$(this.replacementDiv).attr({"role": "tabpanel"});
this.tabsUL = document.createElement("ul");
diff --git a/runestone/tabbedStuff/tabbedStuff.py b/runestone/tabbedStuff/tabbedStuff.py
index 11621e6a4..00ed55434 100644
--- a/runestone/tabbedStuff/tabbedStuff.py
+++ b/runestone/tabbedStuff/tabbedStuff.py
@@ -31,8 +31,10 @@ def setup(app):
app.add_stylesheet('tabbedstuff.css')
+ app.add_config_value('tabbed_div_class', 'alert alert-warning', 'html')
+
#Templates to be formatted by node options
-BEGIN = """
"""
+BEGIN = """
"""
TABDIV_BEGIN = """
"""
@@ -84,6 +86,7 @@ def visit_tabbedstuff_node(self, node):
node.tabbed_stuff_options['inactive'] = ''
res = BEGIN % {'divid':divid,
+ 'divclass':node.tabbed_stuff_options['divclass'],
'inactive':node.tabbed_stuff_options['inactive']}
self.body.append(res)
@@ -108,6 +111,11 @@ class TabDirective(RunestoneDirective):
Content
...
+
+
+config values (conf.py):
+
+- tabbed_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1 # the name of the tab
optional_arguments = 0
@@ -146,6 +154,12 @@ class TabbedStuffDirective(RunestoneDirective):
Content (put tabs here)
...
+
+
+
+config values (conf.py):
+
+- tabbed_div_class - custom CSS class of the component's outermost div
"""
required_arguments = 1 # the div to put the tabbed exhibit in
optional_arguments = 0
@@ -171,6 +185,9 @@ def run(self):
self.options['divid'] = self.arguments[0]
+ env = self.state.document.settings.env
+ self.options['divclass'] = env.config.tabbed_div_class
+
# Create the node, to be populated by "nested_parse".
tabbedstuff_node = TabbedStuffNode(self.options, rawsource=self.block_text)
tabbedstuff_node.source, tabbedstuff_node.line = self.state_machine.get_source_and_line(self.lineno)