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 = '''
    -
    +

    %(caption)s (%(divid)s)

    ''' @@ -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

          +
          +

          %(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)