"""
TEMPLATE_END = """
diff --git a/runestone/activecode/css/activecode.css b/runestone/activecode/css/activecode.css
index 36475353c..c8edb813d 100644
--- a/runestone/activecode/css/activecode.css
+++ b/runestone/activecode/css/activecode.css
@@ -57,16 +57,13 @@
clear: both;
}
-.ac_section .clearfix {
- position: initial;
-}
-
.unittest-results {
margin-left: 20px;
}
.ac_output {
margin-top: 10px;
+ margin-bottom: -10px;
display: none;
background-color: inherit;
}
@@ -74,6 +71,10 @@
background-color: lightgray;
}
+.python_check_results pre {
+ background-color: #f5f5f5;
+}
+
.ac_caption {
text-align: center;
font-weight: bold;
@@ -102,10 +103,6 @@
border: 2px solid black;
}
-.ac_section > .col-md-12 {
- max-width: 100% !important;
-}
-
.full_width ol {
max-width: 100% !important;
}
@@ -150,3 +147,15 @@
margin-bottom: 10px;
min-height: 0px !important;
}
+
+.codelens {
+ margin-bottom: 20px;
+}
+
+.codecoach {
+ margin-top: 20px;
+}
+
+.ac_section .alert h3:first-child {
+ margin-top: 0px;
+ }
\ No newline at end of file
diff --git a/runestone/activecode/js/acfactory.js b/runestone/activecode/js/acfactory.js
index 9f907eed9..40051f1fa 100644
--- a/runestone/activecode/js/acfactory.js
+++ b/runestone/activecode/js/acfactory.js
@@ -86,9 +86,6 @@ export default class ACFactory {
sid: sid,
graderactive: true,
};
- if (language === "htmlmixed") {
- addopts["vertical"] = true;
- }
newac = ACFactory.createActiveCode(thepre, language, addopts);
var savediv = newac.divid;
newac.divid = savediv;
diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js
index c4610ab2d..957f1222b 100755
--- a/runestone/activecode/js/activecode.js
+++ b/runestone/activecode/js/activecode.js
@@ -63,7 +63,6 @@ export class ActiveCode extends RunestoneBase {
this.containerDiv = opts.orig;
this.useRunestoneServices = opts.useRunestoneServices;
this.python3 = true;
- this.alignVertical = opts.vertical;
this.origElem = orig;
this.origText = this.origElem.textContent;
this.divid = opts.orig.id;
@@ -159,7 +158,7 @@ export class ActiveCode extends RunestoneBase {
var linkdiv = document.createElement("div");
linkdiv.id = this.divid.replace(/_/g, "-").toLowerCase(); // :ref: changes _ to - so add this as a target
var codeDiv = document.createElement("div");
- $(codeDiv).addClass("ac_code_div col-md-12");
+ $(codeDiv).addClass("ac_code_div");
this.codeDiv = codeDiv;
this.outerDiv.lang = this.language;
$(this.origElem).replaceWith(this.outerDiv);
@@ -286,7 +285,6 @@ export class ActiveCode extends RunestoneBase {
var ctrlDiv = document.createElement("div");
var butt;
$(ctrlDiv).addClass("ac_actions");
- $(ctrlDiv).addClass("col-md-12");
// Run
butt = document.createElement("button");
$(butt).text($.i18n("msg_activecode_run_code"));
@@ -703,7 +701,7 @@ export class ActiveCode extends RunestoneBase {
// to hold turtle graphics output. We use a div in case the turtle changes from
// using a canvas to using some other element like svg in the future.
var outDiv = document.createElement("div");
- $(outDiv).addClass("ac_output col-md-12");
+ $(outDiv).addClass("ac_output");
this.outDiv = outDiv;
this.output = document.createElement("pre");
this.output.id = this.divid + "_stdout";
@@ -723,26 +721,28 @@ export class ActiveCode extends RunestoneBase {
$(this.graphics).addClass("visible-ac-canvas");
}.bind(this)
);
- var clearDiv = document.createElement("div");
- $(clearDiv).css("clear", "both"); // needed to make parent div resize properly
- this.outerDiv.appendChild(clearDiv);
+
+ //Anything that wants to add output to coachdiv can do so after the h3
+ // all those elements will be cleared with each run and coach display will be
+ // reset to none. Any component that adds content after a run should set display
+ // to block to ensure visibility
+ var coachDiv = document.createElement("div");
+ coachDiv.classList.add("alert", "alert-warning", "codecoach");
+ $(coachDiv).css("display", "none");
+ let coachHead = coachDiv.appendChild(document.createElement("h3"));
+ coachHead.textContent = "Code Coach";
+ this.outerDiv.appendChild(coachDiv);
+ this.codecoach = coachDiv;
+
outDiv.appendChild(this.output);
outDiv.appendChild(this.graphics);
this.outerDiv.appendChild(outDiv);
var lensDiv = document.createElement("div");
+ lensDiv.classList.add("codelens");
lensDiv.id = `${this.divid}_codelens`;
- $(lensDiv).addClass("col-md-12");
$(lensDiv).css("display", "none");
this.codelens = lensDiv;
this.outerDiv.appendChild(lensDiv);
- var coachDiv = document.createElement("div");
- $(coachDiv).addClass("col-md-12");
- $(coachDiv).css("display", "none");
- this.codecoach = coachDiv;
- this.outerDiv.appendChild(coachDiv);
- clearDiv = document.createElement("div");
- $(clearDiv).css("clear", "both"); // needed to make parent div resize properly
- this.outerDiv.appendChild(clearDiv);
}
disableSaveLoad() {
@@ -911,38 +911,6 @@ export class ActiveCode extends RunestoneBase {
div_id: this.divid,
});
}
- //
- showCodeCoach() {
- var myIframe;
- var srcURL;
- var cl;
- var div_id = this.divid;
- if (this.codecoach === null) {
- this.codecoach = document.createElement("div");
- this.codecoach.style.display = "block";
- }
- cl = this.codecoach.firstChild;
- if (cl) {
- this.codecoach.removeChild(cl);
- }
- srcURL = eBookConfig.app + "/admin/diffviewer?divid=" + div_id;
- myIframe = document.createElement("iframe");
- myIframe.setAttribute("id", div_id + "_coach");
- myIframe.setAttribute("width", "100%");
- myIframe.setAttribute("height", "500px");
- myIframe.setAttribute("style", "display:block");
- myIframe.style.background = "#fff";
- myIframe.style.width = "100%";
- myIframe.src = srcURL;
- this.codecoach.appendChild(myIframe);
- $(this.codecoach).show();
- this.logBookEvent({
- event: "coach",
- act: "view",
- div_id: this.divid,
- });
- }
toggleEditorVisibility() {}
@@ -1303,6 +1271,51 @@ Yet another is that there is an internal error. The internal error message is:
}
}
+ async checkPythonSyntax() {
+ let code = this.editor.getValue();
+ fetch('/ns/coach/python_check', {
+ method: 'POST',
+ body: code
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .then((data) => {
+ if(data.trim() !== '') {
+ //clean up returned text
+ let errorLines = data.split("\n");
+ let codeLines = code.split("\n");
+ let message = "";
+ for(let line of errorLines) {
+ if(line.indexOf(".py:") != -1) {
+ //old pyflakes returns "file:line:col error"
+ //new pyflakes returns "file:line:col: error"
+ //handle either
+ const cleaner = /[^.]*.py:(\d+):(\d+):? (.*)/i;
+ let lineParts = line.match(cleaner)
+ message += "Line " + lineParts[1] + ": " + lineParts[3] + "\n";
+ message += codeLines[lineParts[1] - 1] + "\n";
+ message += " ".repeat(lineParts[2] - 1) + "^\n";
+ } else {
+ message += line + "\n";
+ }
+ }
+ message = message.slice(0,-1); //remove trailing newline
+
+ //Render
+ let checkDiv = document.createElement("div");
+ checkDiv.classList.add("python_check_results");
+ let checkPre = checkDiv.appendChild(document.createElement("pre"));
+ checkPre.textContent = message;
+ this.codecoach.append(checkDiv);
+ $(this.codecoach).css("display", "block");
+ }
+ })
+ .catch(err => {
+ console.log("Error with ajax python check:", err);
+ });
+ }
+
/* runProg has several async elements to it.
* 1. Skulpt runs the python program asynchronously
* 2. The history is restored asynchronously
@@ -1328,6 +1341,10 @@ Yet another is that there is an internal error. The internal error message is:
var prog = await this.buildProg(true);
this.saveCode = "True";
$(this.output).text("");
+
+ //clear anything after header in codecoach
+ $(this.codecoach).children().slice(1).remove();
+
while ($(`#${this.divid}_errinfo`).length > 0) {
$(`#${this.divid}_errinfo`).remove();
}
@@ -1369,6 +1386,9 @@ Yet another is that there is an internal error. The internal error message is:
queue: false,
});
}
+ if (this.language == "python" || this.language == "python3") {
+ this.checkPythonSyntax();
+ }
try {
await Sk.misceval.asyncToPromise(function () {
return Sk.importMainWithBody("
", false, prog, true);
diff --git a/runestone/activecode/js/activecode_html.js b/runestone/activecode/js/activecode_html.js
index 5912bd588..c6844789a 100644
--- a/runestone/activecode/js/activecode_html.js
+++ b/runestone/activecode/js/activecode_html.js
@@ -3,7 +3,6 @@ import { ActiveCode } from "./activecode.js";
export default class HTMLActiveCode extends ActiveCode {
constructor(opts) {
super(opts);
- opts.alignVertical = true;
this.code = $("").html(this.origElem.innerHTML).text();
$(this.runButton).text("Render");
this.editor.setValue(this.code);
@@ -14,12 +13,6 @@ export default class HTMLActiveCode extends ActiveCode {
let saveCode = "True";
this.saveCode = await this.manage_scrubber(saveCode);
$(this.output).text("");
- if (!this.alignVertical) {
- $(this.codeDiv).switchClass("col-md-12", "col-md-6", {
- duration: 500,
- queue: false,
- });
- }
$(this.outDiv).show({ duration: 700, queue: false });
prog =
"" +
@@ -28,14 +21,8 @@ export default class HTMLActiveCode extends ActiveCode {
}
createOutput() {
- this.alignVertical = true;
var outDiv = document.createElement("div");
$(outDiv).addClass("ac_output");
- if (this.alignVertical) {
- $(outDiv).addClass("col-md-12");
- } else {
- $(outDiv).addClass("col-md-5");
- }
this.outDiv = outDiv;
this.output = document.createElement("iframe");
$(this.output).css("background-color", "white");
diff --git a/runestone/common/js/presenter_mode.js b/runestone/common/js/presenter_mode.js
index d7277d2ec..5edb6da06 100644
--- a/runestone/common/js/presenter_mode.js
+++ b/runestone/common/js/presenter_mode.js
@@ -138,7 +138,7 @@ function codelensListener(duration) {
function configureCodelens() {
let acCodeTitle = document.createElement("h4");
acCodeTitle.textContent = "Active Code Window";
- let acCode = $(".ac_code_div").removeClass("col-md-12");
+ let acCode = $(".ac_code_div");
$(".ac_code_div").addClass("col-md-6");
acCode.prepend(acCodeTitle);
diff --git a/runestone/hparsons/hparsons.py b/runestone/hparsons/hparsons.py
index 1971d288d..a0b69672a 100755
--- a/runestone/hparsons/hparsons.py
+++ b/runestone/hparsons/hparsons.py
@@ -39,7 +39,7 @@ def setup(app):
TEMPLATE_START = """
-
+
"""
TEMPLATE_END = """
diff --git a/runestone/hparsons/js/SQLFeedback.js b/runestone/hparsons/js/SQLFeedback.js
index 55b5ca097..7cb0163cb 100644
--- a/runestone/hparsons/js/SQLFeedback.js
+++ b/runestone/hparsons/js/SQLFeedback.js
@@ -9,7 +9,7 @@ export default class SQLFeedback extends HParsonsFeedback {
createOutput() {
var outDiv = document.createElement("div");
- $(outDiv).addClass("hp_output col-md-12");
+ $(outDiv).addClass("hp_output");
this.outDiv = outDiv;
this.output = document.createElement("pre");
this.output.id = this.hparsons.divid + "_stdout";
diff --git a/runestone/hparsons/js/hparsons.js b/runestone/hparsons/js/hparsons.js
index e242ef91b..30f903f15 100644
--- a/runestone/hparsons/js/hparsons.js
+++ b/runestone/hparsons/js/hparsons.js
@@ -125,7 +125,6 @@ export default class HParsons extends RunestoneBase {
createControls() {
var ctrlDiv = document.createElement("div");
$(ctrlDiv).addClass("hp_actions");
- $(ctrlDiv).addClass("col-md-12");
// Run Button
this.runButton = document.createElement("button");