(function (){
_.defaults(Exercises, {
khanExercisesUrlBase: "/khan-exercises/",
getCurrentFramework: function (userExerciseOverride){
return (userExerciseOverride || userExercise).exerciseModel.fileName? "khan-exercises": "perseus";
}
}
);
_.extend(Exercises, {
guessLog: undefined,
userActivityLog: undefined}
);
var PerseusBridge = Exercises.PerseusBridge, localMode = Exercises.localMode, originalCheckAnswerText, userExercise, problemNum, answeredCorrectly, hintsAreFree, attempts, numHints, hintsUsed, lastAttemptOrHint;
$(Exercises).bind("problemTemplateRendered", problemTemplateRendered).bind("newProblem", newProblem).bind("hintUsed", hintUsed).bind("readyForNextProblem", readyForNextProblem).bind("warning", warning).bind("upcomingExercise", upcomingExercise).bind("gotoNextProblem", gotoNextProblem).bind("updateUserExercise", updateUserExercise).bind("clearExistingProblem", clearExistingProblem);
function problemTemplateRendered(){
$("#issue-throbber").attr("src", Exercises.khanExercisesUrlBase + "css/images/throbber.gif");
$("#positive-reinforcement").hide();
if (localMode) {
$("#positive-reinforcement > img").attr("src", Exercises.khanExercisesUrlBase + "images/face-smiley.png");
}
originalCheckAnswerText = $("#check-answer-button").val();
$("#check-answer-button").click(handleCheckAnswer);
$("#answerform").submit(handleCheckAnswer);
$("#skip-question-button").click({
skipped: true }
, handleCheckAnswer);
$("#hint").click(handleHint);
$("#next-question-button").click(function (){
$(Exercises).trigger("gotoNextProblem");
$(this).attr("disabled", true ).addClass("buttonDisabled");
}
);
$("#positive-reinforcement").click(function (){
$("#next-question-button").click();
}
);
$("#warning-bar-close a").click(function (e){
e.preventDefault();
$("#warning-bar").fadeOut("slow");
}
);
$("#scratchpad-show").click(function (e){
e.preventDefault();
Khan.scratchpad.toggle();
if (!localMode && userExercise.user) {
window.localStorage["scratchpad:" + userExercise.user] = Khan.scratchpad.isVisible();
}
}
);
$(PerseusBridge).trigger("problemTemplateRendered");
$(Khan).trigger("problemTemplateRendered");
}
function newProblem(e, data){
Exercises.guessLog = [] ;
Exercises.userActivityLog = [] ;
answeredCorrectly = false , hintsAreFree = false , attempts = 0;
numHints = data.numHints;
hintsUsed = 0;
lastAttemptOrHint = new Date().getTime();
$("#hint").attr("disabled", numHints === 0);
}
function handleCheckAnswer(e){
var framework = Exercises.getCurrentFramework();
var skipped = e.data && e.data.skipped;
var score;
if (framework === "perseus") {
score = PerseusBridge.scoreInput();
}
else if (framework === "khan-exercises") {
score = Khan.scoreInput();
}
if (score.empty && !skipped) {
return false ;
}
var curTime = new Date().getTime();
var timeTaken = Math.round((curTime - lastAttemptOrHint) / 1000);
lastAttemptOrHint = curTime;
Exercises.guessLog.push(score.guess);
Exercises.userActivityLog.push([score.correct? "correct-activity": "incorrect-activity", JSON.stringify(score.guess), timeTaken] );
if (score.correct) {
answeredCorrectly = true ;
$(Exercises).trigger("problemDone");
}
if (Exercises.assessmentMode) {
disableCheckAnswer();
}
else if (score.correct) {
$("#check-answer-button").hide();
$("#check-answer-results > p").hide();
_AN_Call_show("show", $("#next-question-button").removeAttr("disabled").removeClass("buttonDisabled")).focus();
_AN_Call_show("show", $("#positive-reinforcement"));
}
else {
$("#check-answer-button").parent().effect("shake", {
times: 3,
distance: 5}
, 480).val("Try Again");
if (score.message != null ) {
_AN_Call_show("show", $("#check-answer-results > p").html(score.message).tmpl());
}
else {
$("#check-answer-results > p").hide();
}
if (framework === "perseus") {
}
else if (framework === "khan-exercises") {
$(Khan).trigger("refocusSolutionInput");
}
}
if (!hintsAreFree) {
hintsAreFree = true ;
$(".hint-box").css("position", "relative").animate({
top: -10}
, 250).find(".info-box-header").slideUp(250).end().find("#hint").removeClass("orange").addClass("green");
updateHintButtonText();
}
$(Exercises).trigger("checkAnswer", {
correct: score.correct,
fast: !localMode && userExercise.secondsPerFastProblem >= timeTaken}
);
if (localMode) {
return false ;
}
var data = buildAttemptData(score.correct, ++attempts, JSON.stringify(score.guess), timeTaken, skipped);
request("problems/" + problemNum + "/attempt", data).fail(function (xhr){
$(Exercises).trigger("attemptError");
if (xhr && xhr.readyState === 0) {
return ;
}
$("#problem-and-answer").css("visibility", "hidden");
$(Exercises).trigger("warning", "This page is out of date. You need to refresh, but " + "don't worry, you haven't lost progress. If you think " + "this is a mistake, tell us.");
}
);
return false ;
}
function handleHint(){
var framework = Exercises.getCurrentFramework();
if (framework === "perseus") {
$(PerseusBridge).trigger("showHint");
}
else if (framework === "khan-exercises") {
$(Khan).trigger("showHint");
}
}
function hintUsed(){
Khan.scratchpad.resize();
hintsUsed++ ;
updateHintButtonText();
if (hintsUsed === numHints) {
$("#hint").attr("disabled", true );
$(Exercises).trigger("allHintsUsed");
}
var curTime = new Date().getTime();
var timeTaken = Math.round((curTime - lastAttemptOrHint) / 1000);
lastAttemptOrHint = curTime;
Exercises.userActivityLog.push(["hint-activity", "0", timeTaken] );
if (!localMode && !userExercise.readOnly && !answeredCorrectly) {
request("problems/" + problemNum + "/hint", buildAttemptData(false , attempts, "hint", timeTaken, false ));
}
}
function updateHintButtonText(){
var $hintButton = $("#hint");
var hintsLeft = numHints - hintsUsed;
if (hintsAreFree) {
$hintButton.val(hintsUsed? "Show next step (" + hintsLeft + " left)": "Show solution");
}
else {
$hintButton.val("I'd like another hint (" + (hintsLeft === 1? "1 hint left": hintsLeft + " hints left") + ")");
}
}
function buildAttemptData(correct, attemptNum, attemptContent, timeTaken, skipped){
var framework = Exercises.getCurrentFramework();
var data;
if (framework === "perseus") {
data = PerseusBridge.getSeedInfo();
}
else if (framework === "khan-exercises") {
data = Khan.getSeedInfo();
}
_.extend(data, {
casing: "camel",
complete: correct? 1: 0,
count_hints: hintsUsed,
time_taken: timeTaken,
attempt_number: attemptNum,
attempt_content: attemptContent,
review_mode: Exercises.reviewMode? 1: 0,
topic_mode: (!Exercises.reviewMode && !Exercises.practiceMode)? 1: 0,
card: JSON.stringify(Exercises.currentCard),
stack_uid: Exercises.completeStack.getUid(),
topic_id: Exercises.topic && Exercises.topic.id,
cards_done: _AN_Read_length("length", Exercises.completeStack),
cards_left: _AN_Read_length("length", Exercises.incompleteStack) - 1,
user_assessment_key: Exercises.userAssessmentKey,
skipped: skipped? 1: 0}
);
return data;
}
var attemptHintQueue = jQuery({
}
);
$(window).unload(function (){
if (attemptHintQueue.queue().length) {
$(Exercises).trigger("attemptError");
}
}
);
function request(method, data){
var apiBaseUrl = (Exercises.assessmentMode? "/api/v1/user/assessment/exercises": "/api/v1/user/exercises");
var params = {
url: apiBaseUrl + "/" + userExercise.exerciseModel.name + "/" + method,
type: "POST",
data: data,
dataType: "json"}
;
var deferred = $.Deferred();
attemptHintQueue.queue(function (next){
$.ajax(params).then(function (data, textStatus, jqXHR){
deferred.resolve(data, textStatus, jqXHR);
$(Exercises).trigger("updateUserExercise", {
userExercise: data,
source: "serverResponse"}
);
}
, function (jqXHR, textStatus, errorThrown){
deferred.reject(jqXHR, textStatus, errorThrown);
attemptHintQueue.clearQueue();
}
).always(function (){
$(Exercises).trigger("apiRequestEnded");
next();
}
);
}
);
$(Exercises).trigger("apiRequestStarted");
return deferred.promise();
}
function readyForNextProblem(e, data){
userExercise = data.userExercise;
problemNum = userExercise.totalDone + 1;
$(Exercises).trigger("updateUserExercise", {
userExercise: userExercise}
);
var framework = Exercises.getCurrentFramework();
if (framework === "perseus") {
$(PerseusBridge).trigger("readyForNextProblem", data);
}
else if (framework === "khan-exercises") {
$(Khan).trigger("readyForNextProblem", data);
}
}
function warning(e, message, showClose){
$(function (){
var warningBar = $("#warning-bar");
$("#warning-bar-content").html(message);
if (showClose) {
_AN_Call_show("show", warningBar.addClass("warning").children("#warning-bar-close"));
}
else {
warningBar.addClass("error").children("#warning-bar-close").hide();
}
warningBar.fadeIn("fast");
}
);
}
function upcomingExercise(e, data){
var framework = Exercises.getCurrentFramework(data.userExercise);
if (framework === "perseus") {
$(PerseusBridge).trigger("upcomingExercise", data);
}
else if (framework === "khan-exercises") {
$(Khan).trigger("upcomingExercise", data);
}
}
function gotoNextProblem(){
var framework = Exercises.getCurrentFramework();
if (framework === "perseus") {
}
else if (framework === "khan-exercises") {
$(Khan).trigger("gotoNextProblem");
}
}
function updateUserExercise(e, data){
var framework = Exercises.getCurrentFramework();
if (framework === "perseus") {
}
else if (framework === "khan-exercises") {
$(Khan).trigger("updateUserExercise", data);
}
}
function enableCheckAnswer(){
$("#check-answer-button").removeAttr("disabled").removeClass("buttonDisabled").val(originalCheckAnswerText);
$("#skip-question-button").removeAttr("disabled").removeClass("buttonDisabled");
}
function disableCheckAnswer(){
$("#check-answer-button").attr("disabled", "disabled").addClass("buttonDisabled").val("Please wait...");
$("#skip-question-button").attr("disabled", "disabled").addClass("buttonDisabled");
}
function clearExistingProblem(){
var framework = Exercises.getCurrentFramework();
enableCheckAnswer();
$("#happy").hide();
if (!$("#examples-show").data("show")) {
$("#examples-show").click();
}
_AN_Call_show("show", $("#check-answer-button"));
$("#next-question-button").blur().hide();
$("#positive-reinforcement").hide();
if (framework === "perseus") {
}
else if (framework === "khan-exercises") {
$(Khan).trigger("cleanupProblem");
}
$("#workarea, #hintsarea, #solutionarea").empty();
$("#solutionarea").off(".emptyAnswer");
$("#hint").removeClass("green").addClass("orange").val("I'd like a hint").data("buttonText", false ).appendTo("#get-hint-button-container");
_AN_Call_show("show", $(".hint-box").css("top", 0).find(".info-box-header"));
_AN_Call_clear("clear", Khan.scratchpad);
}
}
)();