Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions client/stylesheets/animations.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
@import "utilities/animation_key_frames";

.animate-flicker {
-webkit-animation: flickerAnimation 3s infinite;
-moz-animation: flickerAnimation 3s infinite;
-o-animation: flickerAnimation 3s infinite;
animation: flickerAnimation 3s infinite;
}

.animate-shake-wrong {
color : red;
animation: shakeWrongAnimation 0.4s ease 0s 2 alternate;
-o-animation: shakeWrongAnimation 0.4s ease 0s 2 alternate;
-moz-animation: shakeWrongAnimation 0.4s ease 0s 2 alternate;
-webkit-animation: shakeWrongAnimation 0.4s ease 0s 2 alternate;
}
11 changes: 11 additions & 0 deletions client/stylesheets/challenge.scss
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,17 @@
color: #bbbbbb;
margin-right: 10px;
}

/* Replace Wrong Word Choices*/
.phraseWord.phraseWordClickable {
&:hover {
background-color: $very-light-gray;
}
}

.phraseWord.wrong {
color: $light-green;
}
/* Report area */

#feedback-area {
Expand Down
62 changes: 62 additions & 0 deletions client/stylesheets/utilities/_animation_key_frames.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,65 @@
/* Animations */

@keyframes shakeWrongAnimation {
0% {
transform: rotate(0deg);
}
33% {
transform: rotate(7deg);
}
66% {
transform: rotate(0deg);
}
100% {
transform: rotate(-7deg);
}
}

@-o-keyframes shakeWrongAnimation {
0% {
transform: rotate(0deg);
}
33% {
transform: rotate(7deg);
}
66% {
transform: rotate(0deg);
}
100% {
transform: rotate(-7deg);
}
}

@-moz-keyframes shakeWrongAnimation {
0% {
transform: rotate(0deg);
}
33% {
transform: rotate(7deg);
}
66% {
transform: rotate(0deg);
}
100% {
transform: rotate(-7deg);
}
}

@-webkit-keyframes shakeWrongAnimation {
0% {
transform: rotate(0deg);
}
33% {
transform: rotate(7deg);
}
66% {
transform: rotate(0deg);
}
100% {
transform: rotate(-7deg);
}
}

@keyframes flickerAnimation {
0% {
opacity: 1;
Expand Down Expand Up @@ -47,3 +107,5 @@
opacity: 1;
}
}


