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

Commit de09b1e

Browse files
committed
updates and additional features for toggle select
1 parent eae9a06 commit de09b1e

2 files changed

Lines changed: 124 additions & 28 deletions

File tree

runestone/selectquestion/js/selectone.js

Lines changed: 118 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default class SelectOne extends RunestoneBase {
4040
this.primaryOnly = $(opts.orig).data("primary");
4141
this.ABExperiment = $(opts.orig).data("ab");
4242
this.toggle = $(opts.orig).data("toggle");
43+
this.toggleOptions = $(opts.orig).data("toggleoptions");
4344
opts.orig.id = this.selector_id;
4445
}
4546
/**
@@ -84,6 +85,9 @@ export default class SelectOne extends RunestoneBase {
8485
if (this.toggle) {
8586
data.toggle = this.toggle;
8687
}
88+
if (this.toggleOptions) {
89+
data.toggleOptions = this.toggleOptions;
90+
}
8791
let opts = this.origOpts;
8892
let selectorId = this.selector_id;
8993
console.log("getting question source");
@@ -121,13 +125,15 @@ export default class SelectOne extends RunestoneBase {
121125
self.containerDiv = res.question.containerDiv;
122126
self.realComponent.selectorId = selectorId;
123127
} else {
124-
///////////////////////////
125128
if (data.toggle) {
126129
var toggleQuestions = this.questions.split(", ");
127130
var toggleUI = "";
128131
if (!document.getElementById("component-preview")) {
129132
toggleUI +=
130-
'<div id="component-preview" class="col-md-6 toggle-preview" style="z-index: 999;"></div>';
133+
'<div id="component-preview" class="col-md-6 toggle-preview" style="z-index: 999;">' +
134+
'<div id="toggle-buttons"></div>' +
135+
'<div id="toggle-preview"></div>' +
136+
'</div>';
131137
}
132138
toggleUI +=
133139
'<label for="' +
@@ -153,7 +159,7 @@ export default class SelectOne extends RunestoneBase {
153159
)
154160
) {
155161
case "activecode":
156-
toggleQuestionType = "Active Code";
162+
toggleQuestionType = "Write Code";
157163
break;
158164
case "clickablearea":
159165
toggleQuestionType = "Clickable Area";
@@ -168,7 +174,7 @@ export default class SelectOne extends RunestoneBase {
168174
toggleQuestionType = "Multiple Choice";
169175
break;
170176
case "parsons":
171-
toggleQuestionType = "Parsons";
177+
toggleQuestionType = "Mixed-Up Code";
172178
break;
173179
case "shortanswer":
174180
toggleQuestionType = "Short Answer";
@@ -180,8 +186,11 @@ export default class SelectOne extends RunestoneBase {
180186
'">' +
181187
toggleQuestionType +
182188
" - " +
183-
toggleQuestions[i] +
184-
"</option>";
189+
toggleQuestions[i];
190+
if ((i == 0) && (data.toggleOptions.includes("lock"))) {
191+
toggleUI += " (only this question will be graded)";
192+
}
193+
toggleUI += "</option>";
185194
}
186195
toggleUI +=
187196
'</select><div id="' +
@@ -191,13 +200,11 @@ export default class SelectOne extends RunestoneBase {
191200
toggleFirstID = toggleFirstID.split('"')[0];
192201
htmlsrc = toggleUI + htmlsrc + "</div>";
193202
}
194-
///////////////////////////
195203
// just render this component on the page in its usual place
196204
res = renderRunestoneComponent(htmlsrc, selectorId, {
197205
selector_id: selectorId,
198206
useRunestoneServices: true,
199207
});
200-
///////////////////////////
201208
if (data.toggle) {
202209
$("#component-preview").hide();
203210
var toggleQuestionSelect = document.getElementById(
@@ -219,12 +226,12 @@ export default class SelectOne extends RunestoneBase {
219226
"change",
220227
async function () {
221228
await this.togglePreview(
222-
toggleQuestionSelect.parentElement.id
229+
toggleQuestionSelect.parentElement.id,
230+
data.toggleOptions
223231
);
224232
}.bind(this)
225233
);
226234
}
227-
///////////////////////////
228235
}
229236
return response;
230237
}
@@ -241,15 +248,15 @@ export default class SelectOne extends RunestoneBase {
241248
return htmlsrc;
242249
}
243250

244-
async togglePreview(parentID) {
251+
async togglePreview(parentID, toggleOptions) {
245252
var parentDiv = document.getElementById(parentID);
246253
var toggleQuestionSelect = parentDiv.getElementsByTagName("select")[0];
247254
var selectedQuestion =
248255
toggleQuestionSelect.options[toggleQuestionSelect.selectedIndex]
249256
.value;
250257
var htmlsrc = await this.getToggleSrc(selectedQuestion);
251-
let res = renderRunestoneComponent(htmlsrc, "component-preview", {
252-
selector_id: "component-preview",
258+
let res = renderRunestoneComponent(htmlsrc, "toggle-preview", {
259+
selector_id: "toggle-preview",
253260
useRunestoneServices: true,
254261
});
255262
// let pd = document.getElementById(preview_div);
@@ -259,24 +266,54 @@ export default class SelectOne extends RunestoneBase {
259266
$(closeButton).text("Close Preview");
260267
$(closeButton).addClass("btn btn-default");
261268
$(closeButton).click(function (event) {
262-
$("#component-preview").html("");
269+
$("#toggle-buttons").html("");
270+
$("#toggle-preview").html("");
263271
toggleQuestionSelect.value = $("#" + parentID).data(
264272
"toggle_current"
265273
);
266274
$("#component-preview").hide();
267275
});
268-
$("#component-preview").append(closeButton);
276+
$("#toggle-buttons").append(closeButton);
277+
278+
if (!(toggleOptions.includes("lock"))) {
279+
let setButton = document.createElement("button");
280+
$(setButton).text("Select this Problem");
281+
$(setButton).addClass("btn btn-primary");
282+
$(setButton).click(
283+
async function () {
284+
await this.toggleSet(parentID, selectedQuestion, htmlsrc);
285+
$("#component-preview").hide();
286+
}.bind(this)
287+
);
288+
$("#toggle-buttons").append(setButton);
289+
290+
if (toggleOptions.includes("transfer")) {
291+
var optionText;
292+
var currentType;
293+
var selectedType;
294+
for (var n = 0; n < toggleQuestionSelect.options.length; n++) {
295+
optionText = toggleQuestionSelect.options[n].innerHTML;
296+
if (optionText.includes($("#" + parentID).data("toggle_current"))) {
297+
currentType = optionText.substring(0, optionText.indexOf(" - "));
298+
}
299+
if (optionText.includes(selectedQuestion)) {
300+
selectedType = optionText.substring(0, optionText.indexOf(" - "));
301+
}
302+
}
303+
if ((currentType == "Mixed-Up Code") && (selectedType == "Write Code")) {
304+
let transferButton = document.createElement("button");
305+
$(transferButton).text("Transfer Mixed-Up Code to Write Code");
306+
$(transferButton).addClass("btn btn-primary");
307+
$(transferButton).click(
308+
async function () {
309+
await this.toggleTransfer(parentID, selectedQuestion, htmlsrc);
310+
}.bind(this)
311+
);
312+
$("#toggle-buttons").append(transferButton);
313+
}
314+
}
315+
}
269316

270-
let setButton = document.createElement("button");
271-
$(setButton).text("Select this Problem");
272-
$(setButton).addClass("btn btn-primary");
273-
$(setButton).click(
274-
async function () {
275-
await this.toggleSet(parentID, selectedQuestion, htmlsrc);
276-
$("#component-preview").hide();
277-
}.bind(this)
278-
);
279-
$("#component-preview").append(setButton);
280317
$("#component-preview").show();
281318
}
282319

@@ -295,9 +332,64 @@ export default class SelectOne extends RunestoneBase {
295332
{}
296333
);
297334
let response = await fetch(request);
298-
$("#component-preview").html("");
335+
$("#toggle-buttons").html("");
336+
$("#toggle-preview").html("");
299337
$("#" + parentID).data("toggle_current", selectedQuestion);
300338
}
339+
340+
async toggleTransfer(parentID, selectedQuestion, htmlsrc) {
341+
var currentParsons = document.getElementById(parentID + "-toggleSelectedQuestion").querySelectorAll("div[class^='answer']")[0].getElementsByClassName("prettyprint lang-py");
342+
var currentParsonsClass;
343+
var currentBlockIndent;
344+
var indentCount
345+
var indent;
346+
var parsonsLine;
347+
var parsonsLines = ``;
348+
var count;
349+
for (var p = 0; p < currentParsons.length; p++) {
350+
indentCount = 0;
351+
indent = "";
352+
currentParsonsClass = currentParsons[p].classList[2];
353+
if (currentParsonsClass) {
354+
if (currentParsonsClass.includes("indent")) {
355+
indentCount = parseInt(indentCount) + parseInt(currentParsonsClass.substring(6,currentParsonsClass.length));
356+
}
357+
}
358+
currentBlockIndent = currentParsons[p].parentElement.parentElement.style.left;
359+
if (currentBlockIndent) {
360+
indentCount = parseInt(indentCount) + parseInt(currentBlockIndent.substring(0,currentBlockIndent.indexOf("px")) / 30);
361+
}
362+
for (var d = 0; d < indentCount; d++) {
363+
indent += " ";
364+
}
365+
parsonsLine = currentParsons[p].getElementsByTagName("span");
366+
count = 0;
367+
for (var l = 0; l < parsonsLine.length; l++) {
368+
if (parsonsLine[l].childNodes[0].nodeName == "#text") { // parsons blocks have differing amounts of hierarchy levels (spans within spans)
369+
if ((p == 0) && (count == 0)) { // need different check than l == 0 because the l numbering doesn't align with location within line due to inconsistent span heirarchy
370+
parsonsLines += indent + parsonsLine[l].innerHTML;
371+
count++;
372+
}
373+
else if (count != 0) {
374+
parsonsLines += parsonsLine[l].innerHTML;
375+
count++;
376+
}
377+
else {
378+
parsonsLines = parsonsLines + `
379+
` + indent + parsonsLine[l].innerHTML;
380+
parsonsLines = parsonsLines.replace(" ", "");
381+
count++;
382+
}
383+
}
384+
}
385+
}
386+
var htmlsrcFormer = htmlsrc.substring(0, htmlsrc.indexOf("<textarea") + htmlsrc.split("<textarea")[1].indexOf(">") + 10);
387+
var htmlsrcLatter = htmlsrc.substring(htmlsrc.indexOf("</textarea>"), htmlsrc.length);
388+
htmlsrc = htmlsrcFormer + parsonsLines + htmlsrcLatter;
389+
390+
await this.toggleSet(parentID, selectedQuestion, htmlsrc);
391+
$("#component-preview").hide();
392+
}
301393
}
302394

303395
/*

runestone/selectquestion/selectone.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848

4949
TEMPLATE = """
5050
<div class="runestone alert alert-warning sqcontainer">
51-
<div data-component="selectquestion" id={component_id} {selector} {points} {proficiency} {min_difficulty} {max_difficulty} {autogradable} {not_seen_ever} {primary} {AB} {toggle}>
51+
<div data-component="selectquestion" id={component_id} {selector} {points} {proficiency} {min_difficulty} {max_difficulty} {autogradable} {not_seen_ever} {primary} {AB} {toggle} {toggle_options}>
5252
<p>Loading ...</p>
5353
</div>
5454
</div>
@@ -94,7 +94,7 @@ class SelectQuestion(RunestoneIdDirective):
9494
"not_seen_ever": directives.flag,
9595
"primary": directives.flag,
9696
"ab": directives.unchanged,
97-
"toggle": directives.flag,
97+
"toggle": directives.unchanged,
9898
}
9999
)
100100

@@ -183,8 +183,12 @@ def run(self):
183183
self.options["AB"] = ""
184184

185185
if "toggle" in self.options:
186+
self.options[
187+
"toggle_options"
188+
] = f"data-toggleoptions={self.options['toggle']}"
186189
self.options["toggle"] = "data-toggle=true"
187190
else:
191+
self.options["toggle_options"] = ""
188192
self.options["toggle"] = ""
189193

190194
maybeAddToAssignment(self)

0 commit comments

Comments
 (0)