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

Commit e613262

Browse files
committed
merge
2 parents 04beda5 + 9496bc9 commit e613262

File tree

3 files changed

+208
-69
lines changed

3 files changed

+208
-69
lines changed

runestone/shortanswer/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<h2>Short Answer</h2>
2+
3+
```html
4+
<p data-component="shortanswer" data-optional id="example1">What is the best thing about the color blue?</p>
5+
```
6+
7+
The <code>p</code> tag represents the entire Short Answer component to be rendered.
8+
(more info about the use)
9+
10+
11+
Option spec:
12+
13+
<ul>
14+
<li><code>data-component="shortanswer"</code> Identifies this as a Short Answer component</li>
15+
<li><code>id</code> Must be unique in the document</li>
16+
<li><code>data-optional</code> Makes this component optional for the student to answer--it isn't required.</li>
17+
</ul>

runestone/shortanswer/js/shortanswer.js

100755100644
Lines changed: 184 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,201 @@
1+
/*==========================================
2+
======= Master shortanswer.js ========
3+
============================================
4+
=== This file contains the JS for ===
5+
=== the Runestone shortanswer component. ===
6+
============================================
7+
=== Created by ===
8+
=== Isaiah Mayerchak ===
9+
=== 7/2/15 ===
10+
==========================================*/
111

12+
var saList = {}; // Dictionary that contains all instances of shortanswer objects
213

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-
if (storage.has(directive_id)) {
10-
var solution = $('#' + directive_id + '_solution');
11-
solution.text(storage.get(directive_id));
14+
15+
function ShortAnswer (opts) {
16+
if (opts) {
17+
this.init(opts);
1218
}
19+
}
1320

14-
/*directiveRemoteCommand('get_journal_entry', directive_id, {},
15-
function(data) {
16-
var solution = $('#'+directive_id+'_solution');
17-
solution.text(data.solution);
18-
if (storage.has(directive_id)) {
19-
if (storage.is_new(directive_id, data.timestamp)) {
20-
storage.remove(directive_id);
21+
ShortAnswer.prototype = new RunestoneBase();
22+
23+
/*========================================
24+
== Initialize basic ShortAnswer attributes ==
25+
========================================*/
26+
ShortAnswer.prototype.init = function (opts) {
27+
RunestoneBase.apply(this, arguments);
28+
var orig = opts.orig; // entire <p> element that will be replaced by new HTML
29+
this.origElem = orig;
30+
this.divid = orig.id;
31+
this.question = this.origElem.innerHTML;
32+
33+
this.optional = false;
34+
if ($(this.origElem).is("[data-optional]")) {
35+
this.optional = true;
36+
}
37+
38+
this.renderHTML();
39+
this.loadJournal();
40+
};
41+
42+
ShortAnswer.prototype.renderHTML = function() {
43+
this.containerDiv = document.createElement("div");
44+
this.containerDiv.id = this.divid;
45+
if (this.optional) {
46+
$(this.containerDiv).addClass("journal alert alert-success");
2147
} else {
22-
solution.text(storage.get(directive_id));
23-
submitJournal(directive_id);
48+
$(this.containerDiv).addClass("journal alert alert-warning");
2449
}
25-
}
26-
},
27-
function(data) {
28-
console.log(data.message);
29-
}); */
30-
}
3150

