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

Commit 7c76ac3

Browse files
committed
Merge branch 'async_work'
# Conflicts: # runestone/common/js/runestonebase.js
2 parents e93d9ae + d2cd614 commit 7c76ac3

7 files changed

Lines changed: 15840 additions & 6945 deletions

File tree

package-lock.json

Lines changed: 15740 additions & 6801 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runestone/activecode/js/activecode.js

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ export class ActiveCode extends RunestoneBase {
111111
this.caption = "ActiveCode";
112112
}
113113
this.addCaption("runestone");
114+
setTimeout(
115+
function () {
116+
this.editor.refresh();
117+
}.bind(this),
118+
1000
119+
);
114120
if (this.autorun) {
115121
$(document).ready(this.runProg.bind(this));
116122
}
@@ -735,60 +741,6 @@ export class ActiveCode extends RunestoneBase {
735741
}
736742
}
737743

738-
async loadEditor() {
739-
var data = {
740-
acid: this.divid,
741-
};
742-
if (this.sid !== undefined) {
743-
data["sid"] = this.sid;
744-
}
745-
746-
let request = new Request(eBookConfig.ajaxURL + "getprog", {
747-
method: "POST",
748-
headers: this.jsonHeaders,
749-
body: JSON.stringify(data),
750-
});
751-
let response = await fetch(request);
752-
let res = await response.json();
753-
754-
if (res.source) {
755-
this.editor.setValue(res.source);
756-
setTimeout(
757-
function () {
758-
this.editor.refresh();
759-
}.bind(this),
760-
500
761-
);
762-
$(this.loadButton).tooltip({
763-
placement: "bottom",
764-
title: $.i18n("msg_activecode_loaded_code"),
765-
trigger: "manual",
766-
});
767-
} else {
768-
$(this.loadButton).tooltip({
769-
placement: "bottom",
770-
title: $.i18n("msg_activecode_no_saved_code"),
771-
trigger: "manual",
772-
});
773-
}
774-
775-
this.logBookEvent({
776-
event: "activecode",
777-
act: "load",
778-
div_id: this.divid,
779-
}); // Log the run event
780-
781-
$(this.loadButton).tooltip("show");
782-
setTimeout(
783-
function () {
784-
$(this.loadButton).tooltip("destroy");
785-
}.bind(this),
786-
4000
787-
);
788-
789-
return response;
790-
}
791-
792744
async createGradeSummary() {
793745
// get grade and comments for this assignment
794746
// get summary of all grades for this student

runestone/activecode/test/test_activecode.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def test_hello(self):
3030
rb = t1.find_element_by_class_name("run-button")
3131
self.assertIsNotNone(rb)
3232
rb.click()
33+
time.sleep(0.5)
3334
output = t1.find_element_by_class_name("ac_output")
3435
self.assertEqual(output.text.strip(), "Hello World")
3536

@@ -53,6 +54,7 @@ def test_hidden(self):
5354
rb = t1.find_element_by_class_name("run-button")
5455
self.assertIsNotNone(rb)
5556
rb.click()
57+
time.sleep(0.5)
5658
output = t1.find_element_by_class_name("ac_output")
5759
self.assertIn("My Code", output.text.strip())
5860
self.assertIn("hidden code", output.text.strip())
@@ -82,9 +84,9 @@ def test_history(self):
8284
# """,
8385
# interceptor,
8486
# )
85-
window.scrollTo(0, 0);
87+
self.driver.execute_script("window.scrollTo(0, 0);")
8688
rb.click()
87-
89+
8890
ta = t1.find_element_by_class_name("cm-s-default")
8991
self.assertIsNotNone(ta)
9092
self.driver.execute_script(
@@ -171,6 +173,7 @@ def test_sql_activecode(self):
171173
rb = t2.find_element_by_class_name("run-button")
172174
self.assertIsNotNone(rb)
173175
rb.click()
176+
time.sleep(0.5)
174177
res = self.driver.find_element_by_id("sql1_sql_out")
175178
self.assertIsNotNone(res)
176179
out = self.driver.find_element_by_id("sql1_stdout")
@@ -205,8 +208,9 @@ def test_altair(self):
205208
rb.click()
206209
out = t2.find_element_by_id("alt_kiva_bar1_stdout")
207210
self.assertIsNotNone(out)
208-
self.assertTrue("mark = bar" in out.text)
209-
self.assertTrue("{'field': 'customer', 'type': 'nominal'}" in out.text)
211+
time.sleep(.5)
212+
self.assertIn("mark = bar", out.text)
213+
self.assertIn("{'field': 'customer', 'type': 'nominal'}", out.text)
210214
can = t2.find_element_by_tag_name("canvas")
211215
self.assertIsNotNone(can)
212216

@@ -219,8 +223,9 @@ def test_image(self):
219223
rb.click()
220224
out = t2.find_element_by_id("ac14_7_2_stdout")
221225
self.assertIsNotNone(out)
226+
time.sleep(1)
222227
self.assertTrue("400" in out.text)
223228
self.assertTrue("244" in out.text)
224-
self.assertTrue("165 161 158" in out.text)
229+
self.assertTrue(("165 161 158" in out.text) or ("165 162 157" in out.text))
225230
can = t2.find_element_by_tag_name("canvas")
226231
self.assertIsNotNone(can)

runestone/common/js/runestonebase.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export default class RunestoneBase {
151151
);
152152
try {
153153
let response = await fetch(request);
154-
let data = await response.json();
154+
data = await response.json();
155155
this.repopulateFromStorage(data);
156156
} catch (err) {
157157
try {
@@ -167,6 +167,7 @@ export default class RunestoneBase {
167167
this.checkLocalStorage(); // just go right to local storage
168168
}
169169
}
170+
170171
loadData(data) {
171172
// for most classes, loadData doesn't do anything. But for Parsons, and perhaps others in the future,
172173
// initialization can happen even when there's no history to be loaded

runestone/selectquestion/js/selectone.js

Lines changed: 45 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default class SelectOne extends RunestoneBase {
3737
this.not_seen_ever = $(opts.orig).data("not_seen_ever");
3838
this.selector_id = $(opts.orig).first().attr("id");
3939
this.primaryOnly = $(opts.orig).data("primary");
40+
this.ABExperiment = $(opts.orig).data("ab");
4041
opts.orig.id = this.selector_id;
4142
}
4243
/**
@@ -72,59 +73,52 @@ export default class SelectOne extends RunestoneBase {
7273
if (this.primaryOnly) {
7374
data.primary = this.primaryOnly;
7475
}
76+
if (this.ABExperiment) {
77+
data.AB = this.ABExperiment;
78+
}
7579
let opts = this.origOpts;
7680
let selectorId = this.selector_id;
77-
let myPromise = new Promise(
78-
function (resolve, reject) {
79-
$.getJSON(
80-
"/runestone/ajax/get_question_source",
81-
data,
82-
function (htmlsrc) {
83-
if (htmlsrc.indexOf("No preview") >= 0) {
84-
alert(
85-
`Error: Not able to find a question for ${selectorId} based on the criteria`
86-
);
87-
resolve("done");
88-
return;
89-
}
90-
let res;
91-
if (opts.timed) {
92-
// timed components are not rendered immediately, only when the student
93-
// starts the assessment and visits this particular entry.
94-
res = createTimedComponent(htmlsrc, {
95-
timed: true,
96-
selector_id: selectorId,
97-
assessmentTaken: opts.assessmentTaken,
98-
});
99-
// replace the entry in the timed assessment's list of components
100-
// with the component created by createTimedComponent
101-
for (let component of opts.rqa) {
102-
if (component.question == self) {
103-
component.question = res.question;
104-
break;
105-
}
106-
}
107-
self.realComponent = res.question;
108-
self.containerDiv = res.question.containerDiv;
109-
self.realComponent.selectorId = selectorId;
110-
} else {
111-
// just render this component on the page in its usual place
112-
res = renderRunestoneComponent(
113-
htmlsrc,
114-
selectorId,
115-
{
116-
selector_id: selectorId,
117-
useRunestoneServices: true,
118-
}
119-
);
120-
}
121-
console.log("resolving selectquestion");
122-
resolve("done");
123-
}
124-
);
125-
}.bind(this)
126-
);
127-
return myPromise;
81+
let request = new Request("/runestone/ajax/get_question_source", {
82+
method: "POST",
83+
headers: this.jsonHeaders,
84+
body: JSON.stringify(data),
85+
});
86+
let response = await fetch(request);
87+
let htmlsrc = await response.json();
88+
if (htmlsrc.indexOf("No preview") >= 0) {
89+
alert(
90+
`Error: Not able to find a question for ${selectorId} based on the criteria`
91+
);
92+
return response;
93+
}
94+
let res;
95+
if (opts.timed) {
96+
// timed components are not rendered immediately, only when the student
97+
// starts the assessment and visits this particular entry.
98+
res = createTimedComponent(htmlsrc, {
99+
timed: true,
100+
selector_id: selectorId,
101+
assessmentTaken: opts.assessmentTaken,
102+
});
103+
// replace the entry in the timed assessment's list of components
104+
// with the component created by createTimedComponent
105+
for (let component of opts.rqa) {
106+
if (component.question == self) {
107+
component.question = res.question;
108+
break;
109+
}
110+
}
111+
self.realComponent = res.question;
112+
self.containerDiv = res.question.containerDiv;
113+
self.realComponent.selectorId = selectorId;
114+
} else {
115+
// just render this component on the page in its usual place
116+
res = renderRunestoneComponent(htmlsrc, selectorId, {
117+
selector_id: selectorId,
118+
useRunestoneServices: true,
119+
});
120+
}
121+
return response;
128122
}
129123
}
130124

runestone/selectquestion/selectone.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,22 @@
3333
# ----------------------------------
3434
from docutils import nodes
3535
from docutils.parsers.rst import directives
36-
from sqlalchemy import Table
3736

3837
# local imports
3938
# -------------
4039
from runestone.server.componentdb import (
41-
addAssignmentQuestionToDB,
4240
addQuestionToDB,
4341
addHTMLToDB,
44-
get_engine_meta,
4542
maybeAddToAssignment,
4643
)
4744
from runestone.common.runestonedirective import (
4845
RunestoneIdDirective,
49-
RunestoneNode,
50-
add_i18n_js,
5146
)
5247

5348

5449
TEMPLATE = """
5550
<div class="runestone alert alert-warning">
56-
<div data-component="selectquestion" id={component_id} {selector} {points} {proficiency} {min_difficulty} {max_difficulty} {autogradable} {not_seen_ever} {primary}>
51+
<div data-component="selectquestion" id={component_id} {selector} {points} {proficiency} {min_difficulty} {max_difficulty} {autogradable} {not_seen_ever} {primary} {AB}>
5752
<p>Loading ...</p>
5853
</div>
5954
</div>
@@ -75,6 +70,7 @@ class SelectQuestion(RunestoneIdDirective):
7570
:points: number of points for this question
7671
:min_difficulty: minimum difficulty level
7772
:max_difficulty: maximum difficulty level
73+
:ab: experiment_name
7874
7975
Difficulty is measured in one of two ways. For things like multiple choice and
8076
fill in the blank, we can use the % of students that get the answer correct on
@@ -96,6 +92,7 @@ class SelectQuestion(RunestoneIdDirective):
9692
"autogradable": directives.flag,
9793
"not_seen_ever": directives.flag,
9894
"primary": directives.flag,
95+
"ab": directives.unchanged,
9996
}
10097
)
10198

@@ -170,6 +167,13 @@ def run(self):
170167
else:
171168
self.options["primary"] = ""
172169

170+
if "ab" in self.options:
171+
if len(self.question_bank_choices.split(",")) != 2:
172+
raise self.severe("AB questions must have 2 options for :fromid:")
173+
self.options["AB"] = f"data-ab={self.options['ab']}"
174+
else:
175+
self.options["AB"] = ""
176+
173177
maybeAddToAssignment(self)
174178

175179
res = TEMPLATE.format(**self.options)

runestone/timed/js/timed.js

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -98,38 +98,38 @@ export default class Timed extends RunestoneBase {
9898
}
9999
}
100100

101-
checkAssessmentStatus() {
101+
async checkAssessmentStatus() {
102102
// Has the user taken this exam? Inquiring minds want to know
103103
// If a user has not taken this exam then we want to make sure
104104
// that if a question has been seen by the student before we do
105105
// not populate previous answers.
106-
let self = this;
107-
let p = new Promise(function (resolve, reject) {
108-
let sendInfo = {
109-
div_id: self.divid,
110-
course_name: eBookConfig.course,
111-
};
112-
console.log(sendInfo);
113-
if (eBookConfig.useRunestoneServices) {
114-
jQuery.getJSON(
115-
eBookConfig.ajaxURL + "tookTimedAssessment",
116-
sendInfo,
117-
function (data, status) {
118-
self.taken = data.tookAssessment;
119-
self.assessmentTaken = self.taken;
120-
if (!self.taken) {
121-
localStorage.clear();
122-
}
123-
resolve();
124-
}
125-
); // end getJSON
126-
} else {
127-
self.taken = false;
128-
self.assessmentTaken = false;
129-
resolve();
106+
let response = Promise.resolve();
107+
let sendInfo = {
108+
div_id: this.divid,
109+
course_name: eBookConfig.course,
110+
};
111+
console.log(sendInfo);
112+
if (eBookConfig.useRunestoneServices) {
113+
let request = new Request(
114+
eBookConfig.ajaxURL + "tookTimedAssessment",
115+
{
116+
method: "POST",
117+
headers: this.jsonHeaders,
118+
body: JSON.stringify(sendInfo),
119+
}
120+
);
121+
response = await fetch(request);
122+
let data = await response.json();
123+
this.taken = data.tookAssessment;
124+
this.assessmentTaken = this.taken;
125+
if (!this.taken) {
126+
localStorage.clear();
130127
}
131-
}); // end promise
132-
return p;
128+
} else {
129+
this.taken = false;
130+
this.assessmentTaken = false;
131+
}
132+
return response;
133133
}
134134

135135
/*===============================

0 commit comments

Comments
 (0)