30 changes: 27 additions & 3 deletions client/template/challenge/challenge.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,19 @@ Template.challenge.helpers({
return "Match with correct answer";
case QTYPE.MULTIPLE_CHOICES_TRANSLATION_PIC:
return "Match with correct picture";
case QTYPE.MULTIPLE_CHOICES_MULTIPLE_ANSWERS:
return "Pick all answers that mean the same thing";
case QTYPE.TRUE_FALSE:
return "True or False";
case QTYPE.WORD_PAIRING:
return "Match the pairs";
case QTYPE.REARRANGE:
return "Arrange this phrase in Vietnamese";
case QTYPE.FILL_IN_BLANK:
return "Which word goes into the blank?"
case QTYPE.REPLACE_WRONG_WORD:
return "One of the words in the Vietnamese phrase is wrong. Choose which and its replacement."

}
},
completed: function() {
Expand Down Expand Up @@ -174,15 +181,23 @@ function setupQuestion(lesson, qType) {
case QTYPE.MULTIPLE_CHOICES_TRANSLATION_PIC:
setupMultipleChoicesTranslation(lesson);
break;

case QTYPE.MULTIPLE_CHOICES_MULTIPLE_ANSWERS:
setupMultipleChoicesMultipleAnswers(lesson);
break;

case QTYPE.WORD_PAIRING:
setupWordPairing(lesson);
break;

case QTYPE.REARRANGE:
setupRearrange(lesson);
break;

case QTYPE.FILL_IN_BLANK:
setupFillInBlank(lesson);
break;
case QTYPE.REPLACE_WRONG_WORD:
setupReplaceWrongWord(lesson);
break;
default:
return;
}
Expand Down Expand Up @@ -255,7 +270,7 @@ function challengeComplete(lesson) {
var nextLevel = user.profile.level + 1;
if (user.profile.xp >= LEVEL_XP_REQUIREMENTS[nextLevel]) {
Session.set("reachedNewLevel", true);
Meteor.call('unlockLevel', userId, nextLevel);
Meteor.call("unlockLevel", userId, nextLevel);
}

}
Expand Down Expand Up @@ -283,11 +298,20 @@ answer = function(lesson) {
case QTYPE.MULTIPLE_CHOICES_TRANSLATION_PIC:
answerScore = aMultipleChoicesTranslation(phrase);
break;
case QTYPE.MULTIPLE_CHOICES_MULTIPLE_ANSWERS:
answerScore = aMultipleChoicesMultipleAnswers(phrase);
break;
case QTYPE.WORD_PAIRING:
answerScore = aWordPairing();
case QTYPE.REARRANGE:
answerScore = aRearrange();
break;
case QTYPE.FILL_IN_BLANK:
answerScore = aFillInBlank();
break;
case QTYPE.REPLACE_WRONG_WORD:
answerScore = aReplaceWrongWord();
break;
}

computeProgress(answerScore);
Expand Down
6 changes: 6 additions & 0 deletions client/template/challenge/question_area.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ Template.questionArea.helpers({
case QTYPE.MULTIPLE_CHOICES_TRANSLATION:
case QTYPE.MULTIPLE_CHOICES_TRANSLATION_PIC:
return "qMultipleChoicesTranslation";
case QTYPE.MULTIPLE_CHOICES_MULTIPLE_ANSWERS:
return "qMultipleChoicesMultipleAnswers";
case QTYPE.WORD_PAIRING:
return "qWordPairing";
case QTYPE.REARRANGE:
return "qRearrange";
case QTYPE.FILL_IN_BLANK:
return "qFillInBlank";
case QTYPE.REPLACE_WRONG_WORD:
return "qReplaceWrongWord";
default:
return;
}
Expand Down
12 changes: 12 additions & 0 deletions client/template/challenge/types/q_fill_in_blank.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template name="qFillInBlank">
<p class="phrase-multiple-choices">{{phrase}}</p>
<ul class="small-block-grid-4">
{{#each choices}}
<li>
<div class="choice {{#if checked}}checked{{/if}} {{#if gotFeedback}}{{#if isCorrect}}correct{{else}}wrong{{/if}}{{/if}} " id ="{{displayedWord}}">
{{displayedWord}}
</div>
</li>
{{/each}}
</ul>
</template>
125 changes: 125 additions & 0 deletions client/template/challenge/types/q_fill_in_blank.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
const CHOICE_NUM = 4;

Template.qFillInBlank.helpers({

phrase: function() {
var phrase = this.phrases[Session.get("phraseIndex")];
var prompt = phrase.vnPhraseLower + " _____ " + phrase.vnPhraseUpper;
return prompt;
},

choices: function() {
return Session.get("choices");
},
gotFeedback: function() {
return Session.equals("qState", QSTATE.CONTINUE);
},
});

Template.qFillInBlank.events({

"click .choice": function(ev) {

// Select a choice
var choices = Session.get("choices");
var expectedAnswers = Session.get("expectedAnswers");
var clickWord = ev.target.id;

var clickChoice = _.findWhere(choices, {displayedWord: clickWord});
var checkedChoices = _.where(choices, {
checked: true
});

var ONLY_ALLOW_ONE_ANSWER = true; // placeholder for generic multiple choice template work

if(checkedChoices.length && ONLY_ALLOW_ONE_ANSWER) {
// if clicked on a checked choice, then uncheck it (outside of this block)
// otherwise uncheck the previously checked choice
if(clickChoice.displayedWord !== checkedChoices[0].displayedWord) {
checkedChoices[0].checked = false;
}

}
clickChoice.checked = !clickChoice.checked;

// Update session
Session.set("choices", choices);

// Allow for answering
enableSubmitButton();
}

});

// ----------------------
// Public functions
// ----------------------

setupFillInBlank = function(lesson) {
pickChoices(lesson);
}

aFillInBlank = function(phrase) {
var checkedChoices = _.where(Session.get("choices"), {
checked: true
});
checkedChoices = _.map(checkedChoices, function(answer) {
return answer.displayedWord;
});

var expectedAnswers = Session.get("expectedAnswers");


var unionCheckExpect = _.union(checkedChoices, expectedAnswers);

var answerCorrect = false;
var feedback = "no feedback";
if(expectedAnswers.length === checkedChoices.length &&
unionCheckExpect.length === checkedChoices.length) {
// user checked only the correct answers
answerCorrect = true
} else {
feedback = s.toSentence(expectedAnswers);
}

Session.set("feedback", feedback);

return answerCorrect? CHALLENGE_PROGRESS_CORRECT :
CHALLENGE_PROGRESS_WRONG;
}

// ----------------------
// Private functions
// ----------------------

function pickChoices(lesson) {
var phraseIndex = Session.get("phraseIndex");
var phrase = lesson.phrases[phraseIndex];

var expectedAnswers = new Array();
expectedAnswers.push(phrase.answer);

var choices = phrase.wrongChoices;


choices = _.map(choices, function(choice) {
return {
checked: false,
isCorrect: false,
displayedWord: choice,
};
});

// push answer object onto the choices
choices.push( {
checked: false,
isCorrect: true,
displayedWord: phrase.answer,
});

choices = _.shuffle(choices);

Session.set("choices", choices);
Session.set("expectedAnswers", expectedAnswers);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template name="qMultipleChoicesMultipleAnswers">
<p class="phrase-multiple-choices">{{phrase}}</p>
<ul class="small-block-grid-4">
{{#each choices}}
<li>
<div class="choice {{#if checked}}checked{{/if}} {{#if gotFeedback}}{{#if isCorrect}}correct{{else}}wrong{{/if}}{{/if}} " id ="{{displayedWord}}">
{{displayedWord}}
</div>
</li>
{{/each}}
</ul>
</template>
Loading