Skip to content

Commit

Permalink
[CLEAN-UP] Removes quiz iframe structure (hedyorg#2745)
Browse files Browse the repository at this point in the history
  • Loading branch information
TiBiBa authored Jun 1, 2022
1 parent 9247b28 commit d5edf7b
Show file tree
Hide file tree
Showing 19 changed files with 491 additions and 832 deletions.
4 changes: 4 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,9 @@ def index(level, program_id):
hide_cheatsheet = True

quiz = True if QUIZZES[g.lang].get_quiz_data_for_level(level) else False
quiz_questions = 0
if quiz:
quiz_questions = len(QUIZZES[g.lang].get_quiz_data_for_level(level))
if 'other_settings' in customizations and 'hide_quiz' in customizations['other_settings']:
quiz = False

Expand All @@ -835,6 +838,7 @@ def index(level, program_id):
level_number=level,
version=version(),
quiz=quiz,
quiz_questions=quiz_questions,
adventures=adventures,
parsons=parsons,
customizations=customizations,
Expand Down
10 changes: 4 additions & 6 deletions hedyweb.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,15 @@ def get_page_translations(self, language):
return d


def render_code_editor_with_tabs(commands, max_level, level_number, version, quiz, loaded_program, adventures, parsons, customizations, hide_cheatsheet, enforce_developers_mode, teacher_adventures, adventure_name):

def render_code_editor_with_tabs(commands, max_level, level_number, version, quiz, quiz_questions, loaded_program, adventures, parsons, customizations, hide_cheatsheet, enforce_developers_mode, teacher_adventures, adventure_name):
arguments_dict = {}

# Meta stuff
arguments_dict['level_nr'] = str(level_number)
arguments_dict['level'] = level_number
arguments_dict['current_page'] = 'hedy'
arguments_dict['prev_level'] = int(
level_number) - 1 if int(level_number) > 1 else None
arguments_dict['next_level'] = int(
level_number) + 1 if int(level_number) < max_level else None
arguments_dict['prev_level'] = int(level_number) - 1 if int(level_number) > 1 else None
arguments_dict['next_level'] = int(level_number) + 1 if int(level_number) < max_level else None
arguments_dict['customizations'] = customizations
arguments_dict['hide_cheatsheet'] = hide_cheatsheet
arguments_dict['enforce_developers_mode'] = enforce_developers_mode
Expand All @@ -71,6 +68,7 @@ def render_code_editor_with_tabs(commands, max_level, level_number, version, qui
arguments_dict['adventure_name'] = adventure_name
arguments_dict['latest'] = version
arguments_dict['quiz'] = quiz
arguments_dict['quiz_questions'] = quiz_questions

return render_template("code-page.html", **arguments_dict, commands=commands)

Expand Down
2 changes: 1 addition & 1 deletion static/css/generated.css

Large diffs are not rendered by default.

22 changes: 2 additions & 20 deletions static/css/quiz-css.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@
color: white;
}

.button-bar {
display: flex;
padding: 1rem;
background-color: #c6f6d5 !important;
justify-content: space-between !important;

}

.center-picture {
background-color: #bee3f8 !important;
display: flex !important;
Expand All @@ -52,7 +44,6 @@
.option-block {
width: 100%;
position: relative;

display: block;
vertical-align:top;
}
Expand All @@ -62,17 +53,8 @@
margin-top: 2rem;
}

.option-block code{
margin-top: -3rem;
}

.option-text{
margin-top: -2rem;
padding: 0.5rem 0.5rem 0.5rem 0.5rem;
}

.option-row:nth-child(1) .option-block:nth-child(1) {
background-color: #c6f6d5;
background-color: #c6f6d5;
border-color: #2d9068;
}

Expand All @@ -87,7 +69,7 @@
}

.option-row:nth-child(2) .option-block:nth-child(2) {
background-color: #CC99C9;
background-color: #CC99C9;
border-color: #af53a9;
}

Expand Down
87 changes: 0 additions & 87 deletions static/js/appbundle.js

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions static/js/appbundle.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions static/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './app';
export * from './auth';
export * from './statistics';
export * from './tutorial';
export * from './quiz';
import './syntaxModesRules';
import './tabs';
import './translating';
Expand Down
225 changes: 225 additions & 0 deletions static/js/quiz.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import {modal} from "./modal";
import {showAchievements} from "./app";

