From 11cda540435264104841db79db50a3d09e85602f Mon Sep 17 00:00:00 2001 From: AlexandreDoneux <94830560+AlexandreDoneux@users.noreply.github.com> Date: Fri, 15 Dec 2023 08:50:28 +0100 Subject: [PATCH] [task_problems/code] Adding line offset for code problems (#976) A teacher could need to change the code lines offset in order to send back correct review when parsing student code into a template. --- inginious/common/tasks_problems.py | 12 ++++++++++++ inginious/frontend/pages/course_admin/task_edit.py | 2 ++ inginious/frontend/static/js/common.js | 7 +++++-- inginious/frontend/static/js/studio.js | 2 ++ inginious/frontend/task_problems.py | 3 ++- .../templates/course_admin/subproblems/code.html | 9 +++++++++ inginious/frontend/templates/tasks/code.html | 1 + 7 files changed, 33 insertions(+), 3 deletions(-) diff --git a/inginious/common/tasks_problems.py b/inginious/common/tasks_problems.py index ad451f2217..ca0ae88a85 100644 --- a/inginious/common/tasks_problems.py +++ b/inginious/common/tasks_problems.py @@ -181,6 +181,18 @@ def input_is_consistent(self, task_input, default_allowed_extension, default_max @classmethod def parse_problem(self, problem_content): + # Checking problem edit inputs + if len(problem_content["offset"]) == 0: + del problem_content["offset"] + else: + try: + offset = int(problem_content["offset"]) + if offset < 1: + raise Exception("Line offset must be positive!") + problem_content["offset"] = offset + except ValueError: + raise Exception("Line offset must be an integer!") + return Problem.parse_problem(problem_content) @classmethod diff --git a/inginious/frontend/pages/course_admin/task_edit.py b/inginious/frontend/pages/course_admin/task_edit.py index f68da25e6a..032b78a900 100644 --- a/inginious/frontend/pages/course_admin/task_edit.py +++ b/inginious/frontend/pages/course_admin/task_edit.py @@ -142,6 +142,8 @@ def POST_AUTH(self, courseid, taskid): # pylint: disable=arguments-differ # Network grading data["network_grading"] = "network_grading" in data + + except Exception as message: return json.dumps({"status": "error", "message": _("Your browser returned an invalid form ({})").format(message)}) diff --git a/inginious/frontend/static/js/common.js b/inginious/frontend/static/js/common.js index 0382ffe754..c88b745827 100644 --- a/inginious/frontend/static/js/common.js +++ b/inginious/frontend/static/js/common.js @@ -10,7 +10,7 @@ function init_common() colorizeStaticCode(); $('.code-editor').each(function(index, elem) { - registerCodeEditor(elem, $(elem).attr('data-x-language'), $(elem).attr('data-x-lines')); + registerCodeEditor(elem, $(elem).attr('data-x-language'), $(elem).attr('data-x-lines'), $(elem).attr('data-x-first-line')); }); //Fix a bug with codemirror and bootstrap tabs @@ -69,7 +69,7 @@ function colorizeStaticCode() } //Register and init a code editor (ace) -function registerCodeEditor(textarea, lang, lines) +function registerCodeEditor(textarea, lang, lines, firstline=1) { var mode = CodeMirror.findModeByName(lang); if(mode == undefined) @@ -77,8 +77,11 @@ function registerCodeEditor(textarea, lang, lines) var is_single = $(textarea).hasClass('single'); + + var editor = CodeMirror.fromTextArea(textarea, { lineNumbers: true, + firstLineNumber: firstline, mode: mode["mime"], foldGutter: true, styleActiveLine: true, diff --git a/inginious/frontend/static/js/studio.js b/inginious/frontend/static/js/studio.js index d309f8dcab..40bf86fb7c 100644 --- a/inginious/frontend/static/js/studio.js +++ b/inginious/frontend/static/js/studio.js @@ -411,6 +411,8 @@ function studio_init_template_code(well, pid, problem) var default_editor = registerCodeEditor(default_tag, 'text', default_tag.tagName === "INPUT" ? 1 : 10); if("default" in problem) default_editor.setValue(problem["default"]); + if("offset" in problem) + $('#offset-' + pid, well).val(problem["offset"]); } /** diff --git a/inginious/frontend/task_problems.py b/inginious/frontend/task_problems.py index 7c62eef397..5aaec80e43 100644 --- a/inginious/frontend/task_problems.py +++ b/inginious/frontend/task_problems.py @@ -69,6 +69,7 @@ class DisplayableCodeProblem(CodeProblem, DisplayableProblem): def __init__(self, problemid, content, translations, taskfs): super(DisplayableCodeProblem, self).__init__(problemid, content, translations, taskfs) + self._first_line = content.get("offset", 1) @classmethod def get_type_name(cls, language): @@ -82,7 +83,7 @@ def show_input(self, template_helper, language, seed): header = ParsableText(self.gettext(language,self._header), "rst", translation=self.get_translation_obj(language)) return template_helper.render("tasks/code.html", inputId=self.get_id(), header=header, - lines=8, maxChars=0, language=self._language, optional=self._optional, + lines=8, first_line=self._first_line, maxChars=0, language=self._language, optional=self._optional, default=self._default) @classmethod diff --git a/inginious/frontend/templates/course_admin/subproblems/code.html b/inginious/frontend/templates/course_admin/subproblems/code.html index 49228f4d74..0b18dc9bb3 100644 --- a/inginious/frontend/templates/course_admin/subproblems/code.html +++ b/inginious/frontend/templates/course_admin/subproblems/code.html @@ -47,3 +47,12 @@ {% endif %} + +{% if multiline %} +
+ +
+ +
+
+{% endif %} diff --git a/inginious/frontend/templates/tasks/code.html b/inginious/frontend/templates/tasks/code.html index 8fef8f3a7c..0dda84a578 100644 --- a/inginious/frontend/templates/tasks/code.html +++ b/inginious/frontend/templates/tasks/code.html @@ -9,4 +9,5 @@ class="code-editor form-control {% if '/' in inputId %} single {% endif %}" data-x-language="{{language}}" data-x-lines="{{lines}}" + data-x-first-line="{{first_line}}" data-optional="{% if optional %}{{True}}{% else %}{{False}}{% endif %}">{{ default }}