first import book
This commit is contained in:
parent
6be2701fd8
commit
dfd9c869d5
233 changed files with 47797 additions and 0 deletions
2
book/modules/luther/sphinx/assess/__init__.py
Normal file
2
book/modules/luther/sphinx/assess/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
from .assess import *
|
||||
112
book/modules/luther/sphinx/assess/assess.py
Normal file
112
book/modules/luther/sphinx/assess/assess.py
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# Copyright (C) 2011 Bradley N. Miller
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__author__ = 'bmiller'
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst import Directive
|
||||
from assessbase import Assessment
|
||||
from multiplechoice import *
|
||||
from textfield import *
|
||||
from blankfill import *
|
||||
import json
|
||||
import random
|
||||
|
||||
def setup(app):
|
||||
app.add_directive('mchoicemf',MChoiceMF)
|
||||
app.add_directive('mchoicema',MChoiceMA)
|
||||
app.add_directive('fillintheblank',FillInTheBlank)
|
||||
app.add_directive('mcmfrandom',MChoiceRandomMF)
|
||||
app.add_directive('addbutton',AddButton)
|
||||
app.add_directive('qnum',QuestionNumber)
|
||||
app.add_role('textfield',textfield_role)
|
||||
|
||||
|
||||
app.add_javascript('assess.js')
|
||||
|
||||
app.add_node(MChoiceNode, html=(visit_mc_node, depart_mc_node))
|
||||
app.add_node(FITBNode, html=(visit_fitb_node, depart_fitb_node))
|
||||
|
||||
class AddButton(Directive):
|
||||
required_arguments = 1
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
has_content = True
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
:param self:
|
||||
:return:
|
||||
.. addbutton:: bname
|
||||
|
||||
...
|
||||
"""
|
||||
|
||||
TEMPLATE_START = '''
|
||||
<div id="%(divid)s" class="alert alert-warning">
|
||||
<form name="%(divid)s_form" method="get" action="" onsubmit="return false;">
|
||||
'''
|
||||
|
||||
TEMPLATE_END = '''
|
||||
<button class='btn btn-inverse' name="reset" onclick="resetPage('%(divid)s')">Forget My Answers</button>
|
||||
</form>
|
||||
</div>
|
||||
'''
|
||||
|
||||
self.options['divid'] = self.arguments[0]
|
||||
|
||||
res = ""
|
||||
res = TEMPLATE_START % self.options
|
||||
|
||||
res += TEMPLATE_END % self.options
|
||||
return [nodes.raw('',res , format='html')]
|
||||
|
||||
|
||||
class QuestionNumber(Directive):
|
||||
"""Set Parameters for Question Numbering"""
|
||||
required_arguments = 0
|
||||
optional_arguments = 3
|
||||
has_content = False
|
||||
option_spec = { 'prefix': directives.unchanged,
|
||||
'suffix': directives.unchanged,
|
||||
'start': directives.positive_int
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
|
||||
if 'start' in self.options:
|
||||
env.assesscounter = self.options['start'] - 1
|
||||
|
||||
if 'prefix' in self.options:
|
||||
env.assessprefix = self.options['prefix']
|
||||
|
||||
if 'suffix' in self.options:
|
||||
env.assesssuffix = self.options['suffix']
|
||||
|
||||
return []
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#####################
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
95
book/modules/luther/sphinx/assess/assessbase.py
Normal file
95
book/modules/luther/sphinx/assess/assessbase.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Copyright (C) 2011 Bradley N. Miller
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__author__ = 'bmiller'
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst import Directive
|
||||
|
||||
|
||||
_base_js_escapes = (
|
||||
('\\', r'\u005C'),
|
||||
('\'', r'\u0027'),
|
||||
('"', r'\u0022'),
|
||||
("'", r'\u0027'),
|
||||
('>', r'\u003E'),
|
||||
('<', r'\u003C'),
|
||||
('&', r'\u0026'),
|
||||
('=', r'\u003D'),
|
||||
('-', r'\u002D'),
|
||||
(';', r'\u003B'),
|
||||
(u'\u2028', r'\u2028'),
|
||||
(u'\u2029', r'\u2029')
|
||||
)
|
||||
|
||||
# Escape every ASCII character with a value less than 32.
|
||||
_js_escapes = (_base_js_escapes +
|
||||
tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
|
||||
|
||||
# escapejs from Django: https://www.djangoproject.com/
|
||||
def escapejs(value):
|
||||
"""Hex encodes characters for use in JavaScript strings."""
|
||||
if not isinstance(value, basestring):
|
||||
value = str(value)
|
||||
|
||||
for bad, good in _js_escapes:
|
||||
value = value.replace(bad, good)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
class Assessment(Directive):
|
||||
"""Base Class for assessments"""
|
||||
|
||||
def getNumber(self):
|
||||
env = self.state.document.settings.env
|
||||
if not hasattr(env,'assesscounter'):
|
||||
env.assesscounter = 0
|
||||
env.assesscounter += 1
|
||||
|
||||
res = "Q-%d"
|
||||
|
||||
if hasattr(env,'assessprefix'):
|
||||
res = env.assessprefix + "%d"
|
||||
|
||||
res = res % env.assesscounter
|
||||
|
||||
if hasattr(env, 'assesssuffix'):
|
||||
res += env.assesssuffix
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def run(self):
|
||||
|
||||
self.options['qnumber'] = self.getNumber()
|
||||
|
||||
self.options['divid'] = self.arguments[0]
|
||||
|
||||
if self.content[0][:2] == '..': # first line is a directive
|
||||
self.content[0] = self.options['qnumber'] + ': \n\n' + self.content[0]
|
||||
else:
|
||||
self.content[0] = self.options['qnumber'] + ': ' + self.content[0]
|
||||
|
||||
if self.content:
|
||||
if 'iscode' in self.options:
|
||||
self.options['bodytext'] = '<pre>' + "\n".join(self.content) + '</pre>'
|
||||
else:
|
||||
self.options['bodytext'] = "\n".join(self.content)
|
||||
else:
|
||||
self.options['bodytext'] = '\n'
|
||||
|
||||
|
||||
123
book/modules/luther/sphinx/assess/blankfill.py
Normal file
123
book/modules/luther/sphinx/assess/blankfill.py
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# Copyright (C) 2013 Bradley N. Miller
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__author__ = 'bmiller'
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst import Directive
|
||||
from assessbase import *
|
||||
import json
|
||||
import random
|
||||
|
||||
|
||||
|
||||
class FITBNode(nodes.General, nodes.Element):
|
||||
def __init__(self,content):
|
||||
"""
|
||||
|
||||
Arguments:
|
||||
- `self`:
|
||||
- `content`:
|
||||
"""
|
||||
super(FITBNode,self).__init__()
|
||||
self.fitb_options = content
|
||||
|
||||
|
||||
def visit_fitb_node(self,node):
|
||||
res = node.template_start % node.fitb_options
|
||||
|
||||
self.body.append(res)
|
||||
|
||||
|
||||
def depart_fitb_node(self,node):
|
||||
fbl = []
|
||||
for k in sorted(node.fitb_options.keys()):
|
||||
if 'feedback' in k:
|
||||
pair = eval(node.fitb_options[k])
|
||||
p1 = escapejs(pair[1])
|
||||
newpair = (pair[0],p1)
|
||||
fbl.append(newpair)
|
||||
|
||||
if 'casei' in node.fitb_options:
|
||||
node.fitb_options['casei'] = 'true'
|
||||
else:
|
||||
node.fitb_options['casei'] = 'false'
|
||||
node.fitb_options['fbl'] = json.dumps(fbl).replace('"',"'")
|
||||
res = ""
|
||||
|
||||
res += node.template_end % node.fitb_options
|
||||
|
||||
self.body.append(res)
|
||||
|
||||
|
||||
class FillInTheBlank(Assessment):
|
||||
required_arguments = 1
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
has_content = True
|
||||
option_spec = {'correct':directives.unchanged,
|
||||
'feedback':directives.unchanged,
|
||||
'feedback1':directives.unchanged,
|
||||
'feedback2':directives.unchanged,
|
||||
'feedback3':directives.unchanged,
|
||||
'feedback4':directives.unchanged,
|
||||
'blankid':directives.unchanged,
|
||||
'iscode':directives.flag,
|
||||
'casei':directives.flag # case insensitive matching
|
||||
}
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
process the fillintheblank directive and generate html for output.
|
||||
:param self:
|
||||
:return:
|
||||
.. fillintheblank:: qname
|
||||
:iscode: boolean
|
||||
:correct: somestring
|
||||
:feedback: -- displayed if wrong
|
||||
:feedback: ('.*', 'this is the message')
|
||||
Question text
|
||||
...
|
||||
"""
|
||||
|
||||
TEMPLATE_START = '''
|
||||
<div id="%(divid)s" class="alert alert-warning">
|
||||
'''
|
||||
|
||||
TEMPLATE_END = '''
|
||||
<script>
|
||||
$(document).ready(function(){checkPreviousFIB('%(divid)s');});
|
||||
</script>
|
||||
<button class='btn btn-success' name="do answer" onclick="checkFIBStorage('%(divid)s', '%(blankid)s', '%(correct)s',%(fbl)s, %(casei)s)">Check Me</button>
|
||||
<button class='btn btn-default' id="%(divid)s_bcomp" disabled name="compare" onclick="compareFITBAnswers('%(divid)s');">Compare Me</button>
|
||||
<br />
|
||||
<br />
|
||||
<div id="%(divid)s_feedback">
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
|
||||
super(FillInTheBlank,self).run()
|
||||
|
||||
fitbNode = FITBNode(self.options)
|
||||
fitbNode.template_start = TEMPLATE_START
|
||||
fitbNode.template_end = TEMPLATE_END
|
||||
|
||||
self.state.nested_parse(self.content, self.content_offset, fitbNode)
|
||||
|
||||
return [fitbNode]
|
||||
|
||||
|
||||
1
book/modules/luther/sphinx/assess/min/assess-ck.js
Normal file
1
book/modules/luther/sphinx/assess/min/assess-ck.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
var checkMe=function(a,b,c){var d,e=document.forms[a+"_form"].elements.group1;for(var f=e.length-1;f>=0;f--)e[f].checked&&(d=e[f].value);feedBack("#"+a+"_feedback",d==b,c)},feedBack=function(a,b,c){b?$(a).html("You are Correct!"):$(a).html("Inorrect. "+c)};
|
||||
352
book/modules/luther/sphinx/assess/multiplechoice.py
Normal file
352
book/modules/luther/sphinx/assess/multiplechoice.py
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
# Copyright (C) 2013 Bradley N. Miller, Barabara Ericson
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__author__ = 'bmiller'
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst import Directive
|
||||
from assessbase import *
|
||||
import json
|
||||
import random
|
||||
|
||||
|
||||
|
||||
class MChoiceNode(nodes.General, nodes.Element):
|
||||
def __init__(self,content):
|
||||
"""
|
||||
|
||||
Arguments:
|
||||
- `self`:
|
||||
- `content`:
|
||||
"""
|
||||
super(MChoiceNode,self).__init__()
|
||||
self.mc_options = content
|
||||
|
||||
|
||||
def visit_mc_node(self,node):
|
||||
res = ""
|
||||
res = node.template_start % node.mc_options
|
||||
|
||||
self.body.append(res)
|
||||
|
||||
|
||||
def depart_mc_node(self,node):
|
||||
res = node.template_form_start % node.mc_options
|
||||
feedbackStr = "["
|
||||
currFeedback = ""
|
||||
# Add all of the possible answers
|
||||
okeys = node.mc_options.keys()
|
||||
okeys.sort()
|
||||
for k in okeys:
|
||||
if 'answer_' in k:
|
||||
x,label = k.split('_')
|
||||
node.mc_options['alabel'] = label
|
||||
node.mc_options['atext'] = node.mc_options[k]
|
||||
res += node.template_option % node.mc_options
|
||||
currFeedback = "feedback_" + label
|
||||
feedbackStr = feedbackStr + "'" + escapejs(node.mc_options[currFeedback]) + "', "
|
||||
|
||||
# store the feedback array with key feedback minus last comma
|
||||
node.mc_options['feedback'] = feedbackStr[0:-2] + "]"
|
||||
|
||||
res += node.template_end % node.mc_options
|
||||
|
||||
self.body.append(res)
|
||||
|
||||
|
||||
|
||||
|
||||
#####################
|
||||
# multiple choice question with multiple feedback
|
||||
# author - Barb Ericson
|
||||
# author - Anusha
|
||||
class MChoiceMF(Assessment):
|
||||
required_arguments = 1
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
has_content = True
|
||||
option_spec = {'answer_a':directives.unchanged,
|
||||
'answer_b':directives.unchanged,
|
||||
'answer_c':directives.unchanged,
|
||||
'answer_d':directives.unchanged,
|
||||
'answer_e':directives.unchanged,
|
||||
'correct':directives.unchanged,
|
||||
'feedback_a':directives.unchanged,
|
||||
'feedback_b':directives.unchanged,
|
||||
'feedback_c':directives.unchanged,
|
||||
'feedback_d':directives.unchanged,
|
||||
'feedback_e':directives.unchanged,
|
||||
'iscode':directives.flag
|
||||
}
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
process the multiplechoice directive and generate html for output.
|
||||
:param self:
|
||||
:return:
|
||||
.. mcmfstorage:: qname
|
||||
:iscode: boolean
|
||||
:answer_a: possible answer -- what follows _ is label
|
||||
:answer_b: possible answer
|
||||
...
|
||||
:answer_e: possible answer
|
||||
:correct: leter of correct answer
|
||||
:feedback_a: displayed if a is picked
|
||||
:feedback_b: displayed if b is picked
|
||||
:feedback_c: displayed if c is picked
|
||||
:feedback_d: displayed if d is picked
|
||||
:feedback_e: displayed if e is picked
|
||||
|
||||
Question text
|
||||
...
|
||||
"""
|
||||
TEMPLATE_START = '''
|
||||
<div id="%(divid)s" class="alert alert-warning">
|
||||
'''
|
||||
|
||||
OPTION = '''
|
||||
<input type="radio" name="group1" value="%(alabel)s" id="%(divid)s_opt_%(alabel)s" />
|
||||
<label for= "%(divid)s_opt_%(alabel)s"> %(alabel)s) %(atext)s</label><br />
|
||||
'''
|
||||
|
||||
TEMPLATE_END = '''
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){checkRadio('%(divid)s');});
|
||||
</script>
|
||||
<button class='btn btn-success' name="do answer" onclick="checkMCMFStorage('%(divid)s','%(correct)s',%(feedback)s)">Check Me</button>
|
||||
<button class='btn btn-default' id="%(divid)s_bcomp" disabled name="compare" onclick="compareAnswers('%(divid)s');">Compare Me</button>
|
||||
</form><br />
|
||||
<div id="%(divid)s_feedback">
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
super(MChoiceMF,self).run()
|
||||
|
||||
|
||||
|
||||
|
||||
mcNode = MChoiceNode(self.options)
|
||||
mcNode.template_start = TEMPLATE_START
|
||||
mcNode.template_form_start = '''<form name="%(divid)s_form" method="get" action="" onsubmit="return false;">'''
|
||||
mcNode.template_option = OPTION
|
||||
mcNode.template_end = TEMPLATE_END
|
||||
|
||||
self.state.nested_parse(self.content, self.content_offset, mcNode)
|
||||
|
||||
return [mcNode]
|
||||
|
||||
|
||||
#####################
|
||||
# multiple choice question with multiple correct answers
|
||||
# author - Barb Ericson
|
||||
|
||||
class MChoiceMA(Assessment):
|
||||
required_arguments = 1
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
has_content = True
|
||||
option_spec = {'answer_a':directives.unchanged,
|
||||
'answer_b':directives.unchanged,
|
||||
'answer_c':directives.unchanged,
|
||||
'answer_d':directives.unchanged,
|
||||
'answer_e':directives.unchanged,
|
||||
'correct':directives.unchanged,
|
||||
'feedback_a':directives.unchanged,
|
||||
'feedback_b':directives.unchanged,
|
||||
'feedback_c':directives.unchanged,
|
||||
'feedback_d':directives.unchanged,
|
||||
'feedback_e':directives.unchanged,
|
||||
'iscode':directives.flag
|
||||
}
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
process the multiplechoice directive and generate html for output.
|
||||
:param self:
|
||||
:return:
|
||||
.. mchoicemf:: qname
|
||||
:iscode: boolean
|
||||
:answer_a: possible answer -- what follows _ is label
|
||||
:answer_b: possible answer
|
||||
...
|
||||
:answer_e: possible answer
|
||||
:correct: comma seperated list of correct values a, b, c
|
||||
:feedback_a: displayed if a is picked
|
||||
:feedback_b: displayed if b is picked
|
||||
:feedback_c: displayed if c is picked
|
||||
:feedback_d: displayed if d is picked
|
||||
:feedback_e: displayed if e is picked
|
||||
|
||||
Question text
|
||||
...
|
||||
"""
|
||||
TEMPLATE_START = '''
|
||||
<div id="%(divid)s" class="alert alert-warning">
|
||||
'''
|
||||
|
||||
OPTION = '''
|
||||
<input type="checkbox" name="group1" value="%(alabel)s" id="%(divid)s_opt_%(alabel)s" />
|
||||
<label for= "%(divid)s_opt_%(alabel)s"> %(alabel)s) %(atext)s</label><br />
|
||||
'''
|
||||
|
||||
TEMPLATE_END = '''
|
||||
<script>
|
||||
$(document).ready(function(){checkMultipleSelect('%(divid)s');});
|
||||
</script>
|
||||
<button class='btn btn-success' name="do answer" onclick="checkMCMAStorage('%(divid)s','%(correct)s',%(feedback)s)">Check Me</button>
|
||||
<button class='btn btn-default' id="%(divid)s_bcomp" disabled name="compare" onclick="compareAnswers('%(divid)s');">Compare Me</button>
|
||||
</form><br />
|
||||
<div id="%(divid)s_feedback">
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
|
||||
|
||||
super(MChoiceMA,self).run()
|
||||
|
||||
mcNode = MChoiceNode(self.options)
|
||||
mcNode.template_start = TEMPLATE_START
|
||||
mcNode.template_form_start = '''<form name="%(divid)s_form" method="get" action="" onsubmit="return false;">'''
|
||||
mcNode.template_option = OPTION
|
||||
mcNode.template_end = TEMPLATE_END
|
||||
|
||||
self.state.nested_parse(self.content, self.content_offset, mcNode)
|
||||
|
||||
return [mcNode]
|
||||
|
||||
|
||||
|
||||
################################
|
||||
|
||||
|
||||
#####################
|
||||
# display a multiple choice question with feedback that randomizes the answers
|
||||
class MChoiceRandomMF(Assessment):
|
||||
required_arguments = 1
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
has_content = True
|
||||
option_spec = {'answer_a':directives.unchanged,
|
||||
'answer_b':directives.unchanged,
|
||||
'answer_c':directives.unchanged,
|
||||
'answer_d':directives.unchanged,
|
||||
'answer_e':directives.unchanged,
|
||||
'correct':directives.unchanged,
|
||||
'feedback_a':directives.unchanged,
|
||||
'feedback_b':directives.unchanged,
|
||||
'feedback_c':directives.unchanged,
|
||||
'feedback_d':directives.unchanged,
|
||||
'feedback_e':directives.unchanged,
|
||||
'iscode':directives.flag
|
||||
}
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
process the multiplechoice directive and generate html for output.
|
||||
:param self:
|
||||
:return:
|
||||
.. mcmfrandom:: qname
|
||||
:iscode: boolean
|
||||
:answer_a: possible answer -- what follows _ is label
|
||||
:answer_b: possible answer
|
||||
...
|
||||
:answer_e: possible answer
|
||||
:correct: leter of correct answer
|
||||
:feedback_a: displayed if a is picked
|
||||
:feedback_b: displayed if b is picked
|
||||
:feedback_c: displayed if c is picked
|
||||
:feedback_d: displayed if d is picked
|
||||
:feedback_e: displayed if e is picked
|
||||
|
||||
Question text
|
||||
...
|
||||
"""
|
||||
TEMPLATE_START = '''
|
||||
<div id="%(divid)s" class="alert alert-warning">
|
||||
<p>%(qnumber)s: %(bodytext)s</p>
|
||||
<form name="%(divid)s_form" method="get" action="" onsubmit="return true;">
|
||||
'''
|
||||
|
||||
OPTION = '''
|
||||
<div id="%(divid)s_op%(opi)s"></div>
|
||||
'''
|
||||
|
||||
TEMPLATE_END = '''
|
||||
<div id="%(divid)s_bt"></div>
|
||||
|
||||
</form>
|
||||
<div id="%(divid)s_feedback">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){createHTML_MCMFRandom("%(divid)s","%(a)s","%(f)s","%(corr)s");});
|
||||
</script>
|
||||
</div>
|
||||
'''
|
||||
|
||||
|
||||
super(MChoiceRandomMF,self).run()
|
||||
|
||||
res = ""
|
||||
res = TEMPLATE_START % self.options
|
||||
feedbackStr = "["
|
||||
currFeedback = ""
|
||||
# Add all of the possible answers
|
||||
okeys = self.options.keys()
|
||||
okeys.sort()
|
||||
|
||||
|
||||
answ=""
|
||||
feed=""
|
||||
ansArr=[]
|
||||
feedArray=[]
|
||||
for k in okeys:
|
||||
if 'answer_' in k:
|
||||
ansArr.append(k)
|
||||
for f in ansArr:
|
||||
t,flabel=f.split("_")
|
||||
feedArray.append(flabel)
|
||||
|
||||
i=0
|
||||
for k in okeys:
|
||||
if 'answer_' in k:
|
||||
answ=answ+self.options[ansArr[i]]+"*separator*"
|
||||
feed=feed+self.options["feedback_"+feedArray[i]]+"*separator*"
|
||||
self.options['opi']=i+1
|
||||
res += OPTION % self.options
|
||||
i=i+1
|
||||
|
||||
# Store the Answer and Feedback arrays
|
||||
self.options['a']=answ
|
||||
self.options['f']=feed
|
||||
|
||||
op=self.options['correct']
|
||||
|
||||
if(op=='a'):
|
||||
index=0
|
||||
elif(op=='b'):
|
||||
index=1
|
||||
elif(op=='c'):
|
||||
index=2
|
||||
elif(op=='d'):
|
||||
index=3
|
||||
elif(op=='e'):
|
||||
index=4
|
||||
self.options['corr']=self.options[ansArr[index]]
|
||||
|
||||
res += TEMPLATE_END % self.options
|
||||
return [nodes.raw('',res , format='html')]
|
||||
53
book/modules/luther/sphinx/assess/prototype.html
Normal file
53
book/modules/luther/sphinx/assess/prototype.html
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>trial</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript" ></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="prototype">
|
||||
<p>Evaluate the following boolean expression: True or False</p>
|
||||
<form name="prototype_form" method="get" action="" onsubmit="return false;">
|
||||
<input type="radio" name="group1" value="a" id="prototype_opt_1" />
|
||||
<label for= "prototype_opt_1"> a) True</label><br />
|
||||
<input type="radio" name="group1" value="b" id="prototype_opt_2" />
|
||||
<label for="prototype_opt_2"> b) False</label><br />
|
||||
<input type="radio" name="group1" value="c" id="prototype_opt_3">
|
||||
<label for="prototype_opt_3"> c) Unknown</label><br />
|
||||
|
||||
<input type="button" name="do answer"
|
||||
value="Check Me" onclick="checkMe('prototype','a','try again')"/>
|
||||
</form>
|
||||
<div id="prototype_feedback">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript"> // can go in assessfuncs??
|
||||
var checkMe = function(divid, expected,feedback) {
|
||||
var given;
|
||||
var buttonObjs = document.forms[divid+"_form"].elements['group1']
|
||||
for (var i = buttonObjs.length - 1; i >= 0; i--) {
|
||||
if (buttonObjs[i].checked) {
|
||||
given = buttonObjs[i].value;
|
||||
}
|
||||
};
|
||||
// update number of trials??
|
||||
// log this to the db
|
||||
feedBack('#'+divid+'_feedback',given == expected, feedback)
|
||||
}
|
||||
var feedBack = function(divid,correct,feedbackText) {
|
||||
if (correct) {
|
||||
$(divid).html('You are Correct!');
|
||||
} else {
|
||||
$(divid).html("Inorrect. Here's something to think about: " + feedbackText );
|
||||
}
|
||||
}
|
||||
|
||||
// for each form in the div
|
||||
// get the id of the form
|
||||
// call checkMe on the form... -- need metadata what kind of question what parms etc
|
||||
// hidden fields for meta data??? each form defines a checkme function with no parameters
|
||||
// that calls the actual function that checks the answer properly??
|
||||
// summarize
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
65
book/modules/luther/sphinx/assess/textfield.py
Normal file
65
book/modules/luther/sphinx/assess/textfield.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# Copyright (C) 2011 Bradley N. Miller
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__author__ = 'bmiller'
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst import Directive
|
||||
import json
|
||||
import random
|
||||
|
||||
# setup is called in assess.py
|
||||
|
||||
# app.add_node(MChoiceNode, html=(visit_mc_node, depart_mc_node))
|
||||
# app.add_node(FITBNode, html=(visit_fitb_node, depart_fitb_node))
|
||||
|
||||
|
||||
|
||||
def textfield_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
'''
|
||||
Usage:
|
||||
|
||||
In your document you can write :textfield:`myid:myvalue:width`
|
||||
|
||||
This will translate to:
|
||||
<input type='text' id='myid' class="form-control input-small" style="display:inline; width:width;" value='myvalue'></input>
|
||||
|
||||
where width can be specified in pixels or percentage of page width (standard CSS syntax).
|
||||
Width can also be specified using relative sizes:
|
||||
mini, small, medium, large, xlarge, and xxlarge
|
||||
|
||||
|
||||
|
||||
'''
|
||||
iid, value, width = text.split(':')
|
||||
|
||||
if 'mini' in width:
|
||||
width = '60px'
|
||||
elif 'small' in width:
|
||||
width = '90px'
|
||||
elif 'medium' in width:
|
||||
width = '150px'
|
||||
elif 'large' in width:
|
||||
width = '210px'
|
||||
elif 'xlarge' in width:
|
||||
width = '270px'
|
||||
elif 'xxlarge' in width:
|
||||
width = '530px'
|
||||
|
||||
res = '''<input type='text' id='%s' class="form-control" style="display:inline; width: %s;" value="%s"></input>''' % (iid,width,value)
|
||||
|
||||
return [nodes.raw('',res, format='html')],[]
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue