(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); } } )();