diff --git a/app/assets/javascripts/simple_code.js b/app/assets/javascripts/simple_code.js index 18a89d2f..e3cca305 100644 --- a/app/assets/javascripts/simple_code.js +++ b/app/assets/javascripts/simple_code.js @@ -6,6 +6,8 @@ $(document).ready(function(){ Sk.canvas = "studentCanvas"; $.getJSON('/data/simple_code.json', function(response) { data = response; + var externalIdElement = document.getElementById("exercise-data"); + var externalId = externalIdElement.getAttribute("data-external-id"); var initial = data[index]['initial']; var initialArray = initial.split('\n'); var config = data[index]['parsonsConfig']; diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index c226384e..f92cc231 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -3,6 +3,7 @@ class ExercisesController < ApplicationController require 'oauth/request_proxy/rack_request' require 'zip' require 'tempfile' + require 'json' load_and_authorize_resource @@ -225,7 +226,50 @@ def edit end session[:return_to] = @return_to end + # ------------------------------------------------------------- + def edit_parsons + step = params[:step] + full_name = "parsons_s#{step}" + puts "full_name = #{full_name}" + @exercise = Exercise.where('name LIKE ?', "%#{full_name}%").first + json_file_path = Rails.root.join('public', 'data', 'simple_code.json') + if File.exist?(json_file_path) + file_content = File.read(json_file_path) + json_content = JSON.parse(file_content) + @step_data = json_content["s#{step}"] + else + @step_data = {} + end + end + # ------------------------------------------------------------- + def update_parsons + step = params[:step] + json_data = params[:step_json_data] # Ensure this matches the name attribute from the form + Rails.logger.debug "Received JSON data: #{json_data}" + + json_file_path = Rails.root.join('public', 'data', 'simple_code.json') + + unless File.exist?(json_file_path) + redirect_to edit_parsons_exercise_path(step: step), alert: 'JSON file not found.' + return + end + + begin + content = JSON.parse(File.read(json_file_path)) + updated_data = JSON.parse(json_data) + if content["s#{step}"].present? + content["s#{step}"] = updated_data + File.write(json_file_path, JSON.pretty_generate(content)) + redirect_to edit_parsons_exercise_path(step: step), notice: 'Parsons updated successfully.' + else + redirect_to edit_parsons_exercise_path(step: step), alert: "Step not found in JSON." + end + rescue JSON::ParserError => e + Rails.logger.debug e.inspect # Log the error for inspection + redirect_to edit_parsons_exercise_path(step: step), alert: "Failed to parse JSON: #{e.message}" + end + end # ------------------------------------------------------------- # POST /exercises diff --git a/app/views/exercises/_exercise.html.haml b/app/views/exercises/_exercise.html.haml index 2ea70a4f..f18b9e3b 100644 --- a/app/views/exercises/_exercise.html.haml +++ b/app/views/exercises/_exercise.html.haml @@ -95,9 +95,14 @@ = link_to exercise.display_name, show_exercise_path(step: "s#{step}") - else = link_to exercise.display_name, exercise_practice_path(exercise) - + - is_parsons = exercise.name.downcase.include?('parsons') - if [ 'show', 'index', 'search' ].include?(action_name) && (current_user.andand.can? :edit, exercise) - .right= button_link 'Edit', edit_exercise_path(exercise), class: 'btn btn-primary btn-sm' + .right + - if is_parsons + - step = exercise.name.downcase.match(/parsons_s(\d+)/)[1] + = button_link 'Edit', edit_parsons_exercise_path(step: step), class: 'btn btn-primary btn-sm' + - else + = button_link 'Edit', edit_exercise_path(exercise), class: 'btn btn-primary btn-sm' - if !new_workout .summary diff --git a/app/views/exercises/edit_parsons.html.haml b/app/views/exercises/edit_parsons.html.haml new file mode 100644 index 00000000..28f28b75 --- /dev/null +++ b/app/views/exercises/edit_parsons.html.haml @@ -0,0 +1,29 @@ +- if !@lti_launch + = render partial: 'layouts/breadcrumb' + +%h1 + Edit Parsons: + - if @exercise + = link_to @exercise.display_name, exercise_practice_path(@exercise) + - else + %span Error: Exercise not found. + + +%h2 + Edit JSON Data for Step: #{params[:step]} += form_tag update_parsons_exercise_path(step: params[:step]), method: :post do + %fieldset + .field + = label_tag :step_json_data, "Step JSON Data" + = text_area_tag :step_json_data, JSON.pretty_generate(@step_data), class: 'json-editor', rows: 20, cols: 80 + .actions + = submit_tag "Save JSON Changes", class: 'btn btn-primary' + +:css + .json-editor { + font-family: monospace; + background-color: #f9f9f9; + border: 1px solid #ccc; + width: 100%; + margin-top: 5px; + } \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 533051e9..5a5b2231 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -67,6 +67,8 @@ get 'exercises/download_attempt_data' => 'exercises#download_attempt_data', as: :download_exercise_attempt_data get '/gym/exercises/Jsparson/exercise/simple/:step', to: 'exercises#show_exercise', as: 'show_exercise' + get '/exercises/Jsparson/exercise/simple/:step/parsons_edit', to: 'exercises#edit_parsons', as: 'edit_parsons_exercise' + post '/exercises/Jsparson/exercise/simple/:step/update_parsons', to: 'exercises#update_parsons', as: 'update_parsons_exercise' # At the bottom, so the routes above take precedence over existing ids resources :exercises diff --git a/public/data/simple_code.json b/public/data/simple_code.json index 3abcbb85..7c5e4ad3 100644 --- a/public/data/simple_code.json +++ b/public/data/simple_code.json @@ -1,95 +1,94 @@ { - "s3":{ - "initial": "IF $$toggle::a::b$$ $$toggle::<::>::<>$$ b THEN\n min := a\nELSE\n min := b\nENDIF", - "parsonsConfig": { - "max_wrong_lines": 1, - "vartests": [ - { - "initcode": "min = None\na = 0\nb = 2", - "code": "", - "message": "Testing with a = 0 ja b = 2", - "variables": { - "min": 0 - } - }, - { - "initcode": "min = None\na = 7\nb = 4\n", - "code": "", - "message": "Testing with a = 7 ja b = 4", - "variables": { - "min": 4 - } - } - ], - "executable_code": "if $$toggle$$ $$toggle::<::>::!=$$ b:\nmin = a\nelse:\nmin = b\npass", - "programmingLang": "pseudo" + "s3": { + "initial": "IF $$toggle::a::b$$ $$toggle::<::>::<>$$ b THEN\n min := a\nELSE\n min := b\nENDIF", + "parsonsConfig": { + "max_wrong_lines": 1, + "vartests": [ + { + "initcode": "min = None\na = 1\nb = 2", + "code": "", + "message": "Testing with a = 1 ja b = 2", + "variables": { + "min": 1 + } }, - "title": "Find minimum", - "instructions": "Construct a function by drag& dropping and reordering lines from the left to the right.The constructed function should set the value of variable min to be the smaller of variables a and b.", - "order": 0 + { + "initcode": "min = None\na = 7\nb = 4\n", + "code": "", + "message": "Testing with a = 7 ja b = 4", + "variables": { + "min": 4 + } + } + ], + "executable_code": "if $$toggle$$ $$toggle::<::>::!=$$ b:\nmin = a\nelse:\nmin = b\npass", + "programmingLang": "pseudo" }, - "s4":{ - "initial": "$$toggle::x::y::tmp$$ = $$toggle::x::y::tmp$$\n$$toggle::x::y::tmp$$ = $$toggle::x::y::tmp$$\n$$toggle::x::y::tmp$$ = $$toggle::x::y::tmp$$", - "parsonsConfig": { - "max_wrong_lines": 1, - "vartests": [ - { - "initcode": "x = 0\ny=2", - "code": "", - "message": "Testing with initial variable values x = 0 and y = 2", - "variables": { - "x": 2 - } - }, - { - "initcode": "x = 3\ny=4\n", - "code": "", - "message": "Testing with initial variable values x = 3 and y = 4", - "variables": { - "x": 4, - "y": 3 - } - } - ], - "executable_code": "tmp = x\nx = y\ny = tmp\npass" , - "programmingLang": "pseudo" + "title": "Find minimum", + "instructions": "Construct a function by drag& dropping and reordering lines from the left to the right.The constructed function should set the value of variable min to be the smaller of variables a and b.", + "order": 0 + }, + "s4": { + "initial": "$$toggle::x::y::tmp$$ = $$toggle::x::y::tmp$$\n$$toggle::x::y::tmp$$ = $$toggle::x::y::tmp$$\n$$toggle::x::y::tmp$$ = $$toggle::x::y::tmp$$", + "parsonsConfig": { + "max_wrong_lines": 1, + "vartests": [ + { + "initcode": "x = 0\ny=2", + "code": "", + "message": "Testing with initial variable values x = 0 and y = 2", + "variables": { + "x": 2 + } }, - "title": "Variable Swap", - "instructions": "Construct a program that swaps the values of variables x and y using the helper variable tmp. You can change the names of the variables", - "order": 1 + { + "initcode": "x = 3\ny=4\n", + "code": "", + "message": "Testing with initial variable values x = 3 and y = 4", + "variables": { + "x": 4, + "y": 3 + } + } + ], + "executable_code": "tmp = x\nx = y\ny = tmp\npass", + "programmingLang": "pseudo" }, - "s5":{ - "initial": "for (int i=0;i<3;i++) {\nSystem.out.print(\"I \");\nSystem.out.print(\"am \");\nSystem.out.print(\"a Java program \");\n}", - "parsonsConfig": { - "max_wrong_lines": 1, - "vartests": [ - { - "initcode": "output = ''", - "code": "", - "message": "Testing...", - "variables": { - "output": "I am a Java program I am a Java program I am a Java program " - } - } - ], - "executable_code": "for x in range(3):\noutput += 'I '\noutput += 'am '\noutput += 'a Java program '\npass\n", - "programmingLang": "java" - }, - "title": "Print message with loop", - "instructions": "Construct code by reordering and indenting the lines.", - "order": 2 + "title": "Variable Swap", + "instructions": "Construct a program that swaps the values of variables x and y using the helper variable tmp. You can change the names of the variables", + "order": 1 + }, + "s5": { + "initial": "for (int i=0;i<3;i++) {\nSystem.out.print(\"I \");\nSystem.out.print(\"am \");\nSystem.out.print(\"a Java program \");\n}", + "parsonsConfig": { + "max_wrong_lines": 1, + "vartests": [ + { + "initcode": "output = ''", + "code": "", + "message": "Testing...", + "variables": { + "output": "I am a Java program I am a Java program I am a Java program " + } + } + ], + "executable_code": "for x in range(3):\noutput += 'I '\noutput += 'am '\noutput += 'a Java program '\npass\n", + "programmingLang": "java" }, - "s6":{ - "initial": "REPEAT 3 TIMES\nforward(100)\nleft(120)\nENDREPEAT", - "parsonsConfig": { - "max_wrong_lines": 1, - "turtleModelCode":"modelTurtle.forward(100)\nmodelTurtle.left(120)\nmodelTurtle.forward(100)\nmodelTurtle.left(120)\nmodelTurtle.forward(100)\nmodelTurtle.left(120)", - "executable_code": "for i in range(0,3):\nmyTurtle.forward(100)\nmyTurtle.left(120)\npass", - "programmingLang": "pseudo" - }, - "title": "draw triangle", - "instructions": "Construct a program by drag&dropping and reordering lines from the left to the right.The constructed program should draw a triangle like shown below.", - "order": 3 - } - + "title": "Print message with loop", + "instructions": "Construct code by reordering and indenting the lines.", + "order": 2 + }, + "s6": { + "initial": "REPEAT 3 TIMES\nforward(100)\nleft(120)\nENDREPEAT", + "parsonsConfig": { + "max_wrong_lines": 1, + "turtleModelCode": "modelTurtle.forward(100)\nmodelTurtle.left(120)\nmodelTurtle.forward(100)\nmodelTurtle.left(120)\nmodelTurtle.forward(100)\nmodelTurtle.left(120)", + "executable_code": "for i in range(0,3):\nmyTurtle.forward(100)\nmyTurtle.left(120)\npass", + "programmingLang": "pseudo" + }, + "title": "draw triangle", + "instructions": "Construct a program by drag&dropping and reordering lines from the left to the right.The constructed program should draw a triangle like shown below.", + "order": 3 + } } \ No newline at end of file