32-
function submitJournal(directive_id) {
33-
var value = $('#'+directive_id+'_solution').val();
34-
storage.set(directive_id, value);
51+
this.newForm = document.createElement("form");
52+
this.newForm.id = this.divid + "_journal";
53+
this.newForm.name = this.newForm.id;
54+
this.newForm.action = "";
55+
this.containerDiv.appendChild(this.newForm);
56+
57+
this.fieldSet = document.createElement("fieldset");
58+
this.newForm.appendChild(this.fieldSet);
59+
60+
this.legend = document.createElement("legend");
61+
this.legend.innerHTML = "Short Answer";
62+
this.fieldSet.appendChild(this.legend);
63+
64+
this.firstLegendDiv = document.createElement("div");
65+
this.firstLegendDiv.innerHTML = this.question;
66+
$(this.firstLegendDiv).addClass("journal-question");
67+
this.fieldSet.appendChild(this.firstLegendDiv);
68+
69+
this.jInputDiv = document.createElement("div");
70+
this.jInputDiv.id = this.divid + "_journal_input";
71+
this.fieldSet.appendChild(this.jInputDiv);
72+
73+
this.jOptionsDiv = document.createElement("div");
74+
$(this.jOptionsDiv).addClass("journal-options");
75+
this.jInputDiv.appendChild(this.jOptionsDiv);
76+
77+
this.jLabel = document.createElement("label");
78+
$(this.jLabel).addClass("radio-inline");
79+
this.jOptionsDiv.appendChild(this.jLabel);
80+
81+
this.jTextArea = document.createElement("textarea");
82+
this.jTextArea.id = this.divid + "_solution";
83+
$(this.jTextArea).css("display:inline, width:530px");
84+
$(this.jTextArea).addClass("form-control");
85+
this.jTextArea.rows = 4;
86+
this.jTextArea.cols = 50;
87+
this.jLabel.appendChild(this.jTextArea);
88+
89+
this.fieldSet.appendChild(document.createElement("br"));
90+
91+
this.buttonDiv = document.createElement("div");
92+
this.fieldSet.appendChild(this.buttonDiv);
93+
94+
this.submitButton = document.createElement("button");
95+
$(this.submitButton).addClass("btn btn-default");
96+
this.submitButton.textContent = "Save";
97+
this.submitButton.onclick = function () {
98+
this.submitJournal();
99+
}.bind(this);
100+
this.buttonDiv.appendChild(this.submitButton);
101+
102+
this.randomSpan = document.createElement("span");
103+
this.randomSpan.innerHTML = "Instructor's Feedback";
104+
this.fieldSet.appendChild(this.randomSpan);
105+
106+
this.otherOptionsDiv = document.createElement("div");
107+
$(this.otherOptionsDiv).css("padding-left:20px");
108+
$(this.otherOptionsDiv).addClass("journal-options");
109+
this.fieldSet.appendChild(this.otherOptionsDiv);
110+
111+
this.feedbackDiv = document.createElement("div");
112+
$(this.feedbackDiv).addClass("bg-info form-control");
113+
$(this.feedbackDiv).css("width:530px, background-color:#eee, font-style:italic");
114+
this.feedbackDiv.id = this.divid + "_feedback";
115+
this.feedbackDiv.innerHTML = "There is no feedback yet.";
116+
this.otherOptionsDiv.appendChild(this.feedbackDiv);
117+
118+
this.fieldSet.appendChild(document.createElement("br"));
119+
120+
$(this.origElem).replaceWith(this.containerDiv);
121+
};
122+
123+
ShortAnswer.prototype.submitJournal = function () {
124+
var value = $("#"+this.divid+"_solution").val();
125+
localStorage.setItem(this.divid, value);
35126
/*
36-
directiveRemoteCommand('set_journal_entry', directive_id, {'solution': value},
127+
directiveRemoteCommand("set_journal_entry", this.divid, {"solution": value},
37128
function(data) {
38-
storage.remove(directive_id);
129+
storage.remove(this.divid);
39130
},
40131
function(data) {
41132
console.log(data.message);
42133
}); */
43134
this.logBookEvent({'event': 'shortanswer', 'act': JSON.stringify(value), 'div_id': directive_id});
135+
};
136+
137+
ShortAnswer.prototype.loadJournal = function () {
138+
var len = localStorage.length;
139+
if (len > 0) {
140+
var ex = localStorage.getItem(this.divid);
141+
if (ex !== null) {
142+
var solution = $("#" + this.divid + "_solution");
143+
solution.text(localStorage.getItem(this.divid));
144+
}
44145
}
146+
};
147+
148+
/*
149+
150+
<div id='%(divid)s' class='journal alert alert-%(optional)s'>
151+
<form id='%(divid)s_journal' name='%(divid)s_journal' action="">
152+
<fieldset>
153+
<legend>Short Answer</legend>
154+
<div class='journal-question'>%(qnum)s: %(content)s</div>
155+
<div id='%(divid)s_journal_input'>
156+
<div class='journal-options'>
157+
<label class='radio-inline'>
158+
<textarea id='%(divid)s_solution' class="form-control" style="display:inline; width: 530px;"
159+
rows='4' cols='50'></textarea>
160+
</label>
161+
</div><br />
162+
<div><button class="btn btn-default" onclick="submitJournal('%(divid)s');">Save</button></div>
163+
Instructor's Feedback:
164+
<div class='journal-options' style='padding-left:20px'>
165+
<div class='bg-info form-control' style='width:530px; background-color: #eee; font-style:italic'
166+
id='%(divid)s_feedback'>
167+
There is no feedback yet.
168+
</div>
169+
</div><br />
170+
</div>
171+
</fieldset>
172+
</form>
173+
<div id='%(divid)s_results'></div>
174+
<script type='text/javascript'>
175+
// check if the user has already answered this journal
176+
$(function() {
177+
loadJournal('%(divid)s');
178+
});
179+
</script>
180+
</div>
181+
182+
183+
184+
*/
185+
186+
187+
188+
189+
190+
45191

