Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit e24e7b8

Browse files
committed
Add shortanswer directive
renaming of journal from acbart
1 parent 407d1f6 commit e24e7b8

File tree

5 files changed

+160
-1
lines changed

5 files changed

+160
-1
lines changed

CONTRIBUTING.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,7 @@ Provide an example
2626
------------------
2727

2828
The folder ``runestone/common/project_template/_sources`` folder is a great place to add a file
29-
that demonstrates your new feature or component in action.
29+
that demonstrates your new feature or component in action.
30+
31+
In fact you should provide two examples whenever possible to demonstrate that you can have
32+
multiple instances of your component on a single web page.

runestone/shortanswer/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .shortanswer import *

runestone/shortanswer/css/shortanswer.css

Whitespace-only changes.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
3+
/**
4+
* If the divid is in the localStorage, then assume it was put there in a panic
5+
* Check against the server to find which is more recent, and use that.
6+
*
7+
*/
8+
function loadJournal(directive_id) {
9+
directiveRemoteCommand('get_journal_entry', directive_id, {},
10+
function(data) {
11+
var solution = $('#'+directive_id+'_solution');
12+
solution.text(data.solution);
13+
if (storage.has(directive_id)) {
14+
if (storage.is_new(directive_id, data.timestamp)) {
15+
storage.remove(directive_id);
16+
} else {
17+
solution.text(storage.get(directive_id));
18+
submitJournal(directive_id);
19+
}
20+
}
21+
},
22+
function(data) {
23+
console.log(data.message);
24+
});
25+
}
26+
27+
function submitJournal(directive_id) {
28+
var value = $('#'+directive_id+'_solution').val();
29+
storage.set(directive_id, value);
30+
directiveRemoteCommand('set_journal_entry', directive_id, {'solution': value},
31+
function(data) {
32+
storage.remove(directive_id);
33+
},
34+
function(data) {
35+
console.log(data.message);
36+
});
37+
}
38+
39+
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Copyright (C) 2011 Bradley N. Miller
2+
#
3+
# This program is free software: you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation, either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
#
16+
__author__ = 'acbart'
17+
18+
import os
19+
20+
from docutils import nodes
21+
from docutils.parsers.rst import directives
22+
from docutils.parsers.rst import Directive
23+
from runestone.assess import Assessment
24+
25+
def setup(app):
26+
app.add_directive('shortanswer', JournalDirective)
27+
28+
app.add_node(JournalNode, html=(visit_journal_node, depart_journal_node))
29+
30+
app.add_javascript('shortanswer.js')
31+
app.add_stylesheet('shortanswer.css')
32+
33+
34+
TEXT = """
35+
<div id='%(divid)s' class='journal alert alert-%(optional)s'>
36+
<form id='%(divid)s_journal' name='%(divid)s_journal' action="">
37+
<div class='directive-status-icon'><img src='../../images/spinner10.gif'/></div>
38+
<fieldset>
39+
<legend>Journal</legend>
40+
<div class='journal-question'>%(qnum)s: %(content)s</div>
41+
<div id='%(divid)s_journal_input'>
42+
<div class='journal-options'>
43+
<label class='radio-inline'>
44+
<textarea id='%(divid)s_solution' class="form-control" style="display:inline; width: 530px;"
45+
rows='4' cols='50'></textarea>
46+
</label>
47+
</div><br />
48+
Instructor's Feedback:
49+
<div class='journal-options' style='padding-left:20px'>
50+
<div class='bg-info form-control' style='width:530px; background-color: #eee; font-style:italic'
51+
id='%(divid)s_feedback'>
52+
There is no feedback yet.
53+
</div>
54+
</div><br />
55+
</div>
56+
</fieldset>
57+
</form>
58+
<div id='%(divid)s_results'></div>
59+
<script type='text/javascript'>
60+
// check if the user has already answered this journal
61+
$(function() {
62+
loadJournal('%(divid)s');
63+
$('#%(divid)s_solution').on('keyup input propertychange paste change', function() {
64+
addDelay('%(divid)s', function() {
65+
submitJournal('%(divid)s');
66+
});
67+
});
68+
});
69+
</script>
70+
</div>
71+
"""
72+
73+
class JournalNode(nodes.General, nodes.Element):
74+
def __init__(self, options):
75+
super(JournalNode, self).__init__()
76+
self.journalnode_components = options
77+
78+
def visit_journal_node(self, node):
79+
div_id = node.journalnode_components['divid']
80+
back, subchapter = os.path.split(os.path.splitext(node.source.lower())[0])
81+
back, chapter = os.path.split(back)
82+
content = ''
83+
components = dict(node.journalnode_components)
84+
components.update({'divid': div_id,
85+
'subchapter': subchapter,
86+
'chapter': chapter})
87+
res = TEXT % components
88+
self.body.append(res)
89+
90+
def depart_journal_node(self,node):
91+
pass
92+
93+
94+
class JournalDirective(Assessment):
95+
required_arguments = 1 # the div id
96+
optional_arguments = 0
97+
final_argument_whitespace = True
98+
has_content = True
99+
option_spec = {'optional': directives.flag}
100+
101+
node_class = JournalNode
102+
103+
def run(self):
104+
# Raise an error if the directive does not have contents.
105+
106+
self.assert_has_content()
107+
108+
self.options['optional'] = 'success' if 'optional' in self.options else 'warning'
109+
self.options['divid'] = self.arguments[0]
110+
self.options['content'] = "<p>".join(self.content)
111+
self.options['qnum'] = self.getNumber()
112+
journal_node = JournalNode(self.options)
113+
114+
return [journal_node]
115+
116+

0 commit comments

Comments
 (0)