From bb628d78aad00c55d1b8e8d54cecf237ccdf7f88 Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Tue, 21 Mar 2023 13:23:37 -0700 Subject: [PATCH 1/9] Request pyflakes info from server and render to page on Python activecode run --- runestone/activecode/css/activecode.css | 10 +++++ runestone/activecode/js/activecode.js | 58 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/runestone/activecode/css/activecode.css b/runestone/activecode/css/activecode.css index 36475353c..32473c851 100644 --- a/runestone/activecode/css/activecode.css +++ b/runestone/activecode/css/activecode.css @@ -74,6 +74,16 @@ background-color: lightgray; } +.python_check_results { + margin-top: 20px; + padding-top: 0px; + padding-bottom: 0px; +} + +.python_check_results pre { + background-color: #f5f5f5; +} + .ac_caption { text-align: center; font-weight: bold; diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index c4610ab2d..0cb0483e3 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -1303,6 +1303,61 @@ Yet another is that there is an internal error. The internal error message is: } } + async checkPythonSyntax() { + let checkDiv = this.outerDiv.querySelector("div.python_check_results"); + if( checkDiv != null ) + checkDiv.remove(); + + let code = this.editor.getValue(); + + fetch('http://localhost/ns/books/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 + checkDiv = document.createElement("div"); + checkDiv.classList.add("python_check_results","alert", "alert-warning"); + let checkHead = checkDiv.appendChild(document.createElement("h3")); + checkHead.textContent = "Syntax tips:"; + let checkPre = checkDiv.appendChild(document.createElement("pre")); + //checkPre.classList.add("alert-warning"); + checkPre.textContent = message; + + //Squeeze check_results right before output pane + const outDiv = this.outDiv; + outDiv.parentNode.insertBefore(checkDiv, outDiv); + } + }) + .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 @@ -1369,6 +1424,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); From 4c5bd55e354973ed27f7a641a0c8e8812ec9f2e8 Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Tue, 21 Mar 2023 17:52:59 -0700 Subject: [PATCH 2/9] Make Syntax Tips title look more like Error titles --- runestone/activecode/js/activecode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index 0cb0483e3..92b5d0bd3 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -1343,7 +1343,7 @@ Yet another is that there is an internal error. The internal error message is: checkDiv = document.createElement("div"); checkDiv.classList.add("python_check_results","alert", "alert-warning"); let checkHead = checkDiv.appendChild(document.createElement("h3")); - checkHead.textContent = "Syntax tips:"; + checkHead.textContent = "Syntax Tips"; let checkPre = checkDiv.appendChild(document.createElement("pre")); //checkPre.classList.add("alert-warning"); checkPre.textContent = message; From 3448b6e72d178d7fae6ce95b1e05bfafd94edc03 Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Wed, 22 Mar 2023 06:55:16 -0700 Subject: [PATCH 3/9] Change testing fetch url --- runestone/activecode/js/activecode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index 92b5d0bd3..b38ba12b5 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -1310,7 +1310,7 @@ Yet another is that there is an internal error. The internal error message is: let code = this.editor.getValue(); - fetch('http://localhost/ns/books/python_check', { + fetch('/ns/books/python_check', { method: 'POST', body: code }) From 1f0da5c954736491a7028b1605f813c2306540b8 Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Wed, 22 Mar 2023 20:07:23 -0700 Subject: [PATCH 4/9] Update URL to match new endpoint --- runestone/activecode/js/activecode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index b38ba12b5..2bbde2091 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -1310,7 +1310,7 @@ Yet another is that there is an internal error. The internal error message is: let code = this.editor.getValue(); - fetch('/ns/books/python_check', { + fetch('/ns/coach/python_check', { method: 'POST', body: code }) From 7a0fc954a36e7f7e87e594e891a8162c1afbcbc2 Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Wed, 22 Mar 2023 07:07:04 -0700 Subject: [PATCH 5/9] Get rid of col-md-12 in interactives Was there from an experiment with code/output side/side --- runestone/activecode/activecode.py | 2 +- runestone/activecode/css/activecode.css | 4 ---- runestone/activecode/js/activecode.js | 7 ++----- runestone/common/js/presenter_mode.js | 2 +- runestone/hparsons/hparsons.py | 2 +- runestone/hparsons/js/SQLFeedback.js | 2 +- runestone/hparsons/js/hparsons.js | 1 - 7 files changed, 6 insertions(+), 14 deletions(-) diff --git a/runestone/activecode/activecode.py b/runestone/activecode/activecode.py index d565ff78f..34d974c1f 100644 --- a/runestone/activecode/activecode.py +++ b/runestone/activecode/activecode.py @@ -87,7 +87,7 @@ def setup(app): TEMPLATE_START = """
-
+
""" TEMPLATE_END = """ diff --git a/runestone/activecode/css/activecode.css b/runestone/activecode/css/activecode.css index 32473c851..7cd762b65 100644 --- a/runestone/activecode/css/activecode.css +++ b/runestone/activecode/css/activecode.css @@ -112,10 +112,6 @@ border: 2px solid black; } -.ac_section > .col-md-12 { - max-width: 100% !important; -} - .full_width ol { max-width: 100% !important; } diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index 2bbde2091..47147063f 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -159,7 +159,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 +286,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 +702,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"; @@ -731,12 +730,10 @@ export class ActiveCode extends RunestoneBase { this.outerDiv.appendChild(outDiv); var lensDiv = document.createElement("div"); 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); 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"); From 45b33d138f330964359ceda314fca67d40593820 Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Wed, 22 Mar 2023 07:07:38 -0700 Subject: [PATCH 6/9] Margin tweaks for activecode --- runestone/activecode/css/activecode.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runestone/activecode/css/activecode.css b/runestone/activecode/css/activecode.css index 7cd762b65..dc66d1363 100644 --- a/runestone/activecode/css/activecode.css +++ b/runestone/activecode/css/activecode.css @@ -67,6 +67,7 @@ .ac_output { margin-top: 10px; + margin-bottom: -10px; display: none; background-color: inherit; } @@ -156,3 +157,7 @@ margin-bottom: 10px; min-height: 0px !important; } + +.codelens { + margin-bottom: 20px; +} \ No newline at end of file From 5b71fa8223b56fc6ee5033175cb1ea36676ef000 Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Wed, 22 Mar 2023 07:08:16 -0700 Subject: [PATCH 7/9] Activecode - remove useless divs. Add class to codelens and codecoach divs --- runestone/activecode/js/activecode.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index 47147063f..c157e1d89 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -722,24 +722,20 @@ 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); 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).css("display", "none"); this.codelens = lensDiv; this.outerDiv.appendChild(lensDiv); var coachDiv = document.createElement("div"); + coachDiv.classList.add("codecoach"); $(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() { From aa19d4268b7c63604c406dc4577a5aae0e6ae60e Mon Sep 17 00:00:00 2001 From: Andrew Scholer Date: Wed, 22 Mar 2023 07:09:05 -0700 Subject: [PATCH 8/9] Remove alignVertical from activecode --- runestone/activecode/js/acfactory.js | 3 --- runestone/activecode/js/activecode.js | 1 - runestone/activecode/js/activecode_html.js | 13 ------------- 3 files changed, 17 deletions(-) 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 c157e1d89..01d331331 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; 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 = $("