192+
/*=================================
193+
== Find the custom HTML tags and ==
194+
== execute our code on them ==
195+
=================================*/
196+
$(document).ready(function () {
197+
$("[data-component=shortanswer]").each(function (index) {
198+
saList[this.id] = new ShortAnswer({"orig": this});
199+
});
46200

201+
});

runestone/shortanswer/shortanswer.py

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
# You should have received a copy of the GNU General Public License
1414
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
#
16-
__author__ = 'acbart'
17-
16+
__author__ = 'isaiahmayerchak'
17+
#acbart did most of this code, I mostly just changed the template
1818
import os
1919

2020
from docutils import nodes
@@ -28,41 +28,10 @@ def setup(app):
2828
app.add_node(JournalNode, html=(visit_journal_node, depart_journal_node))
2929

3030
app.add_javascript('shortanswer.js')
31-
app.add_stylesheet('shortanswer.css')
3231

3332

3433
TEXT = """
35-
<div id='%(divid)s' class='journal alert alert-%(optional)s'>
36-
<form id='%(divid)s_journal' name='%(divid)s_journal' action="">
37-
<fieldset>
38-
<legend>Short Answer</legend>
39-
<div class='journal-question'>%(qnum)s: %(content)s</div>
40-
<div id='%(divid)s_journal_input'>
41-
<div class='journal-options'>
42-
<label class='radio-inline'>
43-
<textarea id='%(divid)s_solution' class="form-control" style="display:inline; width: 530px;"
44-
rows='4' cols='50'></textarea>
45-
</label>
46-
</div><br />
47-
<div><button class="btn btn-default" onclick="submitJournal('%(divid)s');">Save</button></div>
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-
});
64-
</script>
65-
</div>
34+
<p data-component="shortanswer" id=%(divid)s %(optional)s>%(qnum)s: %(content)s</p>
6635
"""
6736

6837
class JournalNode(nodes.General, nodes.Element):
@@ -96,16 +65,14 @@ class JournalDirective(Assessment):
9665
node_class = JournalNode
9766

9867
def run(self):
99-
# Raise an error if the directive does not have contents.
100-
68+
# Raise an error if the directive does not have contents.
69+
10170
self.assert_has_content()
102-
103-
self.options['optional'] = 'success' if 'optional' in self.options else 'warning'
71+
72+
self.options['optional'] = 'data-optional' if 'optional' in self.options else ''
10473
self.options['divid'] = self.arguments[0]
10574
self.options['content'] = "<p>".join(self.content)
10675
self.options['qnum'] = self.getNumber()
10776
journal_node = JournalNode(self.options)
10877

10978
return [journal_node]
110-
111-

0 commit comments

Comments
 (0)