(function() {
$('.option-block').on("click", function () {
$('.option-block').removeClass('active');
$(this).addClass('active');
});
})();


export function startQuiz(level: number) {
$('#start_quiz_container').hide();
$.ajax({
type: 'POST',
url: '/quiz/initialize_user',
data: JSON.stringify({
level: level
}),
contentType: 'application/json',
dataType: 'json'
}).done(function() {
loadQuestQuestion(level, 1);
}).fail(function(err) {
modal.alert(err.responseText, 3000, true);
});
}

export function loadQuestQuestion(level: number, question: number) {
// If we get the request from the feedback page -> hide just to be sure also remove selected answer
$('#quiz_feedback_container').hide();
$('.option-block').removeClass('active');

$.ajax({
type: 'GET',
url: '/quiz/get-question/' + level + '/' + question,
dataType: 'json'
}).done(function(response: any) {
$('#quiz_container').show();
showQuestion(response.question_text);
if (response.code) {
showQuestionCode(response.code);
} else {
$('#quiz_question_code_container').hide();
}
showAnswers(response.mp_choice_options, level, question);
highlightQuestionBar(question);
loadHint(response.hint);
}).fail(function(err) {
modal.alert(err.responseText, 3000, true);
});
}

function showQuestion(question: string) {
$('#quiz_question_title').html(parseCodeBlocks(question));
$('#quiz_question_container').show();
}

function showQuestionCode(code: string) {
$('#quiz_question_code_container').show();
let editor = ace.edit("quiz_question_code");
editor.setValue(code);
editor.clearSelection(); // Make sure the ace editor is not selected
editor.renderer.$cursorLayer.element.style.display = "none"; // Also remove the cursor
}

function showAnswers(options: any, level: number, question: number) {
// This solution is far from beautiful but seems to best approach to parse YAML code down to the editor
// If we find three backticks -> the answer is a code snippet: remove the backticks and show as snippet
$('.option-block').hide();
$('.option-block').removeClass('incorrect-option');
for (let i = 1; i < options.length+1; ++i) {
if (options[i-1].option.includes("```")) {
$('#answer_text_' + i).hide();
let editor = ace.edit('answer_code_' + i);
// This does look like magic: It removes all backticks and the resting newlines, tabs and whitespaces
editor.setValue($.trim(options[i-1].option.replace(new RegExp('`', 'g'),"").replace(/\s+/g, " ")));
editor.clearSelection(); // Make sure the ace editor is not selected
editor.renderer.$cursorLayer.element.style.display = "none"; // Also remove the cursor
$('#answer_code_' + i).show();
// We have to "click" the editor as for some reason the code is always selected?
$('#answer_code_' + i).click();
} else {
$('#answer_text_' + i).html(parseCodeBlocks(options[i - 1].option));
$('#answer_code_' + i).hide();
$('#answer_text_' + i).show();
}
// Set relevant info on container so we can catch this on answering
$('#answer_container_' + i).attr('level', level);
$('#answer_container_' + i).attr('question', question);
$('#answer_container_' + i).show();
}
$('#quiz_answers_container').show();
}

function parseCodeBlocks(option: string) {
while(option.indexOf('`') != -1 ) {
option = option.replace('`', '<code>').replace('`', '</code>');
}
return option;
}

function highlightQuestionBar(question: number) {
$('.step').removeClass('current');
$('.question_header_text_container').hide();
$('#question_header_text_' + question).show();
$('#question_header_' + question).addClass('current');
}

function loadHint(hint: string) {
$('#quiz_question_hint').html(parseCodeBlocks(hint));
$('#quiz_question_hint').hide();
}

export function answerQuestion(answer_number: number) {
let element = $('#answer_container_' + answer_number);
let level = element.attr('level');
let question = element.attr('question');

$.ajax({
type: 'POST',
url: '/quiz/submit_answer/',
data: JSON.stringify({
level: level,
question: question,
answer: answer_number
}),
contentType: 'application/json',
dataType: 'json'
}).done(function(response: any) {
if (response.attempt == 1 && !response.correct) {
highlightFaultyAnswer(answer_number);
showFaultyFeedback(response.feedback);
}
else if (response.correct) {
showFeedback(response, question || "", true);
updateHeader(question || "", true);
} else {
showFeedback(response, question || "", false);
updateHeader(question || "", false);
}
}).fail(function(err) {
modal.alert(err.responseText, 3000, true);
});
}

function highlightFaultyAnswer(answer_number: number) {
$('.option-block').removeClass('active');
$('#answer_container_' + answer_number).addClass('incorrect-option');
}

function showFaultyFeedback(feedback: string) {
$('#quiz_question_hint').html(parseCodeBlocks(feedback));
$('#quiz_question_hint').show();
}

function showFeedback(response: any, question: string, correct: boolean) {
$('#quiz_question_container').hide();
$('#quiz_answers_container').hide();

$('#question_number_container').text(question);
$('#question_length_container').text(response.max_question);

if (response.next_question) {
$('#next_question_number_container').text(parseInt(question) + 1);
$('#next_question_button').attr('onclick', "hedyApp.loadQuestQuestion(" + response.level + "," + (parseInt(question) + 1) + ");");
$('#next_question_button').show();
} else {
$('#next_question_button').hide();
$('#results_button').show();
}

$('#question_feedback_text_container').html(parseCodeBlocks(response.question_text));
$('#feedback_feedback_text').text(response.feedback);
if (response.correct_answer_text.includes("```")) {
let editor = ace.edit("feedback_answer_code");
editor.setValue($.trim(response.correct_answer_text.replace(new RegExp('`', 'g'),"").replace(/\s+/g, " ")));
editor.clearSelection(); // Make sure the ace editor is not selected
editor.renderer.$cursorLayer.element.style.display = "none"; // Also remove the cursor
$('#feedback_correct_answer_container').hide();
$('#feedback_answer_code').show();
} else {
// Replace the first backtick by an opening code block, the second one with a closing tag
$('#feedback_correct_answer_container').html(parseCodeBlocks(response.correct_answer_text));
$('#feedback_answer_code').hide();
$('#feedback_correct_answer_container').show();
}
if (correct) {
$('#feedback_incorrect_container').hide();
$('#feedback_correct_container').show();
} else {
$('#feedback_correct_container').hide();
$('#feedback_incorrect_container').show();
}
$('#quiz_feedback_container').show();
}

function updateHeader(question: string, correct: boolean) {
if (correct) {
$('#question_header_' + question).addClass('check');
} else {
$('#question_header_' + question).addClass('incorrect');
}
}

export function showQuizResults(level: number) {
$.ajax({
type: 'GET',
url: '/quiz/get_results/' + level,
dataType: 'json'
}).done(function(response: any) {
showResults(response);
if (response.achievement) {
showAchievements(response.achievements, false, "");
}
}).fail(function(err) {
modal.alert(err.responseText, 3000, true);
});
}

function showResults(response: any) {
$('#quiz_container').hide();
$('#quiz_end_score').text(response.score);
$('#end_quiz_container').show();
}
2 changes: 2 additions & 0 deletions templates/code-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ <h2 id="tutorial_title" class="text-white"></h2>
{% endblock %}

{% block scripts %}
<link rel="stylesheet" href="{{ static('/css/quiz-css.css')}}">
<link rel="stylesheet" href="{{ static('/css/progress-bar.css')}}">
<script src="{{static('/vendor/ace.js')}}" type="text/javascript" charset="utf-8" crossorigin="anonymous"></script>
<script src="{{static('/vendor/ext-whitespace.js')}}" type="text/javascript" charset="utf-8" crossorigin="anonymous"></script>
<script src="{{static('/vendor/ext-rtl.js')}}" type="text/javascript" charset="utf-8" crossorigin="anonymous"></script>
Expand Down
6 changes: 3 additions & 3 deletions templates/incl-adventure-tabs.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ <h2 class="z-10 my-0 ml-auto pt-8 text-red-500 text-base">{{ _('specific_adventu
<!-- Add the tabtarget for the quiz -->
{% if quiz %}
<div data-tabtarget="quiz" class="hidden">
<h2>{{_('end')}}</h2>
<div>{{_('quiz_description')}}</div>
<input type="submit" class="green-btn h-3/5 mt-4" value="{{ _('go_to_quiz') }}" onclick="hedyApp.load_quiz ({{level_nr}})">
<div>
{% include 'quiz.html' %}
</div>
</div>
{% endif %}
</div>
Expand Down
Loading

0 comments on commit d5edf7b

Please sign in to comment.