forked from Open-CT/openct-tasks
3432 lines
138 KiB
JavaScript
3432 lines
138 KiB
JavaScript
(function () {
|
||
|
||
'use strict';
|
||
|
||
function getUrlParameterByName(name) {
|
||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
||
results = regex.exec(location.href);
|
||
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||
}
|
||
|
||
function isCrossDomain() {
|
||
function isInIframe() {
|
||
try {
|
||
return window.self !== window.top;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
function isSameDomain() {
|
||
var res = false;
|
||
function doNothing(document){}
|
||
try{
|
||
res = !! parent.document;
|
||
} catch(e){
|
||
res = false;
|
||
}
|
||
return res;
|
||
}
|
||
return isInIframe() && !isSameDomain();
|
||
}
|
||
|
||
var platform;
|
||
|
||
if (!isCrossDomain()) {
|
||
|
||
/* Implementation of a platform proxy for the task iframe. This object is always
|
||
* available, but is effective only when setPlatform is called with a true
|
||
* platform object.
|
||
*/
|
||
|
||
platform = {
|
||
registered_objects: [],
|
||
parent_platform: null,
|
||
initFailed: false,
|
||
setPlatform: function(platformArg) {
|
||
platform.parent_platform = platformArg;
|
||
},
|
||
trigger: function(event, content) {
|
||
for (var i = 0; i < platform.registered_objects.length; i++) {
|
||
var object = platform.registered_objects[i];
|
||
if (typeof (object[event]) != "undefined") {
|
||
object[event].apply(object, content);
|
||
}
|
||
}
|
||
},
|
||
subscribe: function(object) {
|
||
this.registered_objects.push(object);
|
||
},
|
||
unsubscribe: function(object) {
|
||
var index = this.registered_objects.indexOf(object);
|
||
if (index != -1) {
|
||
this.registered_objects.splice(index, 1);
|
||
}
|
||
},
|
||
validate: function(mode, success, error) {
|
||
// TODO: this case is a bit blur...
|
||
var res = platform.parent_platform.validate(mode, success, error);
|
||
this.trigger('validate', [mode]);
|
||
return res;
|
||
},
|
||
showView: function(views, success, error) {
|
||
return platform.parent_platform.showView(views, success, error);
|
||
},
|
||
askHint: function(platformToken, success, error) {
|
||
return platform.parent_platform.askHint(platformToken, success, error);
|
||
},
|
||
updateHeight: function(height, success, error) {
|
||
return platform.parent_platform.updateDisplay({height: height}, success, error);
|
||
},
|
||
updateDisplay: function(data, success, error) {
|
||
return platform.parent_platform.updateDisplay(data, success, error);
|
||
},
|
||
getTaskParams: function(key, defaultValue, success, error) {
|
||
return platform.parent_platform.getTaskParams(key, defaultValue, success, error);
|
||
},
|
||
openUrl: function(url, success, error) {
|
||
return platform.parent_platform.openUrl(url, success, error);
|
||
},
|
||
initCallback: function(callback) {
|
||
this.initCallbackFun = callback;
|
||
if (platform.initDone) {
|
||
callback();
|
||
}
|
||
},
|
||
initWithTask: function(task) {
|
||
platform.task = task;
|
||
window.task = task;
|
||
platform.initDone = true;
|
||
if (platform.initCallbackFun) {
|
||
platform.initCallbackFun();
|
||
}
|
||
}
|
||
};
|
||
|
||
} else {
|
||
|
||
// cross-domain version, depends on jschannel
|
||
platform = {};
|
||
var callAndTrigger = function(fun, triggerName, error, args) {
|
||
return function() {
|
||
try {
|
||
platform.trigger(triggerName, args);
|
||
fun(arguments);
|
||
} catch(e) {
|
||
error(e.toString()+'\n'+e.stack);
|
||
}
|
||
};
|
||
};
|
||
platform.ready = false;
|
||
platform.initFailed = false;
|
||
platform.initWithTask = function(task) {
|
||
if (typeof Channel === 'undefined') {
|
||
platform.initFailed = true;
|
||
console.error('cannot init task if jschannel is not present');
|
||
return;
|
||
}
|
||
|
||
var previousHeights = [];
|
||
var getHeightFiltered = function(success, error) {
|
||
// If the new height has already been returned just before the current
|
||
// height, we're in a loop between two heights, possibly because of a
|
||
// scrollbar.
|
||
// In that case we want to keep the largest of the two heights.
|
||
if(!task.getHeight) { error('task.getHeight not defined yet'); }
|
||
task.getHeight(function(h) {
|
||
if((previousHeights.length == 2) &&
|
||
(previousHeights[0] == h) &&
|
||
(previousHeights[1] >= h)) {
|
||
success(previousHeights[1]);
|
||
return;
|
||
}
|
||
previousHeights.push(h);
|
||
previousHeights = previousHeights.slice(-2);
|
||
success(h);
|
||
}, error);
|
||
}
|
||
|
||
var gradeAnswer = function(params, success, error) {
|
||
var newSuccess = function(score, message, scoreToken) {
|
||
success([score, message, scoreToken]);
|
||
};
|
||
if (typeof task.gradeAnswer === 'function') {
|
||
task.gradeAnswer(params[0], params[1], newSuccess, error);
|
||
} else {
|
||
window.grader.gradeTask(params[0], params[1], newSuccess, error);
|
||
}
|
||
};
|
||
var channelId = getUrlParameterByName('channelId');
|
||
var chan = Channel.build({window: window.parent, origin: "*", scope: channelId, onReady: function() {platform.ready = true;}});
|
||
platform.chan = chan;
|
||
platform.task = task;
|
||
platform.channelId = channelId;
|
||
chan.bind('task.load', function(trans, views) {task.load(views, callAndTrigger(trans.complete, 'load', trans.error, [views]), trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.unload', function(trans) {task.unload(callAndTrigger(trans.complete, 'unload', trans.error, null), trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.getHeight', function(trans) {getHeightFiltered(trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.getMetaData', function(trans) {task.getMetaData(trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.getViews', function(trans) {task.getViews(trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.showViews', function(trans, views) {task.showViews(views, callAndTrigger(trans.complete, 'showViews', trans.error, [views]), trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.updateToken', function(trans, token) {task.updateToken(token, trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.reloadAnswer', function(trans, answer) {task.reloadAnswer(answer, callAndTrigger(trans.complete, 'reloadAnswer', trans.error, [answer]), trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.getAnswer', function(trans) {task.getAnswer(trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.getState', function(trans) {task.getState(trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.getResources', function(trans) {task.getResources(trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.reloadState', function(trans, state) {task.reloadState(state, callAndTrigger(trans.complete, 'reloadState', trans.error, [state]), trans.error);trans.delayReturn(true);});
|
||
chan.bind('grader.gradeTask', function(trans, params) {gradeAnswer(params, trans.complete, trans.error);trans.delayReturn(true);});
|
||
chan.bind('task.gradeAnswer', function(trans, params) {gradeAnswer(params, trans.complete, trans.error);trans.delayReturn(true);});
|
||
};
|
||
|
||
platform.registered_objects = [];
|
||
platform.trigger = function(event, content) {
|
||
for (var i = 0; i < platform.registered_objects.length; i++) {
|
||
var object = platform.registered_objects[i];
|
||
if (typeof object[event] !== "undefined") {
|
||
object[event].apply(object, content);
|
||
}
|
||
}
|
||
};
|
||
platform.subscribe = function(object) {
|
||
platform.registered_objects.push(object);
|
||
};
|
||
platform.unsubscribe = function(object) {
|
||
var index = platform.registered_objects.indexOf(object);
|
||
if (index != -1) {
|
||
platform.registered_objects.splice(index, 1);
|
||
}
|
||
};
|
||
platform.stop = function() {
|
||
platform.chan.destroy();
|
||
};
|
||
platform.validate = function (sMode, success, error) {
|
||
if (!success) success = function(){}; // not mandatory, as most code doesn't use it
|
||
if (!error) error = function() {console.error(arguments);};
|
||
platform.chan.call({method: "platform.validate",
|
||
params: sMode,
|
||
error: error,
|
||
success: callAndTrigger(success, 'validate', error, [sMode])
|
||
});
|
||
};
|
||
platform.getTaskParams = function(key, defaultValue, success, error) {
|
||
if (!success) success = function(){};
|
||
if (!error) error = function() {console.error(arguments);};
|
||
platform.chan.call({method: "platform.getTaskParams",
|
||
params: [key, defaultValue],
|
||
error: error,
|
||
success: success
|
||
});
|
||
};
|
||
platform.showView = function(views, success, error) {
|
||
if (!success) success = function(){};
|
||
if (!error) error = function() {console.error(arguments);};
|
||
platform.chan.call({method: "platform.showView",
|
||
params: views,
|
||
error: error,
|
||
success: success
|
||
});
|
||
};
|
||
platform.askHint = function(platformToken, success, error) {
|
||
if (!success) success = function(){};
|
||
if (!error) error = function() {console.error(arguments);};
|
||
platform.chan.call({method: "platform.askHint",
|
||
params: platformToken,
|
||
error: error,
|
||
success: success
|
||
});
|
||
};
|
||
platform.updateHeight = function(height, success, error) {
|
||
// Legacy
|
||
platform.updateDisplay({height: height}, success, error);
|
||
};
|
||
platform.updateDisplay = function(data, success, error) {
|
||
if (!success) success = function(){};
|
||
if (!error) error = function() {console.error(arguments);};
|
||
platform.chan.call({method: "platform.updateDisplay",
|
||
params: data,
|
||
error: error,
|
||
success: success
|
||
});
|
||
};
|
||
platform.openUrl = function(url, success, error) {
|
||
if (!success) success = function(){};
|
||
if (!error) error = function() {console.error(arguments);};
|
||
platform.chan.call({method: "platform.openUrl",
|
||
params: url,
|
||
error: error,
|
||
success: success
|
||
});
|
||
};
|
||
}
|
||
|
||
window.platform = platform;
|
||
|
||
}());
|
||
|
||
(function() {
|
||
|
||
'use strict';
|
||
|
||
/*
|
||
* Implementation of the displayHelper API.
|
||
*
|
||
* Copyright (c) 2012 Association France-ioi, MIT License http://opensource.org/licenses/MIT
|
||
*
|
||
* See documentation for more information.
|
||
*/
|
||
|
||
window.displayHelper = {
|
||
loaded: false,
|
||
timeLoaded: 0,
|
||
checkAnswerInterval: null,
|
||
prevAnswer: '',
|
||
readOnly: false,
|
||
savedAnswer: '',
|
||
submittedAnswer: '',
|
||
submittedScore: 0,
|
||
hasAnswerChanged: true,
|
||
taskSelector: '#task',
|
||
hideValidateButton: false,
|
||
hideRestartButton: false,
|
||
confirmRestartAll: true,
|
||
showScore: false,
|
||
refreshMessages: true,
|
||
stoppedShowingResult: false,
|
||
previousMessages: {},
|
||
popupMessageShown: false,
|
||
|
||
thresholds: {},
|
||
// Legacy settings for old tasks ; new ones are expected to use thresholds
|
||
thresholdEasy: 60,
|
||
thresholdMedium: 120,
|
||
|
||
timeoutMinutes: 5,
|
||
avatarType: "beaver",
|
||
bUseFullWidth: false,
|
||
|
||
hasLevels: false,
|
||
pointsAsStars: true, // TODO: false as default
|
||
unlockedLevels: 4,
|
||
neverHadHard: false,
|
||
showMultiversionNotice: false,
|
||
taskLevel: '',
|
||
|
||
// Defaults
|
||
levels: ['easy', 'medium', 'hard'],
|
||
levelsIdx: { easy: 0, medium: 1, hard: 2 },
|
||
maxStars: 4,
|
||
popupMessageHandler: null,
|
||
|
||
formatTranslation: function(s, args) { return s.replace(/\{([^}]+)\}/g, function(_, match){ return args[match]; }); },
|
||
|
||
languageStrings: {
|
||
fr: {
|
||
version: "Version",
|
||
levelVersionName_easy: "version facile",
|
||
levelVersionName_medium: "version moyenne",
|
||
levelVersionName_hard: "version difficile",
|
||
levelVersionName_easy_stars: "version à 2 étoiles",
|
||
levelVersionName_medium_stars: "version à 3 étoiles",
|
||
levelVersionName_hard_stars: "version à 4 étoiles",
|
||
levelName_easy: "Facile",
|
||
levelName_medium: "Moyen",
|
||
levelName_hard: "Difficile",
|
||
warningTimeout: "<p>Attention, cela fait plus de {0} minutes que vous êtes sur cette question.</p><p>Vous devriez sans doute changer de sujet, en cliquant sur le bouton tout en haut à droite.</p>",
|
||
alright: "D'accord",
|
||
moveOn: "Passer à la suite",
|
||
solvedMoveOn: "Vous avez entièrement résolu cette question, passez à une autre question.",
|
||
confirmRestart: "Êtes-vous certain de vouloir recommencer cette version ?",
|
||
yes: "Oui",
|
||
no: "Non",
|
||
tryHardLevel: "Nous vous proposons d'essayer la version 4 étoiles.",
|
||
tryMediumLevel: "Nous vous proposons d'essayer la version 3 étoiles.",
|
||
tryNextTask: "Nous vous proposons de passer au sujet suivant. S'il vous reste du temps, vous reviendrez plus tard essayer la version suivante.",
|
||
yourScoreIsNow: "Votre score est maintenant :",
|
||
worseScoreStays: "C'est moins bien qu'avant ; votre score reste :",
|
||
scoreStays: "Votre score reste le même :",
|
||
score: "Score :",
|
||
noPointsForLevel: "Vous n'avez pas encore de points sur cette version.",
|
||
outOf: " sur ",
|
||
tryToDoBetterOrChangeTask: "Essayez de faire encore mieux, ou passez à une autre question.",
|
||
tryToDoBetterOrMoveToNextLevel: "Essayez de faire encore mieux, ou passez à une version plus difficile.",
|
||
bestPossibleScoreCongrats: "C'est le meilleur score possible sur ce sujet ; félicitations !",
|
||
forMorePointsMoveToNextLevel: "Pour obtenir plus de points, passez à une version plus difficile.",
|
||
youDidBetterBefore: "Vous aviez fait mieux avant.",
|
||
scoreStays2: "Votre score reste le même.",
|
||
reloadBestAnswer: "Rechargez votre meilleure réponse.",
|
||
noAnswerSaved: "Aucune réponse actuellement enregistrée pour cette version.",
|
||
validate: "Valider",
|
||
restart: "Recommencer",
|
||
harderLevelSolved: "Attention : vous avez déjà résolu une version plus difficile. Vous ne pourrez pas gagner de points supplémentaires avec cette version.",
|
||
showLevelAnyway: "Voir quand même",
|
||
scoreObtained: "Score obtenu :",
|
||
hardVersionTakesTime: "Résoudre une {0} peut vous prendre beaucoup de temps ; songez en priorité à répondre aux questions en {1} pour gagner des points rapidement.",
|
||
illKeepThatInMind: "J'y prendrai garde",
|
||
harderLevelAvailable: "Notez que pour cette question, vous pouvez résoudre directement une version plus difficile que celle-ci.",
|
||
lockedLevel: "Cette version est verrouillée. Résolvez la précédente pour l'afficher !",
|
||
gradeThisAnswer: "Évaluer cette réponse",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "Enregistrer votre réponse",
|
||
answerSavedModifyOrCancelIt: "Votre réponse a été enregistrée. Vous pouvez la modifier, ou bien {0} et recommencer.",
|
||
cancelIt: "l'annuler",
|
||
warningDifferentAnswerSaved: "Attention : une réponse différente est enregistrée.",
|
||
youMay: "Vous pouvez {0}.",
|
||
reloadIt: "la recharger",
|
||
saveThisNewAnswer: "Enregistrer cette nouvelle réponse",
|
||
|
||
gradingInProgress: "Évaluation en cours",
|
||
scoreIs: "Votre score est de :",
|
||
point: "point",
|
||
points: "points",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "Le concours étant terminé, votre réponse n'est pas enregistrée et votre score reste de :",
|
||
scoreWouldBecome: "Avec cette réponse, votre score serait :",
|
||
reloadValidAnswer: "Rechargez la réponse validée.",
|
||
contestOverAnswerNotSaved: "Le concours est terminé : votre réponse n'est pas enregistrée.",
|
||
scoreWouldStay: "Avec cette réponse, votre score resterait le même :",
|
||
answerNotSavedContestOver: "Le concours étant terminé, votre réponse n'a pas été enregistrée. Vous pouvez {0}.",
|
||
reloadSubmittedAnswer: "recharger la réponse que vous avez soumise",
|
||
difficultyWarning: "<strong>Attention :</strong> résoudre cette version prend du temps.<br/>Vous pourrez résoudre bien plus rapidement les versions 2 et 3 étoiles d'autres sujets.",
|
||
enemyWarning: "<strong>Attention :</strong> dans ce défi, l'ordinateur vous empêchera de trouver la solution par hasard."
|
||
},
|
||
en: {
|
||
version: "版本",
|
||
levelVersionName_easy: "easy version",
|
||
levelVersionName_medium: "medium version",
|
||
levelVersionName_hard: "hard version",
|
||
levelVersionName_easy_stars: "2 stars version",
|
||
levelVersionName_medium_stars: "3 stars version",
|
||
levelVersionName_hard_stars: "4 stars version",
|
||
levelName_easy: "Easy",
|
||
levelName_medium: "Medium",
|
||
levelName_hard: "Hard",
|
||
warningTimeout: "<p>Warning, it has been more than {0} minutes since you started working on this task.</p><p>You should probably switch to a diffrent task, by clicking on the button on the top-right.</p>",
|
||
alright: "Alright",
|
||
moveOn: "Move on",
|
||
solvedMoveOn: "You solved this task completely, move on to another task.",
|
||
confirmRestart: "Are you sure you want to restart this version?",
|
||
yes: "Yes",
|
||
no: "No",
|
||
tryHardLevel: "We suggest you try the 4 stars version.",
|
||
tryMediumLevel: "We suggest you try the 3 stars version.",
|
||
tryNextTask: "We suggest you try the next task. If you still have time, come back later and try the next version of this task.",
|
||
yourScoreIsNow: "Your score is now:",
|
||
worseScoreStays: "This is not as good as before. Your score stays:",
|
||
scoreStays: "Your score stays the same:",
|
||
score: "Score:",
|
||
noPointsForLevel: "You have not received any points yet on this version.",
|
||
outOf: " out of ",
|
||
tryToDoBetterOrChangeTask: "Try to do even better, or move on to another task.",
|
||
tryToDoBetterOrMoveToNextLevel: "Try to do even better, or move on to a more difficult version.",
|
||
bestPossibleScoreCongrats: "This is the best possible score on this task, congratulations!",
|
||
forMorePointsMoveToNextLevel: "要想获得更多的分数,请进入更难的版本。",
|
||
youDidBetterBefore: "You did better before.",
|
||
scoreStays2: "你的得分保持不变",
|
||
reloadBestAnswer: "重新加载你的最佳答案。",
|
||
noAnswerSaved: "到目前为止,这个版本还没有答案。",
|
||
validate: "Validate",
|
||
restart: "重新开始",
|
||
harderLevelSolved: "Warning: you already solved a harder version of this task. You won't be able to obtain extra points with this version.",
|
||
showLevelAnyway: "Show it to me anyways.",
|
||
scoreObtained: "得分:",
|
||
hardVersionTakesTime: "Solving a {0} can take a lot of time. Consider working on the {1} to gain points quickly.",
|
||
illKeepThatInMind: "I'll consider it.",
|
||
harderLevelAvailable: "Note that for this task, you may try to directly work on a harder version than this one.",
|
||
lockedLevel: "This version is locked. Solve the previous version to display it!",
|
||
gradeThisAnswer: "验证一下",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "Save this answer",
|
||
answerSavedModifyOrCancelIt: "Your answer has been saved. You can modify it, or {0} and restart.",
|
||
cancelIt: "cancel it",
|
||
warningDifferentAnswerSaved: "Warning: a different answer was saved before.",
|
||
youMay: "You may {0}.",
|
||
reloadIt: "reload it",
|
||
saveThisNewAnswer: "Save this new answer",
|
||
|
||
gradingInProgress: "Grading in process",
|
||
scoreIs: "Your score is:",
|
||
point: "point",
|
||
points: "points",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "The contest being over, your new answer was not saved and your score stays:",
|
||
scoreWouldBecome: "With this answer, your score would be:",
|
||
reloadValidAnswer: "Reload the validated answer.",
|
||
contestOverAnswerNotSaved: "The contest being over, your new answer was not saved.",
|
||
scoreWouldStay: "With this answer, your score would stay the same:",
|
||
answerNotSavedContestOver: "The contest being over, your answer was not saved. You may {0}.",
|
||
reloadSubmittedAnswer: "reload the validated answer",
|
||
difficultyWarning: "<strong>提醒:</strong> 解决这个版本很耗费时间。<br/>解决2星或3星版本的任务可以更快哦。",
|
||
enemyWarning: "<strong>Warning:</strong> in this challenge, the computer will make sure you don't find the solution by chance."
|
||
},
|
||
sv: {
|
||
version: "Version",
|
||
levelVersionName_easy: "lätt version",
|
||
levelVersionName_medium: "medelsvår version",
|
||
levelVersionName_hard: "svår version",
|
||
levelVersionName_easy_stars: "2-stjärnig version",
|
||
levelVersionName_medium_stars: "3-stjärnig version",
|
||
levelVersionName_hard_stars: "4-stjärnig version",
|
||
levelName_easy: "Lätt",
|
||
levelName_medium: "Medelsvår",
|
||
levelName_hard: "Svår",
|
||
warningTimeout: "<p>Varning: det har gått mer än {0} minuter sedan du började med den här uppgiften. </p><p>Du borde kanske byta till en annan uppgift, genom att klicka på knappen uppe till höger.</p>",
|
||
alright: "Okej",
|
||
moveOn: "Gå vidare",
|
||
solvedMoveOn: "Du löste uppgiften helt! Gå nu vidare till en annan uppgift.",
|
||
confirmRestart: "Är du säker på att du vill börja om med den här versionen?",
|
||
yes: "Ja",
|
||
no: "Nej",
|
||
tryHardLevel: "Vi föreslår att du provar den 4-stjärniga versionen.",
|
||
tryMediumLevel: "Vi föreslår att du provar den 3-stjärniga versionen.",
|
||
tryNextTask: "Vi föreslår att du provar nästa uppgift. Kom tillbaka senare och prova en svårare version av den här uppgiften.",
|
||
yourScoreIsNow: "Din poäng är nu:",
|
||
worseScoreStays: "Det är inte lika bra som tidigare. Poängen fortfarande:",
|
||
scoreStays: "Din poäng är fortfarande:",
|
||
score: "Poäng:",
|
||
noPointsForLevel: "Du har inte fått några poäng än på den här versionen.",
|
||
outOf: " utav ",
|
||
tryToDoBetterOrChangeTask: "Försök klara det ännu bättre, eller gå vidare till en annan uppgift.",
|
||
tryToDoBetterOrMoveToNextLevel: "Försök klara det ännu bättre, eller gå vidare till en svårare version.",
|
||
bestPossibleScoreCongrats: "Detta är högsta möjliga poäng på den här uppgiften. Grattis!",
|
||
forMorePointsMoveToNextLevel: "För att få mer poäng, gå vidare till en svårare version av den här uppgiften.",
|
||
youDidBetterBefore: "Det gick bättre tidigare.",
|
||
scoreStays2: "Din poäng ändras inte.",
|
||
reloadBestAnswer: "Ladda in ditt bästa svar.",
|
||
noAnswerSaved: "No answer saved so far for this version.",
|
||
validate: "Kontrollera svaret",
|
||
restart: "Börja om",
|
||
harderLevelSolved: "Varning: du har redan löst en svårare version av den här uppgiften. Du kommer inte kunna få mer poäng med den här versionen.",
|
||
showLevelAnyway: "Visa den ändå.",
|
||
scoreObtained: "Uppnådd poäng:",
|
||
hardVersionTakesTime: "Att lösa en {0} kan ta lång tid. Fundera på om du ska jobba med en {1} för att tjäna poäng snabbare.",
|
||
illKeepThatInMind: "Jag ska tänka på det.",
|
||
harderLevelAvailable: "Notera att på den här uppgiften kan du direkt försöka med en svårare version än denna.",
|
||
lockedLevel: "Den här versionen är låst. Lös den föregående nivån för att visa den!",
|
||
gradeThisAnswer: "Bedöm svaret",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "Spara svaret",
|
||
answerSavedModifyOrCancelIt: "Ditt svar har sparats. Du kan ändra det, eller {0} och börja om.",
|
||
cancelIt: "avbryta det",
|
||
warningDifferentAnswerSaved: "Varning: ett annat svar finns redan sparat.",
|
||
youMay: "Du kan {0}.",
|
||
reloadIt: "ladda in det på nytt",
|
||
saveThisNewAnswer: "Spara det här nya svaret",
|
||
|
||
gradingInProgress: "Rättning pågår",
|
||
scoreIs: "Din poäng är:",
|
||
point: "poäng",
|
||
points: "poäng",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "Eftersom tävlingen är över sparas inte ditt svar och din poäng ändras inte.",
|
||
scoreWouldBecome: "Med det här svaret, skulle din poäng vara:",
|
||
reloadValidAnswer: "Ladda in det kontrollerade svaret.",
|
||
contestOverAnswerNotSaved: "Eftersom tävlingen är över sparas inte ditt svar.",
|
||
scoreWouldStay: "Med det här svaret, skulle din poäng inte ändras:",
|
||
answerNotSavedContestOver: "Eftersom tävlingen är över sparas inte ditt svar. Du kan {0}.",
|
||
reloadSubmittedAnswer: "ladda in det kontrollerade svaret på nytt",
|
||
difficultyWarning: "<strong>Varning:</strong> att lösa den här versionen tar lång tid.<br/>Det kan gå snabbare att lösa 2- eller 3-stjärniga versioner av andra uppgifter.",
|
||
enemyWarning: "<strong>Varning:</strong> i den här utmaningen kommer datorn se till att du inte hittar lösningen av en slump."
|
||
},
|
||
fi: {
|
||
version: "Versio",
|
||
levelVersionName_easy: "helppo versio",
|
||
levelVersionName_medium: "hieman vaikeampi versio",
|
||
levelVersionName_hard: "vaikea versio",
|
||
levelVersionName_easy_stars: "2 tähden versio",
|
||
levelVersionName_medium_stars: "3 tähden versio",
|
||
levelVersionName_hard_stars: "4 tähden versio",
|
||
levelName_easy: "Helppo",
|
||
levelName_medium: "Hieman vaikeampi",
|
||
levelName_hard: "Vaikea",
|
||
warningTimeout: "<p>Varoitus: on kulunut jo yli {0} minuuttia siitä, kun aloit tekemään tätä tehtävää.</p><p>Sinun mahdollisesti kannattaisi siirtyä yrittämään jotain toista tehtävää, klikkaamalla oikean yläkulman nappia.</p>",
|
||
alright: "Ok",
|
||
moveOn: "Siirry eteenpäin",
|
||
solvedMoveOn: "Ratkaisit tämän tehtävän kokonaan, siirry nyt seuraavaan tehtävään.",
|
||
confirmRestart: "Oletko varma, että haluat aloittaa tämän version alusta?",
|
||
yes: "Kyllä",
|
||
no: "Ei",
|
||
tryHardLevel: "Ehdotamme, että kokeilet 4 tähden versiota.",
|
||
tryMediumLevel: "Ehdotamme, että kokeilet 3 tähden versiota.",
|
||
tryNextTask: "Ehdotamme, että kokeilet seuraavaa tehtävää. Jos sinulle jää vielä aikaa, voit myöhemmin palata takaisin tämän tehtävän pariin.",
|
||
yourScoreIsNow: "Pisteesi nyt:",
|
||
worseScoreStays: "Tämä on aiempaa alhaisempi. Pistemääränäsi säilyy:",
|
||
scoreStays: "Pistemääränäsi sailyy:",
|
||
score: "Pisteet:",
|
||
noPointsForLevel: "Et ole vielä saanut pisteitä tästä versiosta.",
|
||
outOf: " / ",
|
||
tryToDoBetterOrChangeTask: "Yritä saada vielä paremmat pisteet, tai siirry toiseen tehtävään.",
|
||
tryToDoBetterOrMoveToNextLevel: "Yritä saada vielä paremmat pisteet, tai siirry saman tehtävän vaikeampaan versioon.",
|
||
bestPossibleScoreCongrats: "Onnittelut: saavutit tehtävän maksimipistemäärän!",
|
||
forMorePointsMoveToNextLevel: "Siirry tehtävän vaikeampaan versioon saadaksesi enemmän pisteitä.",
|
||
youDidBetterBefore: "Sait aiemmin enemmän pisteitä.",
|
||
scoreStays2: "Pistemääräsi säilyy samana.",
|
||
reloadBestAnswer: "Palauta paras aiempi vastauksesi.",
|
||
noAnswerSaved: "No answer saved so far for this version.",
|
||
validate: "Tarkista vastaus",
|
||
restart: "Aloita alusta",
|
||
harderLevelSolved: "Varoitus: olet jo ratkaissut vaikeamman version tästä tehtävästä. Tämän helpomman version ratkaiseminen ei voi korottaa pistemäärääsi.",
|
||
showLevelAnyway: "Siirry joka tapauksessa.",
|
||
scoreObtained: "Saatu pistemäärä:",
|
||
hardVersionTakesTime: "{0} voi viedä runsaasti aikaa. {1} voi tuottaa pisteitä nopeammin.",
|
||
illKeepThatInMind: "Huomioin tämän.",
|
||
harderLevelAvailable: "Huomaa, että voit myös suoraan koittaa ratkaista vaikeampaa versiota tästä tehtävästä.",
|
||
lockedLevel: "Tämä versio on vielä lukittu: ratkaise ensin helpompi versio!",
|
||
gradeThisAnswer: "Pisteytä tämä vastaus",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "Tallenna vastaus",
|
||
answerSavedModifyOrCancelIt: "Vastauksesi on tallennettu. Voit muokata sitä, tai {0} ja aloittaa uudelleen alusta.",
|
||
cancelIt: "perua sen",
|
||
warningDifferentAnswerSaved: "Varoitus: toisenlainen vastaus on tallennettu jo aiemmin.",
|
||
youMay: "Voit {0}.",
|
||
reloadIt: "ladata sen uudelleen",
|
||
saveThisNewAnswer: "tallentaa tämän uuden vastauksen",
|
||
|
||
gradingInProgress: "Pisteytystä suoritetaan",
|
||
scoreIs: "Pistemääräsi on:",
|
||
point: "piste",
|
||
points: "pisteet",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "Kilpailu on jo päättynyt, joten uutta vastaustasi ei enää tallennettu ja pistemääränäsi säilyy:",
|
||
scoreWouldBecome: "Jos tämäkin vastaus huomioitaisiin, pistemääräsi olisi:",
|
||
reloadValidAnswer: "Palauta aiemmin hyväksytty vastaus.",
|
||
contestOverAnswerNotSaved: "Kilpailu on jo päättynyt, joten uutta vastaustasi ei enää tallennettu.",
|
||
scoreWouldStay: "Jos tämäkin vastaus huomioitaisiin, pistemääräsi olisi yhä:",
|
||
answerNotSavedContestOver: "Kilpailu on jo päättynyt, joten uutta vastaustasi ei enää tallennettu. Voit {0}.",
|
||
reloadSubmittedAnswer: "palauttaa aiemmin lähetetyn vastauksen",
|
||
difficultyWarning: "<strong>Varoitus:</strong> tämän version ratkaiseminen vie aikaa.<br/>Saat luultavasti ratkaistua 2 tai 3 tähden version nopeammin.",
|
||
enemyWarning: "<strong>Varoitus:</strong> tässä tehtävässä tietokone pyrkii varmistamaan, ettet voi löytää ratkaisua sattumalta."
|
||
},
|
||
de: {
|
||
version: "Version",
|
||
levelVersionName_easy: "leichte Version",
|
||
levelVersionName_medium: "mittlere Version",
|
||
levelVersionName_hard: "schwere Version",
|
||
levelVersionName_easy_stars: "2-Sterne-Version",
|
||
levelVersionName_medium_stars: "3-Sterne-Version",
|
||
levelVersionName_hard_stars: "4-Sterne-Version",
|
||
levelName_easy: "Leicht",
|
||
levelName_medium: "Mittel",
|
||
levelName_hard: "Schwer",
|
||
warningTimeout: "<p>Achtung, du bist schon seit {0} Minuten bei dieser Frage.</p><p>Du solltest jetzt zu einer anderen Aufgabe wechseln.</p>",
|
||
alright: "OK",
|
||
moveOn: "Fortfahren",
|
||
solvedMoveOn: "Du hast diese Frage bereits vollständig gelöst. Wähle eine andere Frage zum Bearbeiten aus.",
|
||
confirmRestart: "Bist du sicher, dass du diese Version neustarten möchtest?",
|
||
yes: "Ja",
|
||
no: "Nein",
|
||
tryHardLevel: "Wir schlagen dir vor, die 4-Sterne-Version zu bearbeiten.",
|
||
tryMediumLevel: "Wir schlagen dir vor, die 3-Sterne-Version zu bearbeiten",
|
||
tryNextTask: "Wir schlagen dir vor, die nächste Aufgabe zu bearbeiten. Wenn du am Ende noch Zeit hast, kannst du hierher zurückkehren und die schwerere Version bearbeiten.",
|
||
yourScoreIsNow: "Dein Punktestand ist jetzt:",
|
||
worseScoreStays: "Das ist weniger als vorher; dein Punktestand bleibt:",
|
||
scoreStays: "Dein Punktestand bleibt gleich:",
|
||
score: "Punktestand:",
|
||
noPointsForLevel: "Du hast noch keine Punkte für diese Version erhalten.",
|
||
outOf: " von ",
|
||
tryToDoBetterOrChangeTask: "Versuche, dich zu verbessern oder wähle eine andere Frage.",
|
||
tryToDoBetterOrMoveToNextLevel: "Versuche, dich zu verbessern oder wähle schwierigere Version.",
|
||
bestPossibleScoreCongrats: "Das ist die bestmögliche Punktzahl für diese Aufgabe. Glückwunsch!",
|
||
forMorePointsMoveToNextLevel: "Wähle eine schwerere Version aus, um noch mehr Punkte zu bekommen.",
|
||
youDidBetterBefore: "Du hast dich verbessern.",
|
||
scoreStays2: "Dein Punktestand bleibt gleich.",
|
||
reloadBestAnswer: "Deine beste Antwort wieder laden.",
|
||
noAnswerSaved: "Bisher noch keine Antwort für diese Version gespeichert.",
|
||
validate: "Erstellen",
|
||
restart: "Neustarten",
|
||
harderLevelSolved: "Achtung: Du hast schon eine schwerere Version gelöst. Du kannst mit dieser Version keine zusätzlichen Punkte bekommen.",
|
||
showLevelAnyway: "Trotzdem anzeigen",
|
||
scoreObtained: "Erhaltene Punkte:",
|
||
hardVersionTakesTime: "Eine {0} zu lösen kann dich viel Zeit kosten; Denke zunächst daran, die Fragen in {1} zu beantworten, um schnell Punkte zu bekommen.",
|
||
illKeepThatInMind: "Ich hab das verstanden",
|
||
harderLevelAvailable: "Beachte, dass du bei dieser Frage direkt zu einer schwereren Version gehen kannst.",
|
||
lockedLevel: "Diese Version ist noch gesperrt. Löse die vorherige um diese freizuschalten.",
|
||
gradeThisAnswer: "Diese Antwort auswerten",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "Antwort speichern",
|
||
answerSavedModifyOrCancelIt: "Deine Antwort wurde eingereicht. Du kannst sie noch bearbeiten, oder {0} und neu beginnen.",
|
||
cancelIt: "Abbrechen",
|
||
warningDifferentAnswerSaved: "Achtung: Eine andere Antwort ist bereits gespeichert!",
|
||
youMay: "Du kannst {0}.",
|
||
reloadIt: "Neu laden",
|
||
saveThisNewAnswer: "Diese Antwort speichern",
|
||
|
||
gradingInProgress: "Das Ergebnis wird ausgewertet …",
|
||
scoreIs: "Dein Punktestand beträgt:",
|
||
point: "Punkt",
|
||
points: "Punkte",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "Der Contest ist vorbei, deine Antwort wurde nicht eingereicht und deine Punktestand bleibt:",
|
||
scoreWouldBecome: "Mit dieser Antwort wäre dein Punktestand:",
|
||
reloadValidAnswer: "Die gültige Antwort neu laden.",
|
||
contestOverAnswerNotSaved: "Der Contest ist vorbei, deine Antwort wurde nicht eingereicht.",
|
||
scoreWouldStay: "Mit dieser Antwort bliebe dein Punktestand gleich:",
|
||
answerNotSavedContestOver: "Der Contest ist vorbei, deine Antwort wurde nicht eingereicht. Du kannst {0}.",
|
||
reloadSubmittedAnswer: "Lade die Lösung, die du eingereicht hast",
|
||
difficultyWarning: "<strong>Achtung:</strong> diese Version zu lösen kann einige Zeit in Anspruch nehmen.<br/>Die 2- und 3-Stern Version von anderen Aufgaben lassen sich schneller lösen.",
|
||
enemyWarning: "<strong>Attention :</strong> dans ce défi, l'ordinateur vous empêchera de trouver la solution par hasard."
|
||
},
|
||
ar: {
|
||
version: "المستوى",
|
||
levelVersionName_easy: "المستوى السهل",
|
||
levelVersionName_medium: "المستوى المتوسط",
|
||
levelVersionName_hard: "المستوى الصعب",
|
||
levelVersionName_easy_stars: "المستوى الأول",
|
||
levelVersionName_medium_stars: "المستوى الثاني",
|
||
levelVersionName_hard_stars: "المستوى الثالث",
|
||
levelName_easy: "سهل",
|
||
levelName_medium: "متوسط",
|
||
levelName_hard: "صعب",
|
||
warningTimeout: "<p>لقد مر وقت طويل منذ أن بدأت في هذه المسألة, من الأفضل أن تبدأ في مسألة أخرى حتى لا يضيع الوقت</p>",
|
||
alright: "حسناً",
|
||
moveOn: "استمر",
|
||
solvedMoveOn: "لقد أجبت على هذا السؤال بالكامل. ابدأ في سؤال أخر",
|
||
confirmRestart: "هل ترغب في بدء هذا سؤال من جديد؟",
|
||
yes: "نعم",
|
||
no: "لا",
|
||
tryHardLevel: "نقترح أن تبدأ في المستوى الثالث للسؤال",
|
||
tryMediumLevel: "نقترح أن تبدأ في المستوى الثاني للسؤال",
|
||
tryNextTask: "نقترح أن تبدأ في المسألة التالية, وإذا تبقى عندك وقت يمكنك حل المستوى الأصعب في هذه المسألة لاحقاً",
|
||
yourScoreIsNow: "مجموع نقاطك:",
|
||
worseScoreStays: "هذا ليس جيداً. ما زالت نقاطك:",
|
||
scoreStays: "نقاطك ما زالت كما هي:",
|
||
score: "النقاط",
|
||
noPointsForLevel: "لم تحقق أي نقاط في هذا المستوى",
|
||
outOf: "من",
|
||
tryToDoBetterOrChangeTask: "حاول في مسألة أخرى",
|
||
tryToDoBetterOrMoveToNextLevel: "حاول في المستوى الأصعب",
|
||
bestPossibleScoreCongrats: "مبروك ... لقد حصلت على أعلى درجة في هذا السؤال",
|
||
forMorePointsMoveToNextLevel: "للحصول على المزيد من النقاط جاوب على المستوى الأصعب",
|
||
youDidBetterBefore: "لقد قمت بها أفضل من هذا في وقت سابق",
|
||
scoreStays2: "ما زالت نقاطك كما هي",
|
||
reloadBestAnswer: "اعد تحميل إجابتك الأفضل",
|
||
noAnswerSaved: "No answer saved so far for this version.",
|
||
validate: "تحقق",
|
||
restart: "ابدأ من جديد",
|
||
harderLevelSolved: "لقد قمت بحل المستوى الأصعب في هذا السؤال, لن تتمكن من الحصول على درجات أعلى في هذا السؤال",
|
||
showLevelAnyway: "اظهرها لي على أي حال",
|
||
scoreObtained: "النقاط المكتسبة:",
|
||
hardVersionTakesTime: "Solving a {0} can take a lot of time. Consider working on the {1} to gain points quickly.",
|
||
illKeepThatInMind: "I'll consider it.",
|
||
harderLevelAvailable: "تنبيه: يمكنك حل المستوى الأصعب في هذه المسألة مباشرة",
|
||
lockedLevel: "هذا المستوى مغلق. يجب عليك حل المستوى السابق أولا",
|
||
gradeThisAnswer: "قيم هذه الإجابة",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "احفظ هذه الإجابة",
|
||
answerSavedModifyOrCancelIt: "تم حفظ إجابتك, يمكنك تعديلها أو بدأها من جديد",
|
||
cancelIt: "احذفها",
|
||
warningDifferentAnswerSaved: "تنبيه: يوجد اجابة أخرى محفوظة سابقاً",
|
||
youMay: "You may {0}.",
|
||
reloadIt: "حملها من جديد",
|
||
saveThisNewAnswer: "احفظ الإجابة الجديدة",
|
||
|
||
gradingInProgress: "نقوم بالتقييم",
|
||
scoreIs: "مجموع نقاطك:",
|
||
point: "نقطة",
|
||
points: "نقاط",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "المسابقة انتهت. إجابتك الجديدة لم تحفظ ومجموع نقاطك ما زال:",
|
||
scoreWouldBecome: " مع تلك الإجابة، مجموع نقاطك أصبح:",
|
||
reloadValidAnswer: "اعد تحميل الإجابة المحققة",
|
||
contestOverAnswerNotSaved: "المسابقة إنتهت ولم يتم حفظ إجاباتك الجديدة",
|
||
scoreWouldStay: "بهذه الإجابة سوف يظل مجموع نقاطك كما هو",
|
||
answerNotSavedContestOver: "The contest being over, your answer was not saved. You may {0}.",
|
||
reloadSubmittedAnswer: "اعد تحميل الإجابة المحققة",
|
||
difficultyWarning: "تنبيه: حل هذه النسخة سوف يستغرق وقت كثير. الإفضل أن تبدأ في حل مسائل أخرى",
|
||
enemyWarning: "تحذير: في هذه المسألة سيمنعك الكمبيوتر من إيجاد الحل عن طريق الصدفة. فكر جيداً"
|
||
},
|
||
es: {
|
||
version: "Versión",
|
||
levelVersionName_easy: "versión fácil",
|
||
levelVersionName_medium: "versión moderada",
|
||
levelVersionName_hard: "versión difícil",
|
||
levelVersionName_easy_stars: "versión de 2 estrellas",
|
||
levelVersionName_medium_stars: "versión de 3 estrellas",
|
||
levelVersionName_hard_stars: "versión de 4 estrellas",
|
||
levelName_easy: "Fácil",
|
||
levelName_medium: "Moderado",
|
||
levelName_hard: "Difícil",
|
||
warningTimeout: "<p>Atención, ya lleva {0} minutos en esta pregunta.</p><p>Le recomendamos cambiar de tema haciendo click sobre el botón de arriba a la derecha.</p>",
|
||
alright: "De acuerdo",
|
||
moveOn: "Pasar a la siguiente",
|
||
solvedMoveOn: "Ha resuelto completamente esta pregunta. Pase a otra pregunta.",
|
||
confirmRestart: "¿Está seguro que desea volver a iniciar esta versión?",
|
||
yes: "Sí",
|
||
no: "No",
|
||
tryHardLevel: "Le recomendamos intentar la versión de 4 estrellas.",
|
||
tryMediumLevel: "Le recomendamos intentar la versión de 3 estrellas.",
|
||
tryNextTask: "Nous vous proposons de passer au sujet suivant. S'il vous reste du temps, vous reviendrez plus tard essayer la version suivante.",
|
||
yourScoreIsNow: "Su puntuación es ahora :",
|
||
worseScoreStays: "Esto no está tan bien como antes; su puntuación se mantiene en :",
|
||
scoreStays: "Su puntuación se mantiene igual :",
|
||
score: "Puntuación :",
|
||
noPointsForLevel: "Aún no ha recibido puntos en esta versión.",
|
||
outOf: " de ",
|
||
tryToDoBetterOrChangeTask: "Intente nuevamente para obtener una mejor puntuación, o pase a la siguiente pregunta.",
|
||
tryToDoBetterOrMoveToNextLevel: "Intente nuevamente para obtener una mejor puntuación, o pase una versión más difícil.",
|
||
bestPossibleScoreCongrats: "Esta es la mejor puntuación posible en este problema, ¡felicitaciones!",
|
||
forMorePointsMoveToNextLevel: "Para obtener más puntos, pase a una versión más difícil.",
|
||
youDidBetterBefore: "Realizó un mejor trabajo antes.",
|
||
scoreStays2: "Su puntuación se mantiene igual.",
|
||
reloadBestAnswer: "Recargar su mejor respuesta.",
|
||
noAnswerSaved: "Aún no hay respuesta guardada para esta versión.",
|
||
validate: "Validar",
|
||
restart: "Reiniciar",
|
||
harderLevelSolved: "Atención: ya ha resuelto una versión más difícil. No puede ganar puntos extra con esta versión.",
|
||
showLevelAnyway: "Mostrar el nivel de igual manera",
|
||
scoreObtained: "Puntuación obtenida:",
|
||
hardVersionTakesTime: "Resolver una {0} puede tomar mucho tiempo; le aconsejamos priorizar resolver las preguntas en {1} para ganar puntos rápidamente.",
|
||
illKeepThatInMind: "Lo tendré en mente",
|
||
harderLevelAvailable: "Note que para esta pregunta, puede resolver directamente una versión más difícil que esta.",
|
||
lockedLevel: "Esta versión está bloqueada. Resuelva la version anterior para verla.",
|
||
gradeThisAnswer: "Evaluar esta respuesta",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "Guardar su respuesta",
|
||
answerSavedModifyOrCancelIt: "Su respuesta fue guardada. Puede modificarla, o bien {0} y reiniciar.",
|
||
cancelIt: "cancelarla",
|
||
warningDifferentAnswerSaved: "Atención: una respuesta diferente ha sido guardada.",
|
||
youMay: "Usted puede {0}.",
|
||
reloadIt: "recargarla",
|
||
saveThisNewAnswer: "Guardar esta nueva respuesta",
|
||
|
||
gradingInProgress: "Evaluación en curso",
|
||
scoreIs: "Su puntuación es:",
|
||
point: "punto",
|
||
points: "puntos",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "El concurso está terminando, su respuesta no ha sido guardada y su puntuación se mantiene en:",
|
||
scoreWouldBecome: "Con esta respuesta, su puntuación será :",
|
||
reloadValidAnswer: "Volver a cargar la respuesta válida.",
|
||
contestOverAnswerNotSaved: "El concurso ha terminado: su respuesta no fue guardada.",
|
||
scoreWouldStay: "Con esta respuesta, su puntuación será la misma:",
|
||
answerNotSavedContestOver: "El concurso está terminando y su respuesta no ha sido guardada. Usted puede {0}.",
|
||
reloadSubmittedAnswer: "recargar la respuesta que ha enviado",
|
||
difficultyWarning: "<strong>Advertencia:</strong> resolver esta versión toma tiempo.<br/>Usted puede resolver más rápidamente las versiones de 2 y 3 estrellas de otros problemas.",
|
||
enemyWarning: "<strong>Advertencia:</strong> en este desafío, la computadora se asegurará que no encuentre la respuesta por casualidad."
|
||
},
|
||
sl: {
|
||
version: "Stopnja",
|
||
levelVersionName_easy: "enostavna stopnja",
|
||
levelVersionName_medium: "srednja stopnja",
|
||
levelVersionName_hard: "težka stopnja",
|
||
levelVersionName_easy_stars: "stopnja 2 zvezdici",
|
||
levelVersionName_medium_stars: "stopnja 3 zvezdice",
|
||
levelVersionName_hard_stars: "stopnja 4 zvezdice",
|
||
levelName_easy: "Enostavno",
|
||
levelName_medium: "Srednje",
|
||
levelName_hard: "Težko",
|
||
warningTimeout: "<p>Opozorilo: Odkar rešuješ to nalogo, je minilo že več kot {0} minut.</p><p>Najbolje, da izbereš drugo nalogo, tako da klikneš gumb v zgornjem desnem kotu.</p>",
|
||
alright: "V redu",
|
||
moveOn: "Nadaljuj",
|
||
solvedMoveOn: "Ta naloga je dokončana, nadaljuj z naslednjo nalogo.",
|
||
confirmRestart: "Ali res želiš znova začeti to stopnjo?",
|
||
yes: "Da",
|
||
no: "Ne",
|
||
tryHardLevel: "Predlagamo, da poizkusiš stopnjo s 4 zvezdicami.",
|
||
tryMediumLevel: "Predlagamo, da poizkusiš stopnjo s 3 zvezdicami.",
|
||
tryNextTask: "Prdlagamo, da poizkusiš naslednjo nalogo. Če bo ostalo dovolj časa, se vrni in poizkusi naslednjo stopnjo te naloge.",
|
||
yourScoreIsNow: "Tvoj rezultat je:",
|
||
worseScoreStays: "Rešitev ni tako dobra, kot prejšnja. Tvoj rezultat ostaja:",
|
||
scoreStays: "Tvoj rezultat ostaja enak:",
|
||
score: "Rezultat:",
|
||
noPointsForLevel: "Na tej stopnji nisi dobil(-a) še nobene točke.",
|
||
outOf: " od ",
|
||
tryToDoBetterOrChangeTask: "Poskusi nalogo rešiti še bolje ali se premakni na naslednjo nalogo.",
|
||
tryToDoBetterOrMoveToNextLevel: "Poskusi nalogo rešiti še bolje ali se premakni na težjo stopnjo.",
|
||
bestPossibleScoreCongrats: "Čestitamo, to je najboljši možni rezultat te naloge!",
|
||
forMorePointsMoveToNextLevel: "Če želiš dobiti še več točk, se premakni na težjo stopnjo te naloge.",
|
||
youDidBetterBefore: "Rešitev je boljša od prejšnje.",
|
||
scoreStays2: "Tvoj rezultat ostaja enak.",
|
||
reloadBestAnswer: "Znova naloži najboljšo rešitev.",
|
||
noAnswerSaved: "No answer saved so far for this version.",
|
||
validate: "Preveri",
|
||
restart: "Začni znova",
|
||
harderLevelSolved: "Opozorilo: Rešil(-a) si že težjo stopnjo te naloge. S to stopnjo ne boš dobil(-a) dodatnih točk.",
|
||
showLevelAnyway: "Vseeno mi pokaži stopnjo.",
|
||
scoreObtained: "Dobljeni rezultat:",
|
||
hardVersionTakesTime: "Reševanje {0} lahko traja veliko časa. Razmisli o reševanju {1}, da boš hitro dobil(-a) točke.",
|
||
illKeepThatInMind: "Razmislil(-a) bom.",
|
||
harderLevelAvailable: "Ne pozabi, da lahko to nalogo rešuješ na težji stopnji kot je ta.",
|
||
lockedLevel: "Ta stopnja je zaklenjena! Za pikaz moraš najprej rešiti prejšnjo stopnjo!",
|
||
gradeThisAnswer: "Oceni ta odgovor",
|
||
|
||
// The following messages are used for tasks with no feedback
|
||
saveAnswer: "Shrani ta odgovor",
|
||
answerSavedModifyOrCancelIt: "Tvoj odgovor je bil shranjen. Lahko ga spremeniš ali {0} in začneš znova.",
|
||
cancelIt: "prekličeš",
|
||
warningDifferentAnswerSaved: "Opozorilo: Prej je bil shranjen drugačen odgovor.",
|
||
youMay: "Lahko ga {0}.",
|
||
reloadIt: "naložiš znova",
|
||
saveThisNewAnswer: "Shrani ta nov odgovor",
|
||
|
||
gradingInProgress: "Ocenjevanje poteka",
|
||
scoreIs: "Tvoj rezultat je:",
|
||
point: "točka",
|
||
points: "točk",
|
||
// The following messages are used when viewing tasks after contest is over
|
||
contestOverScoreStays: "Ker je tekmovanja konec, tvoj novi odgovor ni bil shranjen in rezultat bo ostal:",
|
||
scoreWouldBecome: "S to rešitvijo bi bil tvoj rezultat:",
|
||
reloadValidAnswer: "Znova naloži preverjeno rešitev.",
|
||
contestOverAnswerNotSaved: "Ker je tekmovanja konec, tvoj novi odgovor ni bil shranjen.",
|
||
scoreWouldStay: "S to rešitvijo bi tvoj rezultat ostal enak:",
|
||
answerNotSavedContestOver: "Ker je tekmovanja konec, tvoj novi odgovor ni bil shranjen. Lahko {0}.",
|
||
reloadSubmittedAnswer: "znova naložiš preverjeno rešitev",
|
||
difficultyWarning: "<strong>Opozorilo:</strong> Reševanje te stopnje lahko traja veliko časa. <br/>Hitreje lahko rešiš stopnje z 2 ali s 3 zvezdicami drugih nalog.",
|
||
enemyWarning: "<strong>Opozorilo:</strong> Pri tej nalogi ti bo računalnik preprečil naključno rešitev."
|
||
},
|
||
},
|
||
initLanguage: function() {
|
||
if (window.stringsLanguage == undefined) {
|
||
window.stringsLanguage = 'fr';
|
||
}
|
||
this.strings = this.languageStrings[window.stringsLanguage];
|
||
},
|
||
/***********************************************
|
||
* Initialization functions called by the task *
|
||
***********************************************/
|
||
load: function(views) {
|
||
this.initLanguage();
|
||
var self = this;
|
||
this.showScore = (typeof views.grader !== 'undefined' && views.grader === true);
|
||
window.platform.getTaskParams(null, null, function(taskParams) {
|
||
self.taskParams = taskParams;
|
||
self.readOnly = (self.taskParams.readonly === true || self.taskParams.readOnly == 'true');
|
||
self.graderScore = +self.taskParams.noScore;
|
||
self.savedAnswer = '';
|
||
|
||
$("#difficultyWarning").html(self.strings.difficultyWarning).addClass("warningHeader");
|
||
$("#enemyWarning").html(self.strings.enemyWarning).addClass("warningHeader");
|
||
var addTaskHTML = '<div id="displayHelperAnswering" class="contentCentered">';
|
||
// Place button placements at the end of HTML if they don't already exist
|
||
var placementNames = ['graderMessage', 'validate', 'cancel', 'saved'];
|
||
for (var iPlacement = 0; iPlacement < placementNames.length; iPlacement++) {
|
||
var placement = 'displayHelper_' + placementNames[iPlacement];
|
||
if ($('#' + placement).length === 0) {
|
||
addTaskHTML += '<div id="' + placement + '"></div>';
|
||
}
|
||
}
|
||
addTaskHTML += '</div>';
|
||
if (!document.getElementById('displayHelperAnswering')) {
|
||
$(self.taskSelector).append(addTaskHTML);
|
||
}
|
||
self.loaded = true;
|
||
self.timeLoaded = new Date().getTime();
|
||
if (self.popupMessageShown) {
|
||
$('#displayHelperAnswering').hide();
|
||
}
|
||
|
||
var taskDelayWarning = function() {
|
||
if (self.popupMessageShown) {
|
||
self.taskDelayWarningTimeout = setTimeout(taskDelayWarning, 5000);
|
||
} else {
|
||
self.showPopupMessage(self.formatTranslation(self.strings.warningTimeout, [self.timeoutMinutes]), 'blanket', self.strings.alright, null, null, "warning");
|
||
self.taskDelayWarningTimeout = null;
|
||
}
|
||
};
|
||
if (self.timeoutMinutes > 0) {
|
||
self.taskDelayWarningTimeout = setTimeout(taskDelayWarning, self.timeoutMinutes * 60 * 1000);
|
||
}
|
||
});
|
||
},
|
||
unload: function() {
|
||
if (this.taskDelayWarningTimeout) {
|
||
this.taskDelayWarningTimeout = clearTimeout(this.taskDelayWarningTimeout);
|
||
}
|
||
clearInterval(this.checkAnswerInterval);
|
||
this.checkAnswerInterval = null;
|
||
this.loaded = false;
|
||
this.prevAnswer = '';
|
||
this.readOnly = false;
|
||
this.savedAnswer = '';
|
||
this.submittedAnswer = '';
|
||
this.submittedScore = 0;
|
||
this.hasAnswerChanged = true;
|
||
this.hideValidateButton = false;
|
||
this.hideRestartButton = false;
|
||
this.showScore = false;
|
||
this.refreshMessages = true;
|
||
this.stoppedShowingResult = false;
|
||
this.previousMessages = {};
|
||
this.popupMessageShown = false;
|
||
this.hasLevels = false;
|
||
this.pointsAsStars = true; // TODO: false as default
|
||
this.unlockedLevels = 4;
|
||
this.neverHadHard = false;
|
||
this.showMultiversionNotice = false;
|
||
this.taskLevel = '';
|
||
this.initLevelVars();
|
||
return true;
|
||
},
|
||
|
||
initLevelVars: function() {
|
||
var defaultLevelsRanks = { basic: 1, easy: 2, medium: 3, hard: 4 };
|
||
this.levelsRanks = {};
|
||
this.levelsScores = {};
|
||
this.prevLevelsScores = {};
|
||
for(var i=0; i < this.levels.length; i++) {
|
||
var levelName = this.levels[i];
|
||
if(typeof this.levelsRanks[levelName] == 'undefined') {
|
||
this.levelsRanks[levelName] = defaultLevelsRanks[levelName];
|
||
}
|
||
this.levelsScores[levelName] = 0;
|
||
this.prevLevelsScores[levelName] = 0;
|
||
}
|
||
},
|
||
|
||
setupLevels: function(initLevel, reloadWithCallbacks, levels) {
|
||
this.reloadWithCallbacks = reloadWithCallbacks;
|
||
this.initLanguage();
|
||
if(levels) {
|
||
this.levels = levels;
|
||
this.levelsIdx = {};
|
||
for(var i = 0; i < this.levels.length; i++) {
|
||
this.levelsIdx[this.levels[i]] = i;
|
||
}
|
||
}
|
||
this.initLevelVars();
|
||
|
||
var self = this;
|
||
function callSetupLevels() {
|
||
if(!initLevel) {
|
||
initLevel = self.taskParams.options.difficulty ? self.taskParams.options.difficulty : "easy";
|
||
}
|
||
self.doSetupLevels(initLevel);
|
||
};
|
||
if (!this.taskParams) {
|
||
window.platform.getTaskParams(null, null, function(taskParams) {
|
||
self.taskParams = taskParams;
|
||
callSetupLevels();
|
||
});
|
||
} else {
|
||
callSetupLevels();
|
||
}
|
||
},
|
||
doSetupLevels: function(initLevel) {
|
||
// TODO To fix: levelWrapper-1 does not work correctly without this part,
|
||
// so the level is loaded twice initially (once here, and once below).
|
||
if(!this.reloadWithCallbacks) {
|
||
task.reloadStateObject(task.getDefaultStateObject(), true);
|
||
task.reloadAnswerObject(task.getDefaultAnswerObject());
|
||
}
|
||
|
||
this.setupParams();
|
||
if (!document.getElementById('popupMessage')) {
|
||
this.setupLevelsTabs();
|
||
$('#tabsMenu .li').on('click', function(event) {
|
||
event.preventDefault();
|
||
var newLevel = $(this).children().attr('href').split('#')[1];
|
||
displayHelper.setLevel(newLevel);
|
||
});
|
||
}
|
||
|
||
this.setLevel(initLevel);
|
||
|
||
if (this.unlockedLevels > 1 && this.showMultiversionNotice) {
|
||
this.showPopupMessage(this.strings.harderLevelAvailable, 'blanket', this.strings.alright,
|
||
function() {
|
||
this.showMultiversionNotice = false;
|
||
}
|
||
);
|
||
}
|
||
},
|
||
setupParams: function() {
|
||
var taskParams = this.taskParams;
|
||
|
||
this.hasLevels = true;
|
||
var paramNames = ['pointsAsStars', 'unlockedLevels', 'neverHadHard', 'showMultiversionNotice'];
|
||
for (var iParam = 0; iParam < paramNames.length; iParam++) {
|
||
var param = paramNames[iParam];
|
||
if (taskParams[param] !== undefined) {
|
||
this[param] = taskParams[param];
|
||
}
|
||
}
|
||
|
||
var maxScore = taskParams.maxScore !== undefined ? taskParams.maxScore : 40;
|
||
this.levelsMaxScores = {};
|
||
for(var i=0; i < this.levels.length; i++) {
|
||
var levelName = this.levels[i];
|
||
var levelMaxScore = maxScore * this.levelsRanks[levelName] / this.maxStars;
|
||
this.levelsMaxScores[levelName] = this.pointsAsStars ? levelMaxScore : Math.round(levelMaxScore);
|
||
}
|
||
},
|
||
setupLevelsTabs: function() {
|
||
var scoreHTML;
|
||
var maxScores = this.levelsMaxScores;
|
||
if (this.pointsAsStars) {
|
||
var titleStarContainers = [];
|
||
scoreHTML = '<span></span><span id="titleStars"></span>';
|
||
$('#task > h1').append(scoreHTML);
|
||
drawStars('titleStars', this.maxStars, 24, 0, 'normal');
|
||
} else {
|
||
// Disabled: doesn't work with new tabs layout.
|
||
//scoreHTML = '<div class="bestScore">Score retenu : <span id="bestScore">0</span> sur ' + maxScores.hard + '</div>';
|
||
//$('#tabsContainer').append(scoreHTML);
|
||
}
|
||
|
||
var tabsStarContainers = [];
|
||
var tabsHTML = '<div id="tabsMenu">';
|
||
var curLevel;
|
||
for (curLevel in this.levelsRanks) {
|
||
tabsHTML += '<span class="li" id="tab_' + curLevel + '"><a href="#' + curLevel + '">';
|
||
if (this.pointsAsStars) {
|
||
tabsHTML += '<span class="levelLabel">' + this.strings.version + '</span><span id="stars_' + this.levelsRanks[curLevel] + '"></span>';
|
||
} else {
|
||
tabsHTML += this.strings["levelName_" + curLevel] + ' — ' +
|
||
'<span id="tabScore_' + curLevel + '">0</span> / ' + maxScores[curLevel];
|
||
}
|
||
tabsHTML += '</a></span>';
|
||
}
|
||
tabsHTML += '</div>';
|
||
$('#tabsContainer').append(tabsHTML);
|
||
|
||
var self = this;
|
||
setTimeout(function() {
|
||
for (var iLevel = 0; iLevel < self.levels.length; iLevel++) {
|
||
curLevel = self.levels[iLevel];
|
||
if (iLevel >= self.unlockedLevels) {
|
||
$('#tab_' + curLevel).addClass('lockedLevel');
|
||
}
|
||
self.updateStarsAtLevel(curLevel);
|
||
}
|
||
self.updateLayout();
|
||
}, 100);
|
||
|
||
$('#tabsContainer').after('<div id="popupMessage"></div>');
|
||
},
|
||
|
||
updateStarsAtLevel: function(level) {
|
||
var rate = this.levelsScores[level] / this.levelsMaxScores[level];
|
||
var iLevel = this.levelsIdx[level];
|
||
var starsIdx = this.levelsRanks[level];
|
||
var mode = 'normal';
|
||
if (iLevel >= this.unlockedLevels) {
|
||
mode = 'locked';
|
||
}
|
||
if (this.graderScore > this.levelsMaxScores[level]) {
|
||
mode = 'useless';
|
||
}
|
||
drawStars('stars_' + starsIdx, starsIdx, 14, rate, mode);
|
||
},
|
||
|
||
updateLayout: function() {
|
||
if (!this.bUseFullWidth) {
|
||
return
|
||
}
|
||
$('#valider').appendTo($('#displayHelper_validate'));
|
||
if(window.innerWidth >= 1200) {
|
||
$('#task').addClass('largeScreen');
|
||
$('#displayHelperAnswering').appendTo($('#zone_1'));
|
||
}
|
||
else {
|
||
$('#task').removeClass('largeScreen');
|
||
if ($('#showSolutionButton')) {
|
||
$('#displayHelperAnswering').insertBefore($('#showSolutionButton'));
|
||
}
|
||
else {
|
||
$('#displayHelperAnswering').appendTo($('#task'));
|
||
}
|
||
}
|
||
},
|
||
|
||
useFullWidth: function() {
|
||
// TODO: find a clean way to do this
|
||
try {
|
||
$('#question-iframe', window.parent.document).css('width', '100%');
|
||
} catch(e) {
|
||
}
|
||
// This try is probably not needed but avoid breaking just in case
|
||
try {
|
||
$(document).ready(function () {displayHelper.updateLayout();});
|
||
$(window).resize(function () {displayHelper.updateLayout();});
|
||
this.bUseFullWidth = true;
|
||
} catch(e) {
|
||
}
|
||
},
|
||
|
||
// Deprecated: use directly levelsMaxScores instead
|
||
getLevelsMaxScores: function() {
|
||
return this.levelsMaxScores;
|
||
},
|
||
|
||
displayLevel: function(newLevel) {
|
||
// Only displays a level, without requesting a level change to the task
|
||
if (this.popupMessageShown) {
|
||
$('#popupMessage').hide();
|
||
$('#displayHelperAnswering, #taskContent').show();
|
||
this.popupMessageShown = false;
|
||
}
|
||
|
||
var allLevels = ['basic', 'easy', 'medium', 'hard'];
|
||
if(this.levelsRanks) {
|
||
for(var lr in this.levelsRanks) {
|
||
allLevels.push(lr);
|
||
}
|
||
}
|
||
for(var i=0; i < allLevels.length; i++) {
|
||
var curLevel = allLevels[i];
|
||
$('#tab_' + curLevel).removeClass('current');
|
||
$('.' + curLevel).hide();
|
||
}
|
||
$('#tab_' + newLevel).addClass('current');
|
||
$('.' + newLevel).show();
|
||
|
||
// Add prev and next classes to .current direct siblings
|
||
$('#tabsMenu .li').removeClass('prev next');
|
||
$('#tabsMenu .li.current').prev().addClass('prev');
|
||
$('#tabsMenu .li.current').next().addClass('next');
|
||
},
|
||
|
||
setLevel: function(newLevel) {
|
||
if (this.taskLevel == newLevel) {
|
||
return;
|
||
}
|
||
|
||
this.displayLevel(newLevel);
|
||
|
||
var answer = task.getAnswerObject();
|
||
var state = task.getStateObject();
|
||
state.level = newLevel;
|
||
this.taskLevel = newLevel;
|
||
var self = this;
|
||
|
||
var afterReload = function() {
|
||
self.submittedScore = self.levelsScores[self.taskLevel];
|
||
self.refreshMessages = true;
|
||
self.checkAnswerChanged();
|
||
self.stopShowingResult();
|
||
if ($('#tab_' + newLevel).hasClass('lockedLevel')) {
|
||
self.showPopupMessage(self.strings.lockedLevel, 'lock');
|
||
} else if (!self.hasSolution) {
|
||
if ($('#tab_' + newLevel).hasClass('uselessLevel') && self.levelsScores[newLevel] < self.levelsMaxScores[newLevel]) {
|
||
self.showPopupMessage(self.strings.harderLevelSolved, 'tab', self.strings.showLevelAnyway, null, null, "warning");
|
||
} else if (newLevel == 'hard' && self.neverHadHard) {
|
||
var hardVersionKey = "levelVersionName_hard";
|
||
var easyVersionKey = "levelVersionName_easy";
|
||
if (self.pointsAsStars) {
|
||
hardVersionKey += "_stars";
|
||
easyVersionKey += "_stars";
|
||
}
|
||
self.showPopupMessage(self.formatTranslation(self.strings.hardVersionTakesTime, [self.strings[hardVersionKey], self.strings[easyVersionKey]]),
|
||
'tab',
|
||
self.strings.illKeepThatInMind, function() {
|
||
self.neverHadHard = false;
|
||
}
|
||
);
|
||
}
|
||
}
|
||
};
|
||
|
||
if(self.reloadWithCallbacks) {
|
||
task.reloadStateObject(state, function() {
|
||
task.reloadAnswerObject(answer, afterReload);
|
||
});
|
||
}
|
||
else {
|
||
task.reloadStateObject(state, true);
|
||
task.reloadAnswerObject(answer);
|
||
afterReload();
|
||
}
|
||
},
|
||
|
||
getImgPath: function() {
|
||
if(window.contestsRoot) {
|
||
// Hack: when in the context of the platform, we need to change the path
|
||
return window.contestsRoot + '/' + window.contestFolder + '/';
|
||
} else if(window.modulesPath) {
|
||
var modulesPath = window.modulesPath[window.modulesPath.length-1] == '/' ? window.modulesPath : window.modulesPath + '/';
|
||
return modulesPath + 'img/';
|
||
} else {
|
||
return '../../../_common/modules/img/';
|
||
}
|
||
},
|
||
|
||
getAvatar: function(mood) {
|
||
if (displayHelper.avatarType == "beaver") {
|
||
return "castor.png";
|
||
} else if (displayHelper.avatarType == "none") {
|
||
return "";
|
||
} else {
|
||
if (mood == "success") {
|
||
return "laptop_success.png";
|
||
} else if (mood == "warning") {
|
||
return "laptop_warning.png";
|
||
}{
|
||
return "laptop_error.png";
|
||
}
|
||
}
|
||
},
|
||
|
||
|
||
showPopupDialog: function(message) {
|
||
if ($('#popupMessage').length == 0) {
|
||
$('#task').after('<div id="popupMessage"></div>');
|
||
}
|
||
|
||
$('#popupMessage').addClass('floatingMessage');
|
||
|
||
var imgPath = displayHelper.getImgPath();
|
||
|
||
var popupHtml = '<div class="container">' +
|
||
'<img class="messageArrow" src="' + imgPath + 'fleche-bulle.png"/>' +
|
||
'<div class="message">' + message + '</div></div>';
|
||
|
||
$('#popupMessage').html(popupHtml).show();
|
||
|
||
this.popupMessageShown = true;
|
||
try {
|
||
$(parent.document).scrollTop(0);
|
||
} catch (e) {
|
||
}
|
||
},
|
||
|
||
|
||
errorPopupAvatar: function() {
|
||
$('#popupMessage').addClass('noAvatar');
|
||
},
|
||
|
||
|
||
showPopupMessage: function(message, mode, yesButtonText, agreeFunc, noButtonText, avatarMood, defaultText, disagreeFunc) {
|
||
if(this.popupMessageHandler) {
|
||
// A custom popupMessageHandler was defined, call it
|
||
// It must return true if it handled the popup, false if displayHelper
|
||
// should handle the popup instead
|
||
if(this.popupMessageHandler.apply(null, arguments)) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
if ($('#popupMessage').length == 0) {
|
||
$('#task').after('<div id="popupMessage"></div>');
|
||
}
|
||
if (mode == 'blanket' || mode == 'input') {
|
||
$('#popupMessage').addClass('floatingMessage');
|
||
} else {
|
||
$('#taskContent, #displayHelperAnswering').hide();
|
||
$('#popupMessage').removeClass('floatingMessage');
|
||
}
|
||
$('#popupMessage').removeClass('noAvatar');
|
||
|
||
var imgPath = displayHelper.getImgPath();
|
||
if(mode == 'lock') {
|
||
var buttonYes = '';
|
||
} else if (mode == 'input') {
|
||
var buttonYes = '<button class="buttonYes">' + (yesButtonText || this.strings.validate) + '</button>';
|
||
} else {
|
||
var buttonYes = '<button class="buttonYes">' + (yesButtonText || this.strings.alright) + '</button>';
|
||
}
|
||
var buttonNo = '';
|
||
if (noButtonText != undefined) {
|
||
buttonNo = '<button class="buttonNo" style="margin-left: 10px;">' + noButtonText + '</button>';
|
||
}
|
||
var popupHtml = '<div class="container">' +
|
||
'<img class="beaver" src="' + imgPath + this.getAvatar(avatarMood) + '" onerror="displayHelper.errorPopupAvatar();"/>' +
|
||
'<img class="messageArrow" src="' + imgPath + 'fleche-bulle.png"/>' +
|
||
'<div class="message">' + message + '</div>';
|
||
if(mode == 'input') {
|
||
popupHtml += '<input id="popupInput" type="text" value="' + (defaultText ? defaultText : '') + '"></input>';
|
||
}
|
||
popupHtml += '<div class="buttonsWrapper">' + buttonYes + buttonNo + '</div></div>';
|
||
$('#popupMessage').html(popupHtml).show();
|
||
if(mode == 'input') {
|
||
$('#popupInput').focus();
|
||
}
|
||
|
||
var validateFunc = function() {
|
||
$('#popupMessage').hide();
|
||
$('#displayHelperAnswering, #taskContent').show();
|
||
displayHelper.popupMessageShown = false;
|
||
if (agreeFunc) {
|
||
if(mode == 'input') {
|
||
agreeFunc($('#popupInput').val());
|
||
} else {
|
||
agreeFunc();
|
||
}
|
||
}
|
||
};
|
||
|
||
var validateFuncNo = function() {
|
||
$('#popupMessage').hide();
|
||
$('#displayHelperAnswering, #taskContent').show();
|
||
displayHelper.popupMessageShown = false;
|
||
if (disagreeFunc) {
|
||
if(mode == 'input') {
|
||
disagreeFunc($('#popupInput').val());
|
||
} else {
|
||
disagreeFunc();
|
||
}
|
||
}
|
||
};
|
||
|
||
$('#popupMessage .buttonYes').click(validateFunc);
|
||
$('#popupMessage .buttonNo').click(validateFuncNo);
|
||
$('#popupInput').keypress(function (e) {
|
||
if(e.which === 13) { validateFunc(); }
|
||
});
|
||
|
||
$('#popupMessage .buttonNo').click(function() {
|
||
$('#popupMessage').hide();
|
||
$('#displayHelperAnswering, #taskContent').show();
|
||
displayHelper.popupMessageShown = false;
|
||
});
|
||
this.popupMessageShown = true;
|
||
try {
|
||
$(parent.document).scrollTop(0);
|
||
} catch (e) {
|
||
}
|
||
},
|
||
|
||
// Function to call at the beginning of task loading, before any html has
|
||
// been modified. It places the markers where the buttons will appear, if the
|
||
// markers are not present already.
|
||
showViews: function(views) {
|
||
// Fix for an old version of Firefox in which selection was stuck
|
||
try {
|
||
if (document.getSelection) {
|
||
var selection = document.getSelection();
|
||
if (selection !== undefined && selection.removeAllRanges !== undefined) {
|
||
selection.removeAllRanges();
|
||
}
|
||
}
|
||
} catch (err) {}
|
||
|
||
this.views = views;
|
||
this.hasSolution = (typeof views.solution !== 'undefined');
|
||
if (this.hasSolution && this.graderScore) {
|
||
this.prevSavedScore = this.graderScore;
|
||
}
|
||
var self = this;
|
||
this.checkAnswerInterval = setInterval(
|
||
function() {
|
||
self.checkAnswerChanged();
|
||
}, 1000);
|
||
task.getAnswer(function(answer) {
|
||
self.defaultAnswer = answer;
|
||
self.refreshMessages = true;
|
||
self.checkAnswerChanged();
|
||
});
|
||
},
|
||
|
||
reloadAnswer: function(strAnswer) {
|
||
this.savedAnswer = strAnswer;
|
||
this.prevAnswer = strAnswer;
|
||
this.submittedAnswer = strAnswer;
|
||
var that = this;
|
||
if (this.showScore) {
|
||
// TODO we only know the answer here, and not the state. Possibly problematic?
|
||
this.updateScore(strAnswer, true, function() {
|
||
that.checkAnswerChanged(); // necessary?
|
||
});
|
||
} else {
|
||
that.checkAnswerChanged(); // necessary?
|
||
}
|
||
},
|
||
|
||
reloadState: function() {
|
||
this.checkAnswerChanged(); // necessary?
|
||
},
|
||
|
||
stopShowingResult: function() {
|
||
this.stoppedShowingResult = true;
|
||
this.updateMessages();
|
||
},
|
||
|
||
/**********************
|
||
* Internal functions *
|
||
**********************/
|
||
restartAll: function() {
|
||
if(this.confirmRestartAll) {
|
||
this.showPopupMessage(this.strings.confirmRestart, 'blanket', this.strings.yes, this.restartAllNoConfirm, this.strings.no);
|
||
}
|
||
else {
|
||
this.restartAllNoConfirm();
|
||
}
|
||
},
|
||
|
||
restartAllNoConfirm: function() {
|
||
displayHelper.stopShowingResult();
|
||
if (!displayHelper.hasLevels) {
|
||
// TODO is this the desired behavior for no levels?
|
||
task.reloadAnswer('', function() {});
|
||
} else {
|
||
task.getAnswer(function(strAnswer) {
|
||
var answer = $.parseJSON(strAnswer);
|
||
var defaultAnswer = task.getDefaultAnswerObject();
|
||
var level = displayHelper.taskLevel;
|
||
answer[level] = defaultAnswer[level];
|
||
task.reloadAnswer(JSON.stringify(answer), function() {});
|
||
});
|
||
}
|
||
},
|
||
|
||
setValidateString: function(str) {
|
||
this.customValidateString = str;
|
||
$("#displayHelper_validate > input").val(str);
|
||
},
|
||
|
||
callValidate: function() {
|
||
if (this.customValidate != undefined) {
|
||
this.customValidate();
|
||
} else {
|
||
platform.validate("none", function() {});
|
||
}
|
||
},
|
||
|
||
validate: function(mode) {
|
||
this.stoppedShowingResult = false;
|
||
var self = this;
|
||
if (mode == 'log') {
|
||
// Ignore it? Do something?
|
||
} else if (mode == 'cancel') {
|
||
this.savedAnswer = '';
|
||
task.reloadAnswer('', function() {
|
||
self.checkAnswerChanged();
|
||
});
|
||
} else {
|
||
task.getAnswer(function(strAnswer) {
|
||
if (!self.hasSolution) {
|
||
self.prevSavedScore = self.graderScore;
|
||
if (self.hasLevels) {
|
||
self.prevLevelsScores[self.taskLevel] = self.levelsScores[self.taskLevel];
|
||
}
|
||
}
|
||
var refresh = function() {
|
||
self.refreshMessages = true;
|
||
self.checkAnswerChanged();
|
||
};
|
||
self.submittedAnswer = strAnswer;
|
||
if (self.showScore) {
|
||
self.updateScore(strAnswer, false, refresh, (mode == "silent"));
|
||
} else {
|
||
self.savedAnswer = strAnswer;
|
||
refresh();
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
updateScore: function(strAnswer, allLevels, callback, silentMode) {
|
||
var self = this;
|
||
function refresh() {
|
||
self.refreshMessages = true;
|
||
self.checkAnswerChanged();
|
||
callback();
|
||
}
|
||
if (allLevels) {
|
||
// TODO: make sure the grader doesn't evaluate each level at each call (most do right now!)
|
||
var levelsToDo = this.levels.slice();
|
||
var updateNextScore = null;
|
||
updateNextScore = function() {
|
||
var nextLevel = levelsToDo.shift();
|
||
if(nextLevel) {
|
||
self.updateScoreOneLevel(strAnswer, nextLevel, updateNextScore);
|
||
} else {
|
||
refresh();
|
||
}
|
||
}
|
||
updateNextScore();
|
||
} else {
|
||
this.updateScoreOneLevel(strAnswer, this.taskLevel, function() {
|
||
if (!silentMode) {
|
||
if (self.hasLevels) {
|
||
self.showValidatePopup(self.taskLevel);
|
||
} else {
|
||
self.showValidatePopup();
|
||
}
|
||
}
|
||
callback();
|
||
}, silentMode);
|
||
}
|
||
},
|
||
updateScoreOneLevel: function(strAnswer, gradedLevel, callback, silentMode) {
|
||
var self = this;
|
||
this.graderMessage = this.strings.gradingInProgress;
|
||
task.getLevelGrade(strAnswer, null, function(score, message) {
|
||
score = +score;
|
||
self.submittedScore = score;
|
||
if (self.hasSolution) {
|
||
self.graderScore = score;
|
||
self.levelsScores[gradedLevel] = score;
|
||
} else {
|
||
if (self.hasLevels) {
|
||
if (score > self.levelsScores[gradedLevel]) {
|
||
self.levelsScores[gradedLevel] = score;
|
||
self.graderScore = score;
|
||
if (self.savedAnswer === '') {
|
||
self.savedAnswer = strAnswer;
|
||
} else {
|
||
var savedAnswerObj = $.parseJSON(self.savedAnswer);
|
||
var answerObj = $.parseJSON(strAnswer);
|
||
savedAnswerObj[gradedLevel] = answerObj[gradedLevel];
|
||
self.savedAnswer = JSON.stringify(savedAnswerObj);
|
||
}
|
||
}
|
||
} else if (score > self.graderScore) {
|
||
self.savedAnswer = strAnswer;
|
||
self.graderScore = score;
|
||
}
|
||
}
|
||
if (silentMode) {
|
||
message = "";
|
||
}
|
||
if (message !== undefined) {
|
||
self.graderMessage = message;
|
||
} else {
|
||
self.graderMessage = "";
|
||
}
|
||
// TODO : should not be called from here, might update the display of a level not currently opened!
|
||
if (self.hasLevels) {
|
||
self.updateScoreDisplays(gradedLevel);
|
||
}
|
||
callback();
|
||
}, gradedLevel);
|
||
},
|
||
updateScoreDisplays: function(gradedLevel) {
|
||
var scores = this.levelsScores;
|
||
var maxScores = this.levelsMaxScores;
|
||
if (this.pointsAsStars) {
|
||
this.updateStarsAtLevel(gradedLevel);
|
||
drawStars('titleStars', this.maxStars, 24, this.graderScore / maxScores.hard, 'normal');
|
||
} else {
|
||
$('#tabScore_' + gradedLevel).html(scores[gradedLevel]);
|
||
$('#bestScore').html(this.graderScore);
|
||
}
|
||
|
||
var gradedLevelNum = $.inArray(gradedLevel, this.levels);
|
||
var curLevel;
|
||
// Possibly unlocking a level
|
||
if (maxScores[gradedLevel] == scores[gradedLevel]) {
|
||
var unlockedLevel = gradedLevelNum + 1;
|
||
if (unlockedLevel < this.levels.length && unlockedLevel >= this.unlockedLevels) {
|
||
curLevel = this.levels[unlockedLevel];
|
||
$('#tab_' + curLevel).removeClass('lockedLevel');
|
||
this.unlockedLevels++;
|
||
this.updateStarsAtLevel(curLevel);
|
||
}
|
||
}
|
||
if (scores[gradedLevel] == this.graderScore) {
|
||
// Marks levels that can't earn points as useless
|
||
for (curLevel in this.levelsRanks) {
|
||
if (maxScores[curLevel] > this.graderScore) {
|
||
break;
|
||
}
|
||
if (this.pointsAsStars) {
|
||
this.updateStarsAtLevel(curLevel);
|
||
}
|
||
$('#tab_' + curLevel).addClass('uselessLevel');
|
||
}
|
||
}
|
||
},
|
||
showValidatePopup: function(gradedLevel) {
|
||
var curTime = new Date().getTime();
|
||
var secondsSinceLoaded = (curTime - this.timeLoaded) / 1000;
|
||
var actionNext = "stay";
|
||
// Display popup to indicate what to do next
|
||
var fullMessage = this.graderMessage;
|
||
var maxScores = this.levelsMaxScores;
|
||
var buttonText = this.strings.alright;
|
||
var avatarMood = "error";
|
||
if ((gradedLevel == undefined) && (this.graderScore >= this.taskParams.maxScore - 0.001)) {
|
||
avatarMood = "success";
|
||
buttonText = this.strings.moveOn;
|
||
fullMessage += "<br/><br/>";
|
||
actionNext = "nextTask";
|
||
fullMessage += this.strings.solvedMoveOn;
|
||
} else if (maxScores && (gradedLevel !== undefined) && this.graderScore >= maxScores[gradedLevel] - 0.001) {
|
||
avatarMood = "success";
|
||
buttonText = this.strings.moveOn;
|
||
fullMessage += "<br/><br/>";
|
||
var levelIdx = this.levelsIdx[gradedLevel];
|
||
var nextLevel = levelIdx !== undefined && levelIdx < this.levels.length-1 ? this.levels[levelIdx+1] : null;
|
||
if(nextLevel) {
|
||
// Offer to try next task if the user solved this difficulty slowly
|
||
var threshold = this.thresholds[gradedLevel];
|
||
if(!threshold) {
|
||
if(gradedLevel == "medium") { threshold = this.thresholdMedium; }
|
||
else if(gradedLevel == "easy") { threshold = this.thresholdEasy; }
|
||
}
|
||
if(!threshold || (threshold && secondsSinceLoaded < threshold)) {
|
||
actionNext = nextLevel;
|
||
if(gradedLevel == "easy") { fullMessage += this.strings.tryMediumLevel; }
|
||
if(gradedLevel == "medium") { fullMessage += this.strings.tryHardLevel; }
|
||
} else {
|
||
actionNext = "nextTask";
|
||
fullMessage += this.strings.tryNextTask;
|
||
}
|
||
} else {
|
||
// Solved the last level, move on
|
||
actionNext = "nextTask";
|
||
fullMessage += this.strings.solvedMoveOn;
|
||
}
|
||
}
|
||
var self = this;
|
||
// Offer an option to stay on the task instead of forcing nextTask
|
||
var noButtonText = actionNext == "nextTask" ? this.strings.no : null;
|
||
this.showPopupMessage(fullMessage, 'blanket', buttonText,
|
||
function() {
|
||
// TODO: replace with something compatible with the API.
|
||
try {
|
||
$(parent.document).scrollTop(0);
|
||
} catch (e) {
|
||
}
|
||
if (actionNext == "nextTask") {
|
||
platform.validate("nextImmediate");
|
||
} else if(self.levelsIdx[actionNext] !== undefined) {
|
||
self.setLevel(actionNext);
|
||
}
|
||
},
|
||
noButtonText,
|
||
avatarMood
|
||
);
|
||
},
|
||
|
||
// Does task have unsaved answers?
|
||
hasNonSavedAnswer: function(callback) {
|
||
if (!task) {
|
||
return false;
|
||
}
|
||
var self = this;
|
||
task.getAnswer(function(curAnswer) {
|
||
if (curAnswer != self.prevAnswer) {
|
||
try {
|
||
if (self != top && parent.Tracker) {
|
||
var data = {
|
||
dataType: 'nonSavedAnswer', teamID: parent.teamID, questionKey: parent.currentQuestionKey, answer: curAnswer
|
||
};
|
||
// Call TrackData, only when loaded in an iframe
|
||
// this is not yet document in the API, but should be soonish
|
||
parent.Tracker.trackData(data);
|
||
}
|
||
} catch (e) {}
|
||
self.prevAnswer = curAnswer;
|
||
}
|
||
if (curAnswer != self.submittedAnswer) {
|
||
self.submittedAnswer = '';
|
||
self.refreshMessages = true;
|
||
}
|
||
if (curAnswer == self.defaultAnswer && self.savedAnswer === '') {
|
||
callback(false);
|
||
} else {
|
||
callback(curAnswer != self.submittedAnswer);
|
||
}
|
||
});
|
||
},
|
||
|
||
// Checks task.getAnswer() against previously recorded result, and calls
|
||
// displayHelper.updateMessages() accordingly.
|
||
checkAnswerChanged: function() {
|
||
if (!this.loaded) {
|
||
this.checkAnswerInterval = clearInterval(this.checkAnswerInterval);
|
||
return;
|
||
}
|
||
var self = this;
|
||
this.hasNonSavedAnswer(function(hasNonSavedAnswer) {
|
||
if (hasNonSavedAnswer && !self.hasAnswerChanged) {
|
||
self.refreshMessages = true;
|
||
self.hasAnswerChanged = true;
|
||
} else if (!hasNonSavedAnswer && self.hasAnswerChanged) {
|
||
self.refreshMessages = true;
|
||
self.hasAnswerChanged = false;
|
||
}
|
||
if (self.refreshMessages) {
|
||
self.updateMessages();
|
||
}
|
||
});
|
||
},
|
||
|
||
getFullFeedbackSavedMessage: function(taskMode) {
|
||
var scoreDiffMsg = this.strings.score;
|
||
var showRetrieveAnswer = false;
|
||
if (this.submittedAnswer !== '' && this.prevSavedScore !== undefined) {
|
||
if (!this.hasSolution) {
|
||
if (this.prevSavedScore < this.submittedScore) {
|
||
scoreDiffMsg = this.strings.yourScoreIsNow;
|
||
} else if (this.prevSavedScore > this.submittedScore) {
|
||
scoreDiffMsg = this.strings.worseScoreStays;
|
||
showRetrieveAnswer = true;
|
||
}
|
||
else {
|
||
scoreDiffMsg = this.strings.scoreStays;
|
||
}
|
||
} else {
|
||
if (this.prevSavedScore != this.submittedScore) {
|
||
scoreDiffMsg = this.strings.contestOverScoreStays + " " + this.prevSavedScore + ". " + this.strings.scoreWouldBecome;
|
||
} else if (this.submittedAnswer != this.savedAnswer) {
|
||
scoreDiffMsg = this.strings.contestOverScoreStays + " " + this.prevSavedScore + ". " + this.strings.scoreWouldStay;
|
||
} else {
|
||
scoreDiffMsg = this.strings.scoreIs;
|
||
}
|
||
}
|
||
}
|
||
scoreDiffMsg += " " + this.graderScore + this.strings.outOf + this.taskParams.maxScore + ".";
|
||
if ((this.hasSolution && this.savedAnswer != this.prevAnswer) ||
|
||
(this.graderScore > 0 && (taskMode == 'saved_changed' || showRetrieveAnswer))) {
|
||
scoreDiffMsg += ' <a href="#" onclick="displayHelper.retrieveAnswer(); return false;">' + this.strings.reloadValidAnswer + '</a>';
|
||
}
|
||
return scoreDiffMsg;
|
||
},
|
||
getFullFeedbackWithLevelsSavedMessage: function() {
|
||
var maxScoreLevel = this.levelsMaxScores[this.taskLevel];
|
||
var showRetrieveAnswer = false;
|
||
var message = "";
|
||
var curAnswer = this.submittedAnswer;
|
||
var answerExists = false;
|
||
if (curAnswer !== '') {
|
||
curAnswer = $.parseJSON(curAnswer);
|
||
answerExists = !$.isEmptyObject(curAnswer);
|
||
}
|
||
if (!answerExists) {
|
||
if (this.levelsScores[this.taskLevel] > 0) {
|
||
if (this.hideScoreDetails) {
|
||
message = this.strings.scoreObtained + ' <span id="answerScore">' + this.levelsScores[this.taskLevel] + " " + strPoint + " " + this.strings.outOf + " " + maxScoreLevel + ".</span><br/>";;
|
||
} else {
|
||
showRetrieveAnswer = true;
|
||
}
|
||
} else {
|
||
message += this.strings.noPointsForLevel;
|
||
}
|
||
} else {
|
||
var strPoint = this.strings.point;
|
||
if (this.submittedScore > 1) {
|
||
strPoint = this.strings.points;
|
||
}
|
||
message = this.strings.scoreObtained + ' <span id="answerScore">' + this.submittedScore + " " + strPoint + " " + this.strings.outOf + " " + maxScoreLevel + ".</span><br/>";
|
||
if (this.hideScoreDetails) {
|
||
} else if (this.hasSolution) {
|
||
message += this.strings.contestOverAnswerNotSaved;
|
||
if (this.prevSavedScore !== undefined) {
|
||
showRetrieveAnswer = true;
|
||
}
|
||
} else {
|
||
var prevScore = this.prevLevelsScores[this.taskLevel];
|
||
if (this.prevSavedScore !== undefined) {
|
||
if (this.submittedScore > prevScore) {
|
||
if (this.submittedScore < maxScoreLevel) {
|
||
if (this.taskLevel == "hard") {
|
||
message += this.strings.tryToDoBetterOrChangeTask;
|
||
} else {
|
||
message += this.strings.tryToDoBetterOrMoveToNextLevel;
|
||
}
|
||
} else if (this.taskLevel == "hard") {
|
||
message += this.strings.bestPossibleScoreCongrats;
|
||
} else {
|
||
message += this.strings.forMorePointsMoveToNextLevel;
|
||
}
|
||
} else if (this.submittedScore < prevScore) {
|
||
message += this.strings.youDidBetterBefore;
|
||
showRetrieveAnswer = true;
|
||
}
|
||
else {
|
||
message += this.strings.scoreStays2;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (showRetrieveAnswer) {
|
||
message += ' <a href="#" onclick="displayHelper.retrieveAnswer(); return false;">' + this.strings.reloadBestAnswer + '</a>';
|
||
}
|
||
return message;
|
||
},
|
||
getFullFeedbackGraderMessage: function(taskMode) {
|
||
switch (taskMode) {
|
||
case 'saved_unchanged':
|
||
var color = 'red';
|
||
if (this.submittedScore == this.taskParams.maxScore) {
|
||
color = 'green';
|
||
} else if (this.submittedScore > 0) {
|
||
color = '#ff8c00';
|
||
}
|
||
if (this.graderMessage !== "") {
|
||
if (!this.stoppedShowingResult) {
|
||
return '<div style="margin: .2em 0; color: ' + color + '; font-weight: bold;">' + this.graderMessage + '</div>';
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
return '';
|
||
},
|
||
// TODO: rename function below to getFullFeedbackValidate, assuming it is not called from outside this file
|
||
getFullFeedbackValidateMessage: function(taskMode, disabledStr) {
|
||
var strValidate = this.strings.validate;
|
||
if (this.customValidateString != undefined) {
|
||
strValidate = this.customValidateString;
|
||
}
|
||
switch (taskMode) {
|
||
case 'saved_unchanged':
|
||
if (this.graderMessage !== "") {
|
||
if (!this.hideValidateButton && !this.hasSolution) {
|
||
return '<input type="button" value="' + strValidate + '" onclick="displayHelper.callValidate();" ' +
|
||
disabledStr + '/>';
|
||
}
|
||
}
|
||
break;
|
||
case 'unsaved_unchanged':
|
||
case 'unsaved_changed':
|
||
if (!this.hideValidateButton) {
|
||
if (this.hasSolution) {
|
||
return '<input type="button" value="' + this.strings.gradeThisAnswer + '" onclick="displayHelper.validate(\'test\');" ' +
|
||
disabledStr + '/>';
|
||
} else {
|
||
return '<input type="button" value="' + strValidate + '" onclick="displayHelper.callValidate();" ' +
|
||
disabledStr + '/>';
|
||
}
|
||
}
|
||
break;
|
||
case 'saved_changed':
|
||
if (!this.hideValidateButton) {
|
||
if (this.hasSolution) {
|
||
return '<input type="button" value="' + this.strings.gradeThisAnswer + '" onclick="displayHelper.validate(\'test\');" ' +
|
||
disabledStr + '/>';
|
||
} else {
|
||
// was: Valider votre nouvelle réponse
|
||
return '<input type="button" value="' + strValidate + '" onclick="displayHelper.callValidate();" ' +
|
||
disabledStr + '/>';
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
return '';
|
||
},
|
||
|
||
lastSentHeight: null,
|
||
updateMessages: function() {
|
||
this.initLanguage();
|
||
var self = this;
|
||
this.refreshMessages = false;
|
||
var suffix, prefix;
|
||
if (this.hasAnswerChanged) {
|
||
suffix = 'changed';
|
||
} else {
|
||
suffix = 'unchanged';
|
||
}
|
||
if (this.savedAnswer !== '' && this.savedAnswer != this.defaultAnswer) {
|
||
prefix = 'saved';
|
||
} else {
|
||
prefix = 'unsaved';
|
||
}
|
||
if (this.submittedAnswer !== '' && this.submittedAnswer != this.savedAnswer) {
|
||
prefix = 'saved'; // equivalent, should be named differently
|
||
suffix = 'unchanged';
|
||
}
|
||
var taskMode = prefix + '_' + suffix;
|
||
var messages = { graderMessage: '', validate: '', cancel: '', saved: '' };
|
||
var disabledStr = this.readOnly ? ' disabled' : '';
|
||
if (this.showScore) {
|
||
if (!this.hideRestartButton) {
|
||
messages.cancel = '<input type="button" value="' + this.strings.restart + '" onclick="displayHelper.restartAll();"' +
|
||
disabledStr + '/></div>';
|
||
}
|
||
messages.graderMessage = this.getFullFeedbackGraderMessage(taskMode);
|
||
messages.validate = this.getFullFeedbackValidateMessage(taskMode, disabledStr);
|
||
if (this.hasLevels) {
|
||
messages.saved = this.getFullFeedbackWithLevelsSavedMessage(taskMode);
|
||
} else {
|
||
messages.saved = this.getFullFeedbackSavedMessage(taskMode);
|
||
}
|
||
} else {
|
||
switch (taskMode) {
|
||
case 'unsaved_unchanged':
|
||
case 'unsaved_changed':
|
||
if (!this.hasSolution) {
|
||
messages.validate = '<input type="button" value="' + this.strings.saveAnswer + '" ' +
|
||
'onclick="platform.validate(\'done\', function(){})" ' + disabledStr + '/>';
|
||
}
|
||
break;
|
||
case 'saved_unchanged':
|
||
if (!this.hasSolution) {
|
||
messages.saved = this.formatTranslation(this.strings.answerSavedModifyOrCancelIt,
|
||
["<a href='#' onclick=\"platform.validate('cancel', function(){}); return false;\" " + disabledStr + ">" + this.strings.cancelIt + "</a>"]);
|
||
} else {
|
||
messages.saved = this.formatTranslation(this.strings.answerNotSavedContestOver,
|
||
["<a href='#' onclick=\"displayHelper.validate('cancel'); return false;\" " + disabledStr + ">" + this.strings.reloadSubmittedAnswer + "</a>"]);
|
||
}
|
||
break;
|
||
case 'saved_changed':
|
||
messages.saved = "<br/><b style='color: red;'>" + this.strings.warningDifferentAnswerSaved + "</b> " +
|
||
this.formatTranslation(this.strings.youMay, ["<a href='#' onclick='displayHelper.retrieveAnswer(); return false;'>" + this.strings.reloadIt + "</a>"]);
|
||
if (!this.hideValidateButton) {
|
||
messages.validate = "<input type='button' value='" + this.strings.saveThisNewAnswer + "' onclick=\"platform.validate('done', function(){})\" " + disabledStr + "/>";
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
for (var type in messages) {
|
||
if (this.loaded && (typeof this.previousMessages[type] === 'undefined' || this.previousMessages[type] !== messages[type])) {
|
||
$('#displayHelper_' + type).html(messages[type]);
|
||
this.previousMessages[type] = messages[type];
|
||
}
|
||
}
|
||
if (this.pointsAsStars && $('#answerScore').length) {
|
||
drawStars('answerScore', this.levelsRanks[this.taskLevel], 20,
|
||
this.levelsScores[this.taskLevel] / this.levelsMaxScores[this.taskLevel], 'normal');
|
||
}
|
||
window.task.getHeight(function(height) {
|
||
if (height != self.lastSentHeight) {
|
||
self.lastSentHeight = height;
|
||
window.platform.updateDisplay({height: height}, function(){});
|
||
}
|
||
});
|
||
},
|
||
|
||
getSavedAnswer: function() {
|
||
// Gets the previously saved answer
|
||
var retrievedAnswer;
|
||
if (this.hasLevels) {
|
||
var savedAnswerObj = this.savedAnswer && $.parseJSON(this.savedAnswer);
|
||
if(savedAnswerObj) {
|
||
var retrievedAnswerObj = task.getAnswerObject();
|
||
retrievedAnswerObj[this.taskLevel] = savedAnswerObj[this.taskLevel];
|
||
retrievedAnswer = retrievedAnswerObj[this.taskLevel] && JSON.stringify(retrievedAnswerObj);
|
||
} else {
|
||
retrievedAnswer = null;
|
||
}
|
||
} else {
|
||
retrievedAnswer = this.savedAnswer;
|
||
}
|
||
return retrievedAnswer;
|
||
},
|
||
retrieveAnswer: function() {
|
||
// Loads previously saved answer
|
||
var retrievedAnswer = this.getSavedAnswer();
|
||
if(!retrievedAnswer) {
|
||
this.showPopupMessage(this.strings.noAnswerSaved, 'blanket', this.strings.alright, null, null, "warning");
|
||
return;
|
||
}
|
||
var self = displayHelper;
|
||
task.reloadAnswer(retrievedAnswer, function() {
|
||
self.submittedAnswer = self.savedAnswer;
|
||
self.updateScore(self.savedAnswer, false, function() {});
|
||
});
|
||
},
|
||
hasSavedAnswer: function() {
|
||
// Returns whether a saved answer exists
|
||
if (this.hasLevels) {
|
||
var savedAnswerObj = this.savedAnswer && $.parseJSON(this.savedAnswer);
|
||
if(savedAnswerObj) {
|
||
return !!savedAnswerObj[this.taskLevel];
|
||
}
|
||
} else {
|
||
return !!this.savedAnswer;
|
||
}
|
||
return false;
|
||
},
|
||
|
||
sendBestScore: function(callback, scores, messages) {
|
||
var bestLevel = 'easy';
|
||
for (var curLevel in scores) {
|
||
if (scores[bestLevel] <= scores[curLevel]) {
|
||
bestLevel = curLevel;
|
||
}
|
||
}
|
||
callback(scores[bestLevel], messages[bestLevel] + " (" + this.strings["levelVersionName_" + bestLevel] + ")");
|
||
}
|
||
};
|
||
|
||
|
||
/*
|
||
draw nbStars stars of width starWidth in element of id id
|
||
fills rate% of them in yellow from the left
|
||
mode is "norma", "locked" or "useless"
|
||
*/
|
||
function drawStars(id, nbStars, starWidth, rate, mode) {
|
||
$('#' + id).addClass('stars');
|
||
|
||
function clipPath(coords, xClip) {
|
||
var result = [[coords[0][0], coords[0][1]]];
|
||
var clipped = false;
|
||
for (var iCoord = 1; iCoord <= coords.length; iCoord++) {
|
||
var x1 = coords[iCoord - 1][0];
|
||
var y1 = coords[iCoord - 1][1];
|
||
var x2 = coords[iCoord % coords.length][0];
|
||
var y2 = coords[iCoord % coords.length][1];
|
||
if (x2 > xClip) {
|
||
if (!clipped) {
|
||
result.push([xClip, y1 + (y2 - y1) * (xClip - x1) / (x2 - x1)]);
|
||
clipped = true;
|
||
}
|
||
} else {
|
||
if (clipped) {
|
||
result.push([xClip, y1 + (y2 - y1) * (xClip - x1) / (x2 - x1)]);
|
||
clipped = false;
|
||
}
|
||
result.push([x2, y2]);
|
||
}
|
||
}
|
||
result.pop();
|
||
return result;
|
||
}
|
||
|
||
function pathFromCoords(coords) {
|
||
var result = 'm' + coords[0][0] + ',' + coords[0][1];
|
||
for (var iCoord = 1; iCoord < coords.length; iCoord++) {
|
||
var x1 = coords[iCoord - 1][0];
|
||
var y1 = coords[iCoord - 1][1];
|
||
var x2 = coords[iCoord][0];
|
||
var y2 = coords[iCoord][1];
|
||
result += ' ' + (x2 - x1) + ',' + (y2 - y1);
|
||
}
|
||
result += 'z';
|
||
return result;
|
||
}
|
||
|
||
var fillColors = { normal: 'white', locked: '#ddd', useless: '#ced' };
|
||
var strokeColors = { normal: 'black', locked: '#ddd', useless: '#444' };
|
||
var starCoords = [[25, 60], [5, 37], [35, 30], [50, 5], [65, 30], [95, 37], [75, 60], [78, 90], [50, 77], [22, 90]];
|
||
var fullStarCoords = [
|
||
[[5, 37], [35, 30], [50, 5], [65, 30], [95, 37], [75, 60], [25, 60]],
|
||
[[22, 90], [50, 77], [78, 90], [75, 60], [25, 60]]
|
||
];
|
||
|
||
|
||
if ($('#' + id).length == 0) {
|
||
return;
|
||
}
|
||
$('#' + id).html('');
|
||
var paper = new Raphael(id, starWidth * nbStars, starWidth * 0.95);
|
||
for (var iStar = 0; iStar < nbStars; iStar++) {
|
||
var scaleFactor = starWidth / 100;
|
||
var deltaX = iStar * starWidth;
|
||
var coordsStr = pathFromCoords(starCoords, iStar * 100);
|
||
|
||
paper.path(coordsStr).attr({
|
||
fill: fillColors[mode],
|
||
stroke: 'none'
|
||
}).transform('s' + scaleFactor + ',' + scaleFactor + ' 0,0 t' + (deltaX / scaleFactor) + ',0');
|
||
|
||
var ratio = Math.min(1, Math.max(0, rate * nbStars - iStar));
|
||
var xClip = ratio * 100;
|
||
if (xClip > 0) {
|
||
for (var iPiece = 0; iPiece < fullStarCoords.length; iPiece++) {
|
||
var coords = clipPath(fullStarCoords[iPiece], xClip);
|
||
var star = paper.path(pathFromCoords(coords)).attr({
|
||
fill: '#ffc90e',
|
||
stroke: 'none'
|
||
}).transform('s' + scaleFactor + ',' + scaleFactor + ' 0,0 t' + (deltaX / scaleFactor) + ",0");
|
||
}
|
||
}
|
||
paper.path(coordsStr).attr({
|
||
fill: 'none',
|
||
stroke: strokeColors[mode],
|
||
'stroke-width': 5 * scaleFactor
|
||
}).transform('s' + scaleFactor + ',' + scaleFactor + ' 0,0 t' + (deltaX / scaleFactor) + ',0');
|
||
}
|
||
}
|
||
|
||
|
||
window.platform.subscribe(displayHelper);
|
||
|
||
})();
|
||
|
||
var Beav = new Object();
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Object */
|
||
|
||
Beav.Object = new Object();
|
||
|
||
Beav.Object.eq = function eq(x, y) {
|
||
// assumes arguments to be of same type
|
||
var tx = typeof(x);
|
||
var ty = typeof(y);
|
||
if (tx != ty) {
|
||
throw "Beav.Object.eq incompatible types";
|
||
}
|
||
if (tx == "boolean" || tx == "number" || tx == "string" || tx == "undefined") {
|
||
return x == y;
|
||
}
|
||
if ($.isArray(x)) {
|
||
if (! $.isArray(y))
|
||
throw "Beav.Object.eq incompatible types";
|
||
if (x.length != y.length)
|
||
return false;
|
||
for (var i = 0; i < x.length; i++)
|
||
if (! eq(x[i], y[i]))
|
||
return false;
|
||
return true;
|
||
}
|
||
if (tx == "object") {
|
||
var kx = [];
|
||
for (var key in x) {
|
||
kx.push(key);
|
||
}
|
||
var ky = [];
|
||
for (var key in y) {
|
||
ky.push(key);
|
||
}
|
||
var sort_keys = function(n1,n2) { return (n1 < n2) ? -1 : ((n1 > n2) ? 1 : 0); };
|
||
kx.sort(sort_keys);
|
||
ky.sort(sort_keys);
|
||
if (kx.length != ky.length)
|
||
return false;
|
||
for (var i = 0; i < kx.length; i++) {
|
||
var ex = kx[i];
|
||
var ey = ky[i];
|
||
if (ex != ey)
|
||
return false;
|
||
if (! eq(x[ex], y[ex]))
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
throw "Beav.Object.eq unsupported types";
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Array */
|
||
|
||
Beav.Array = new Object();
|
||
|
||
Beav.Array.make = function(nb, initValue) {
|
||
var t = [];
|
||
for (var i = 0; i < nb; i++)
|
||
t[i] = initValue;
|
||
return t;
|
||
};
|
||
|
||
Beav.Array.init = function(nb, initFct) {
|
||
var t = [];
|
||
for (var i = 0; i < nb; i++)
|
||
t.push(initFct(i));
|
||
return t;
|
||
};
|
||
|
||
Beav.Array.indexOf = function(t, v, eq) {
|
||
if (eq === undefined)
|
||
eq = Beav.Object.eq;
|
||
for (var i = 0; i < t.length; i++)
|
||
if (eq(t[i], v))
|
||
return i;
|
||
return -1;
|
||
};
|
||
|
||
Beav.Array.has = function(t, v, eq) {
|
||
return Beav.Array.indexOf(t, v, eq) != -1;
|
||
};
|
||
|
||
Beav.Array.filterCount = function(t, filterFct) {
|
||
var count = 0;
|
||
for (var i = 0; i < t.length; i++)
|
||
if (filterFct(t[i], i))
|
||
count++;
|
||
return count;
|
||
};
|
||
|
||
Beav.Array.stableSort = function(t, compFct) {
|
||
var swap = function(a, b) {
|
||
var v = t[a];
|
||
t[a] = t[b];
|
||
t[b] = v;
|
||
};
|
||
var insert = function (i, j, v) {
|
||
while(i+1 < j && compFct(t[i+1], v) < 0) {
|
||
swap(i, i+1);
|
||
i++;
|
||
}
|
||
t[i] = v;
|
||
};
|
||
var merge = function(i, k, j) {
|
||
for ( ; i<k; i++) {
|
||
if (compFct(t[k], t[i]) < 0) {
|
||
var v = t[i];
|
||
t[i] = t[k];
|
||
insert(k, j, v);
|
||
}
|
||
}
|
||
};
|
||
var msort = function msort(i, j) {
|
||
var size = j - i;
|
||
if (size < 2)
|
||
return;
|
||
var k = i + Math.floor(size/2);
|
||
msort(i, k);
|
||
msort(k, j);
|
||
merge(i, k, j);
|
||
};
|
||
msort(0, t.length);
|
||
};
|
||
|
||
Beav.Array.shuffle = function(t, randomSeed) {
|
||
var nbValues = t.length;
|
||
for (var iValue = 0; iValue < nbValues; iValue++) {
|
||
// TODO: we should pick the next random number at every step
|
||
// by calling, e.g., randomSeed = RandomGenerator.next(randomSeed);
|
||
var randomShift = randomSeed % (nbValues - iValue);
|
||
var pos = iValue + randomShift;
|
||
var tmp = t[iValue];
|
||
t[iValue] = t[pos];
|
||
t[pos] = tmp;
|
||
}
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Matrix */
|
||
|
||
Beav.Matrix = new Object();
|
||
|
||
Beav.Matrix.init = function(nbRows, nbCols, initFct) {
|
||
var m = [];
|
||
for (var x = 0; x < nbRows; x++) {
|
||
var t = [];
|
||
for (var y = 0; y < nbCols; y++) {
|
||
t.push(initFct(x, y));
|
||
}
|
||
m.push(t);
|
||
}
|
||
return m;
|
||
};
|
||
|
||
Beav.Matrix.map = function(m, mapFct) {
|
||
var r = [];
|
||
for (var x = 0; x < m.length; x++) {
|
||
r[x] = [];
|
||
for (var y = 0; y < m[x].length; y++) {
|
||
r[x][y] = mapFct(m[x][y], x, y, m);
|
||
}
|
||
}
|
||
return r;
|
||
};
|
||
|
||
Beav.Matrix.copy = function(m) {
|
||
return Beav.Matrix.map(m, function(v) { return v; });
|
||
};
|
||
|
||
Beav.Matrix.make = function(nbRows, nbCols, v) {
|
||
return Beav.Matrix.init(nbRows, nbCols, function() { return v; });
|
||
};
|
||
|
||
Beav.Matrix.forEach = function(m, iterFct) {
|
||
for (var x = 0; x < m.length; x++) {
|
||
for (var y = 0; y < m[x].length; y++) {
|
||
iterFct(m[x][y], x, y, m);
|
||
}
|
||
}
|
||
};
|
||
|
||
Beav.Matrix.filterCount = function(m, selectFct) {
|
||
var count = 0;
|
||
for (var x = 0; x < m.length; x++) {
|
||
for (var y = 0; y < m[x].length; y++) {
|
||
if (selectFct(m[x][y], x, y)) {
|
||
count++;
|
||
}
|
||
}
|
||
}
|
||
return count;
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Matrix3D */
|
||
|
||
Beav.Matrix3D = new Object();
|
||
|
||
Beav.Matrix3D.init = function(nbX, nbY, nbZ, initFct) {
|
||
var m = [];
|
||
for (var x = 0; x < nbX; x++) {
|
||
var t = [];
|
||
for (var y = 0; y < nbY; y++) {
|
||
var r = [];
|
||
for (var z = 0; z < nbZ; z++) {
|
||
r.push(initFct(x, y, z));
|
||
}
|
||
t.push(r);
|
||
}
|
||
m.push(t);
|
||
}
|
||
return m;
|
||
};
|
||
|
||
Beav.Matrix3D.map = function(m, mapFct) {
|
||
var r = [];
|
||
for (var x = 0; x < m.length; x++) {
|
||
r[x] = [];
|
||
for (var y = 0; y < m[x].length; y++) {
|
||
r[x][y] = [];
|
||
for (var z = 0; z < m[x][y].length; z++) {
|
||
r[x][y][z] = mapFct(m[x][y][z], x, y, z, m);
|
||
}
|
||
}
|
||
}
|
||
return r;
|
||
};
|
||
|
||
Beav.Matrix3D.copy = function(m) {
|
||
return Beav.Matrix3D.map(m, function(v) { return v; });
|
||
};
|
||
|
||
Beav.Matrix3D.make = function(nbX, nbY, nbZ, v) {
|
||
return Beav.Matrix3D.init(nbX, nbY, nbZ, function() { return v; });
|
||
};
|
||
|
||
Beav.Matrix3D.forEach = function(m, iterFct) {
|
||
for (var x = 0; x < m.length; x++) {
|
||
for (var y = 0; y < m[x].length; y++) {
|
||
for (var z = 0; z < m[x][y].length; z++) {
|
||
iterFct(m[x][y][z], x, y, z, m);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
Beav.Matrix3D.filterCount = function(m, selectFct) {
|
||
var count = 0;
|
||
for (var x = 0; x < m.length; x++) {
|
||
for (var y = 0; y < m[x].length; y++) {
|
||
for (var z = 0; z < m[x][y].length; z++) {
|
||
if (selectFct(m[x][y][z], x, y, z)) {
|
||
count++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return count;
|
||
};
|
||
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Exception */
|
||
|
||
/* Mechanism for having user exceptions that cannot be confused
|
||
with JavaScript builtin exceptions.
|
||
|
||
To throw the exception myExn, do:
|
||
|
||
Beav.Exception.throw(myExn);
|
||
|
||
To catch only user exceptions, do:
|
||
|
||
try {
|
||
...
|
||
} catch (exn) {
|
||
var myExn = Beav.Exception.extract(exn);
|
||
...
|
||
}
|
||
|
||
In this case, the exception is automatically re-thrown
|
||
if it is not a user exception.
|
||
|
||
*/
|
||
/*
|
||
Beav.Exception = {};
|
||
|
||
Beav.Exception.constructor = function(arg) {
|
||
this.contents = arg;
|
||
};
|
||
|
||
Beav.Exception.throw = function(arg) {
|
||
throw new Beav.Exception.constructor(arg);
|
||
};
|
||
|
||
Beav.Exception.extract = function(exn) {
|
||
if (exn instanceof Beav.Exception.constructor) {
|
||
return exn.contents;
|
||
} else {
|
||
throw exn;
|
||
}
|
||
};
|
||
*/
|
||
|
||
/**********************************************************************************/
|
||
/* Navigator */
|
||
|
||
Beav.Navigator = new Object();
|
||
|
||
Beav.Navigator.isIE8 = function() {
|
||
return navigator.appVersion.indexOf("MSIE 8.") != -1;
|
||
}
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Dom */
|
||
|
||
Beav.Dom = new Object();
|
||
|
||
Beav.Dom.showOrHide = function(e, visible) {
|
||
if (visible)
|
||
e.show();
|
||
else
|
||
e.hide();
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* HTML */
|
||
|
||
Beav.Html = new Object();
|
||
|
||
// Escape the html characters in a string
|
||
Beav.Html.escape = function(stringToEncode) {
|
||
var entityMap = {
|
||
"&": "&",
|
||
"<": "<",
|
||
">": ">",
|
||
'"': '"',
|
||
"'": ''',
|
||
"/": '/' };
|
||
return String(stringToEncode).replace(/[&<>"'\/]/g, function (s) {
|
||
return entityMap[s];
|
||
});
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Raphael */
|
||
|
||
Beav.Raphael = new Object();
|
||
|
||
Beav.Raphael.line = function(paper, x1, y1, x2, y2) {
|
||
return paper.path([ "M", x1, y1, "L", x2, y2 ]);
|
||
};
|
||
|
||
Beav.Raphael.lineRelative = function(paper, x1, y1, dx, dy) {
|
||
return Beav.Raphael.line(paper, x1, y1, x1+dx, y1+dy);
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Random */
|
||
|
||
Beav.Random = new Object();
|
||
|
||
Beav.Random.bit = function(randomSeed, idBit) {
|
||
return (randomSeed & (1 << idBit)) ? 1 : 0;
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Task */
|
||
|
||
Beav.Task = new Object();
|
||
|
||
Beav.Task.scoreInterpolate = function(minScore, maxScore, minResult, maxResult, result) {
|
||
// requires minResult <= result <= maxResult and minScore <= maxScore
|
||
return Math.round(minScore + (maxScore - minScore) * (result - minResult) / (maxResult - minResult));
|
||
};
|
||
|
||
|
||
/**********************************************************************************/
|
||
/* Geometry */
|
||
|
||
Beav.Geometry = new Object();
|
||
|
||
Beav.Geometry.distance = function(x1,y1,x2,y2) {
|
||
return Math.sqrt(Math.pow(x2 - x1,2) + Math.pow(y2 - y1,2));
|
||
};
|
||
|
||
/*
|
||
This is used to handle drag on devices that have both a touch screen and a mouse.
|
||
Can be tested on chrome by loading a task in desktop mode, then switching to tablet mode.
|
||
To call instead of element.drag(onMove, onStart, onEnd);
|
||
*/
|
||
Beav.dragWithTouch = function(element, onMove, onStart, onEnd) {
|
||
var touchingX = 0;
|
||
var touchingY = 0;
|
||
var disabled = false;
|
||
|
||
function onTouchStart(evt) {
|
||
if (disabled) {
|
||
return;
|
||
}
|
||
var touches = evt.changedTouches;
|
||
touchingX = touches[0].pageX;
|
||
touchingY = touches[0].pageY;
|
||
onStart(touches[0].pageX, touches[0].pageY, evt);
|
||
}
|
||
|
||
function onTouchEnd(evt) {
|
||
if (disabled) {
|
||
return;
|
||
}
|
||
onEnd(null);
|
||
}
|
||
|
||
function onTouchMove(evt) {
|
||
if (disabled) {
|
||
return;
|
||
}
|
||
var touches = evt.changedTouches;
|
||
var dx = touches[0].pageX - touchingX;
|
||
var dy = touches[0].pageY - touchingY;
|
||
onMove(dx, dy, touches[0].pageX, touches[0].pageY, evt);
|
||
}
|
||
|
||
function callOnStart(x,y,event) {
|
||
disabled = true;
|
||
onStart(x,y,event);
|
||
}
|
||
|
||
function callOnMove(dx,dy,x,y,event) {
|
||
disabled = true;
|
||
onMove(dx,dy,x,y,event);
|
||
}
|
||
|
||
function callOnEnd(event) {
|
||
disabled = false;
|
||
onEnd(event);
|
||
}
|
||
|
||
// element.undrag();
|
||
element.drag(callOnMove,callOnStart,callOnEnd);
|
||
if (element.touchstart) {
|
||
element.touchstart(onTouchStart);
|
||
element.touchend(onTouchEnd);
|
||
element.touchcancel(onTouchEnd);
|
||
element.touchmove(onTouchMove);
|
||
}
|
||
}
|
||
(function() {
|
||
|
||
'use strict';
|
||
|
||
// requires jQuery, and a task object in the global scope.
|
||
|
||
// this should be called before the task loads, because the task can modify
|
||
// its html at load, and we want to return unmodified html in getTaskResources.
|
||
var res = {};
|
||
|
||
var taskResourcesLoaded = false;
|
||
|
||
window.implementGetResources = function(task) {
|
||
task.getResources = function(callback)
|
||
{
|
||
if (taskResourcesLoaded) {
|
||
callback(res);
|
||
return;
|
||
}
|
||
res.task = ('task' in res) ? res.task : [{ type: 'html', content: $('#task').html() }];
|
||
res.solution = ('solution' in res) ? res.solution : [{ type: 'html', content: $('#solution').html() }];
|
||
res.grader = [];
|
||
res.task_modules = [];
|
||
res.solution_modules = [];
|
||
res.grader_modules = [];
|
||
if (!res.hints) {
|
||
res.hints = [];
|
||
$('.hint').each(function(index) {
|
||
res.hints[res.hints.length] = [{type: 'html', content: $(this).html() }];
|
||
$(this).attr('hint-Num', res.hints.length-1);
|
||
});
|
||
}
|
||
res.proxy = [];
|
||
res.proxy_modules = [];
|
||
res.display = [];
|
||
res.display_modules = [];
|
||
res.sat = [];
|
||
res.sat_modules = [];
|
||
res.files = [];
|
||
if (!res.title) {
|
||
res.title = $('title').text();
|
||
}
|
||
|
||
// Resources
|
||
var curDest = 'task';
|
||
var curType = 'javascript';
|
||
$('script, style, link').each(function() {
|
||
if ($(this).hasClass('remove')) {
|
||
return;
|
||
}
|
||
if ($(this).hasClass('solution') && $(this).hasClass('module')) {
|
||
curDest = res.solution_modules;
|
||
}
|
||
else if ($(this).hasClass('solution')) {
|
||
curDest = res.solution;
|
||
}
|
||
else if ($(this).hasClass('grader') && $(this).hasClass('module')) {
|
||
curDest = res.grader_modules;
|
||
}
|
||
else if ($(this).hasClass('grader')) {
|
||
curDest = res.grader;
|
||
}
|
||
else if ($(this).hasClass('hint')) {
|
||
res.hints.push([{ type: 'html', content: $(this).html() }]);
|
||
return;
|
||
}
|
||
else if ($(this).hasClass('proxy') && $(this).hasClass('module')) {
|
||
curDest = res.proxy_modules;
|
||
}
|
||
else if ($(this).hasClass('proxy')) {
|
||
curDest = res.proxy;
|
||
}
|
||
else if ($(this).hasClass('stdButtonsAndMessages') && $(this).hasClass('module')) {
|
||
curDest = res.display_modules;
|
||
}
|
||
else if ($(this).hasClass('stdButtonsAndMessages')) {
|
||
curDest = res.display;
|
||
}
|
||
else if ($(this).hasClass('stdAnswerTypes') && $(this).hasClass('module')) {
|
||
curDest = res.sat_modules;
|
||
}
|
||
else if ($(this).hasClass('stdAnswerTypes')) {
|
||
curDest = res.sat;
|
||
}
|
||
else if ($(this).hasClass('module')) {
|
||
curDest = res.task_modules;
|
||
}
|
||
else {
|
||
curDest = res.task;
|
||
}
|
||
|
||
if ($(this).is('script')) {
|
||
curType = 'javascript';
|
||
}
|
||
else if ($(this).is('style') || $(this).is('link')) {
|
||
curType = 'css';
|
||
}
|
||
|
||
if ($(this).attr('src')) {
|
||
curDest.push({ type: curType, url: $(this).attr('src'), id: $(this).attr('id') });
|
||
}
|
||
else if ($(this).attr('href')) {
|
||
curDest.push({ type: curType, url: $(this).attr('href'), id: $(this).attr('id') });
|
||
}
|
||
else {
|
||
curDest.push({ type: curType, id: $(this).attr('id'), content: $(this).html() });
|
||
}
|
||
});
|
||
|
||
// Images
|
||
var images = [];
|
||
var image = '';
|
||
$('#task img').each(function() {
|
||
var src = $(this).attr('src');
|
||
if (src) {
|
||
image = src.toString();
|
||
if ($.inArray(image, images) === -1) {
|
||
res.task.push({ type: 'image', url: image });
|
||
images.push(image);
|
||
}
|
||
}
|
||
});
|
||
fillImages($('#task').html(), images, res.task);
|
||
$('script').each(function() {
|
||
if ($(this).hasClass('remove') || $(this).attr('src') || $(this).attr('href')) {
|
||
return;
|
||
}
|
||
fillImages($(this).html(), images, res.task);
|
||
});
|
||
$('#solution img').each(function() {
|
||
image = $(this).attr('src').toString();
|
||
if ($.inArray(image, images) === -1) {
|
||
res.solution.push({ type: 'image', url: image });
|
||
images.push(image);
|
||
}
|
||
});
|
||
fillImages($('#solution').html(), images, res.solution);
|
||
$('.hint').each(function() {
|
||
var hintnum = $(this).attr('hint-num');
|
||
$('[hint-num='+hintnum+'] img').each(function() {
|
||
image = $(this).attr('src').toString();
|
||
if ($.inArray(image, images) === -1) {
|
||
res.hints[hintnum].push({ type: 'image', url: image });
|
||
images.push(image);
|
||
}
|
||
});
|
||
fillImages($(this).html(), images, res.hints[hintnum]);
|
||
});
|
||
|
||
// Links
|
||
$('iframe').each(function () {
|
||
var curUrl = $(this).attr('src');
|
||
if(curUrl.indexOf('://') == -1 && curUrl.charAt(0) != '/') {
|
||
res.files.push({ type: this.tagName, url: $(this).attr('src') });
|
||
}
|
||
});
|
||
|
||
// Other resources
|
||
$('source, track').each(function() {
|
||
res.files.push({ type: this.tagName, url: $(this).attr('src') });
|
||
});
|
||
$('fioi-video-player').each(function() {
|
||
var fileAttributes = ["data-source", "data-image", "data-subtitles"];
|
||
for(var i=0; i<fileAttributes.length; i++) {
|
||
var curAttr = $(this).attr(fileAttributes[i]);
|
||
curAttr = curAttr ? curAttr.split(';') : [];
|
||
for(var a=0; a<curAttr.length; a++) {
|
||
var curAttrFile = curAttr[a];
|
||
if(curAttrFile && curAttrFile != 'animation' && curAttrFile != 'none') {
|
||
res.files.push({ type: fileAttributes[i], url: curAttrFile });
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
taskResourcesLoaded = true;
|
||
|
||
if(window.taskGetResourcesPost) {
|
||
window.taskGetResourcesPost(res, callback);
|
||
} else {
|
||
callback(res);
|
||
}
|
||
};
|
||
}
|
||
|
||
function declareResource(type, resource) {
|
||
if (!res[type]) {
|
||
res[type] = [];
|
||
}
|
||
res[type].push(resource);
|
||
}
|
||
|
||
window.declareTaskResource = declareResource;
|
||
|
||
var resourcesObjectForRegistration = {};
|
||
|
||
$(document).ready(function() {
|
||
if (typeof json !== 'undefined') {
|
||
res = json;
|
||
}
|
||
|
||
if(window.preprocessingFunctions) {
|
||
for(var i=0; i<window.preprocessingFunctions.length; i++) {
|
||
window.preprocessingFunctions[i]();
|
||
}
|
||
}
|
||
window.preprocessingFunctions = [];
|
||
|
||
res.hints = [];
|
||
$('.hint').each(function(index) {
|
||
res.hints[res.hints.length] = [{type: 'html', content: $(this).html() }];
|
||
$(this).attr('hint-num', res.hints.length-1);
|
||
});
|
||
res.task = [{ type: 'html', content: $('#task').html() }];
|
||
res.solution = [{ type: 'html', content: $('#solution').html() }];
|
||
if (window.task) {
|
||
window.implementGetResources(window.task);
|
||
// alias for old code, TODO: remove
|
||
window.getTaskResources = task.getResources;
|
||
}
|
||
});
|
||
|
||
|
||
function fillImages(text, images, res) {
|
||
var extensions = ["png", "jpg", "gif", "ttf", "woff", "eot", "mp4", "zip"];
|
||
for (var iExt = 0; iExt < extensions.length; iExt++) {
|
||
var ext = extensions[iExt];
|
||
var regexp = new RegExp("[\'\"]([^;\"\']*." + ext + ")[\'\"]", "g");
|
||
while (true) {
|
||
var match = regexp.exec(text);
|
||
if (!match) {
|
||
break;
|
||
}
|
||
var image = match[1];
|
||
if (image.length <= ext.length + 1) {
|
||
continue;
|
||
}
|
||
if ($.inArray(image, images) === -1) {
|
||
res.push({ type: 'image', url: image });
|
||
images.push(image);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
})();
|
||
|
||
(function() {
|
||
'use strict';
|
||
|
||
/*
|
||
* Implementation of a small platform for standalone tasks, mostly for
|
||
* development, demo and testing purposes.
|
||
*
|
||
* Requirements:
|
||
* - jQuery
|
||
* - a Platform class creating a simple platform (present in the standard
|
||
* implementation of the integration API
|
||
* - task.getMetaData(), as documented in the PEM
|
||
*/
|
||
|
||
// demo platform key
|
||
var demo_key = 'buddy'
|
||
|
||
|
||
var languageStrings = {
|
||
ar: {
|
||
'task': 'Task',
|
||
'submission': 'Submission',
|
||
'solution': 'Solution',
|
||
'editor': 'Edit',
|
||
'hints': 'Hints',
|
||
'showSolution': '显示答案',
|
||
'yourScore': "Your score:",
|
||
'canReadSolution': "You can now read the solution at the bottom of this page.",
|
||
'gradeAnswer': 'Test grader'
|
||
},
|
||
fr: {
|
||
'task': 'Exercice',
|
||
'submission': 'Soumission',
|
||
'solution': 'Solution',
|
||
'editor': 'Résoudre',
|
||
'hints': 'Conseils',
|
||
'showSolution': 'Voir la solution',
|
||
'yourScore': "Votre score :",
|
||
'canReadSolution': "Vous pouvez maintenant lire la solution en bas de la page.",
|
||
'gradeAnswer': "Tester le grader"
|
||
},
|
||
en: {
|
||
'task': 'Task',
|
||
'submission': 'Submission',
|
||
'solution': 'Solution',
|
||
'editor': 'Edit',
|
||
'hints': 'Hints',
|
||
'showSolution': 'Show solution',
|
||
'yourScore': "Your score:",
|
||
'canReadSolution': "You can now read the solution at the bottom of this page.",
|
||
'gradeAnswer': 'Test grader'
|
||
},
|
||
fi: {
|
||
'task': 'Task',
|
||
'submission': 'Submission',
|
||
'solution': 'Solution',
|
||
'editor': 'Edit',
|
||
'hints': 'Hints',
|
||
'showSolution': 'Show solution',
|
||
'yourScore': "Your score:",
|
||
'canReadSolution': "You can now read the solution at the bottom of this page.",
|
||
'gradeAnswer': 'Test grader'
|
||
},
|
||
sv: {
|
||
'task': 'Task',
|
||
'submission': 'Submission',
|
||
'solution': 'Solution',
|
||
'editor': 'Edit',
|
||
'hints': 'Hints',
|
||
'showSolution': 'Show solution',
|
||
'yourScore': "Your score:",
|
||
'canReadSolution': "You can now read the solution at the bottom of this page.",
|
||
'gradeAnswer': 'Test grader'
|
||
},
|
||
de: {
|
||
'task': 'Aufgabe',
|
||
'submission': 'Abgabe',
|
||
'solution': 'Lösung',
|
||
'editor': 'Bearbeiten',
|
||
'hints': 'Hinweise',
|
||
'showSolution': 'Lösung anzeigen',
|
||
'yourScore': "Dein Punktestand:",
|
||
'canReadSolution': "Du kannst dir jetzt die Lösung unten auf der Seite anschauen.",
|
||
'gradeAnswer': 'Test grader'
|
||
},
|
||
es: {
|
||
'task': 'Problema',
|
||
'submission': 'Sumisión',
|
||
'solution': 'Solución',
|
||
'editor': 'Editar',
|
||
'hints': 'Pistas',
|
||
'showSolution': 'Mostrar solución',
|
||
'yourScore': 'Su puntuación:',
|
||
'canReadSolution': 'Puede leer la solución al final de esta página.',
|
||
'gradeAnswer': 'Test grader'
|
||
}
|
||
};
|
||
|
||
function getLanguageString(key) {
|
||
// Default to english strings
|
||
var ls = languageStrings[window.stringsLanguage] ? languageStrings[window.stringsLanguage] : languageStrings['en'];
|
||
var str = ls[key];
|
||
return str ? str : '';
|
||
}
|
||
|
||
/*
|
||
* Create custom elements for platformless implementation
|
||
*/
|
||
var miniPlatformWrapping = {
|
||
beaver: {
|
||
'header' : '\
|
||
<div id="miniPlatformHeader">\
|
||
<table>\
|
||
<td><img src="' + (window.modulesPath?window.modulesPath:'../../../_common/modules') + '/img/castor.png" width="60px" style="display:inline-block;margin-right:20px;vertical-align:middle"/></td>\
|
||
<td><span class="platform">高阶思维能力测试</span></td>\
|
||
<td><a href="http://concours.castor-informatique.fr/" style="display:inline-block;text-align:right;">Le concours Castor</a></td>\
|
||
</table>\
|
||
</div>'
|
||
},
|
||
laptop: {
|
||
'header' : '\
|
||
<div style="width:100%; border-bottom:1px solid #B47238;overflow:hidden">\
|
||
<table style="width:770px;margin: 10px auto;">\
|
||
<td><img src="' + (window.modulesPath?window.modulesPath:'../../../_common/modules') + '/img/laptop.png" width="60px" style="display:inline-block;margin-right:20px;vertical-align:middle"/></td>\
|
||
<td><span class="platform">Concours Alkindi</span></td>\
|
||
<td><a href="http://concours-alkindi.fr/home.html#/" style="display:inline-block;text-align:right;">Le concours Alkindi</a></td>\
|
||
</table>\
|
||
</div>'
|
||
},
|
||
none: {
|
||
'header' : '<span></span>'
|
||
}
|
||
};
|
||
|
||
function inIframe() {
|
||
try {
|
||
return window.self !== window.top;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
if(typeof window.jwt == 'undefined') {
|
||
window.jwt = {
|
||
isDummy: true,
|
||
sign: function() { return null; },
|
||
decode: function(token) { return token; }
|
||
};
|
||
}
|
||
|
||
function TaskToken(data, key) {
|
||
|
||
this.data = data
|
||
this.data.sHintsRequested = "[]";
|
||
this.key = key
|
||
|
||
var query = document.location.search.replace(/(^\?)/,'').split("&").map(function(n){return n = n.split("="),this[n[0]] = n[1],this}.bind({}))[0];
|
||
this.queryToken = query.sToken;
|
||
|
||
this.addHintRequest = function(hint_params, callback) {
|
||
try {
|
||
hint_params = jwt.decode(hint_params).askedHint;
|
||
} catch(e) {}
|
||
var hintsReq = JSON.parse(this.data.sHintsRequested);
|
||
var exists = hintsReq.find(function(h) {
|
||
return h == hint_params;
|
||
});
|
||
if(!exists) {
|
||
hintsReq.push(hint_params);
|
||
this.data.sHintsRequested = JSON.stringify(hintsReq);
|
||
}
|
||
return this.get(callback);
|
||
}
|
||
|
||
this.update = function(newData, callback) {
|
||
for(var key in newData) {
|
||
this.data[key] = newData[key];
|
||
}
|
||
}
|
||
|
||
this.getToken = function(data, callback) {
|
||
var res = jwt.sign(data, this.key)
|
||
if(callback) {
|
||
// imitate async req
|
||
setTimeout(function() {
|
||
callback(res)
|
||
}, 0);
|
||
}
|
||
return res;
|
||
}
|
||
|
||
this.get = function(callback) {
|
||
if(window.jwt.isDummy && this.queryToken) {
|
||
var token = this.queryToken;
|
||
if(callback) {
|
||
// imitate async req
|
||
setTimeout(function() {
|
||
callback(token)
|
||
}, 0);
|
||
}
|
||
return token;
|
||
}
|
||
return this.getToken(this.data, callback);
|
||
}
|
||
|
||
this.getAnswerToken = function(answer, callback) {
|
||
var answerData = {};
|
||
for(var key in this.data) {
|
||
answerData[key] = this.data[key];
|
||
}
|
||
answerData.sAnswer = answer;
|
||
return this.getToken(answerData, callback);
|
||
}
|
||
}
|
||
|
||
|
||
function AnswerToken(key) {
|
||
this.key = key
|
||
this.get = function(answer, callback) {
|
||
var res = jwt.sign(answer, this.key)
|
||
if(callback) {
|
||
// imitate async req
|
||
setTimeout(function() {
|
||
callback(res)
|
||
}, 0)
|
||
}
|
||
return res;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
var taskMetaData;
|
||
|
||
// important for tracker.js
|
||
var compiledTask = true;
|
||
|
||
window.miniPlatformShowSolution = function() {
|
||
$("#showSolutionButton").hide();
|
||
task.getAnswer(function(answer) {
|
||
task.showViews({"task": true, "solution": true}, function() {
|
||
// For tasks with no feedback / older tasks
|
||
// miniPlatformPreviewGrade(answer);
|
||
platform.trigger('showViews', [{"task": true, "solution": true}]);
|
||
});
|
||
});
|
||
}
|
||
|
||
function miniPlatformPreviewGrade(answer) {
|
||
var minScore = -3;
|
||
if (taskMetaData.fullFeedback) {
|
||
minScore = 0;
|
||
}
|
||
var maxScore = 40;
|
||
var score;
|
||
var showGrade = function(score) {
|
||
if ($("#previewScorePopup").length === 0) {
|
||
$("<div id='previewScorePopup'><div style=\"background-color:#111;opacity: 0.65;filter:alpha(opacity=65);position:absolute;z-index:10;top:0px;left:0px;width:100%;height:2000px\"></div>" +
|
||
"<div style='position:fixed;top:100px;left:100px;width:400px;height:200px;background-color:#E0E0FF;color:black;border: solid black 3px;text-align:center;z-index:1000'>" +
|
||
"<div style='padding:50px'><span id='previewScoreMessage'></span><br/><br/><input type='button' onclick='$(\"#previewScorePopup\").remove()' value='OK' /></div></div></div>").insertBefore("#solution");
|
||
}
|
||
$("#previewScorePopup").show();
|
||
$("#previewScoreMessage").html("<b>" + getLanguageString('showSolution') + " " + score + "/" + maxScore + "</b><br/>" + getLanguageString('showSolution'));
|
||
};
|
||
// acceptedAnswers is not documented, but necessary for old Bebras tasks
|
||
if (taskMetaData.acceptedAnswers && taskMetaData.acceptedAnswers[0]) {
|
||
if ($.inArray("" + answer, taskMetaData.acceptedAnswers) > -1) {
|
||
score = maxScore;
|
||
}
|
||
else {
|
||
score = minScore;
|
||
}
|
||
showGrade(score);
|
||
} else {
|
||
score = grader.gradeTask(answer, null, showGrade);
|
||
}
|
||
}
|
||
|
||
var alreadyStayed = false;
|
||
|
||
var miniPlatformValidate = function(task) { return function(mode, success, error) {
|
||
//$.post('updateTestToken.php', {action: 'showSolution'}, function(){}, 'json');
|
||
if (mode == 'nextImmediate' || mode == 'log') {
|
||
return;
|
||
}
|
||
if (mode == 'stay') {
|
||
if (alreadyStayed) {
|
||
platform.trigger('validate', [mode]);
|
||
if (success) {
|
||
success();
|
||
}
|
||
} else {
|
||
alreadyStayed = true;
|
||
}
|
||
}
|
||
if (mode == 'cancel') {
|
||
alreadyStayed = false;
|
||
}
|
||
if(platform.registered_objects && platform.registered_objects.length > 0) {
|
||
platform.trigger('validate', [mode]);
|
||
} else {
|
||
// Try to validate
|
||
task.getAnswer(function(answer) {
|
||
task.gradeAnswer(answer, task_token.getAnswerToken(answer), function(score, message) {
|
||
if(success) { success(); }
|
||
})
|
||
});
|
||
}
|
||
if (success) {
|
||
success();
|
||
}
|
||
}};
|
||
|
||
function getUrlParameter(sParam)
|
||
{
|
||
var sPageURL = window.location.search.substring(1);
|
||
var sURLVariables = sPageURL.split('&');
|
||
for (var i = 0; i < sURLVariables.length; i++)
|
||
{
|
||
var sParameterName = sURLVariables[i].split('=');
|
||
if (sParameterName[0] == sParam)
|
||
{
|
||
return decodeURIComponent(sParameterName[1]);
|
||
}
|
||
}
|
||
}
|
||
|
||
function getHashParameter(sParam)
|
||
{
|
||
var sPageURL = window.location.hash.substring(1);
|
||
var sURLVariables = sPageURL.split('&');
|
||
for (var i = 0; i < sURLVariables.length; i++)
|
||
{
|
||
var sParameterName = sURLVariables[i].split('=');
|
||
if (sParameterName[0] == sParam)
|
||
{
|
||
return decodeURIComponent(sParameterName[1]);
|
||
}
|
||
}
|
||
}
|
||
|
||
var chooseView = (function () {
|
||
// Manages the buttons to choose the view
|
||
return {
|
||
doubleEnabled: false,
|
||
isDouble: false,
|
||
lastShownViews: {},
|
||
|
||
init: function(views) {
|
||
if (! $("#choose-view").length)
|
||
$(document.body).append('<div id="choose-view" style="margin-top:6em"></div>');
|
||
$("#choose-view").html("");
|
||
// Display buttons to select task view or solution view
|
||
/*
|
||
for(var viewName in views) {
|
||
if (!views[viewName].requires) {
|
||
var btn = $('<button id="choose-view-'+viewName+'" class="btn btn-default choose-view-button">' + getLanguageString(viewName) + '</button>')
|
||
$("#choose-view").append(btn);
|
||
btn.click(this.selectFactory(viewName));
|
||
}
|
||
}
|
||
*/
|
||
$("#grade").remove();
|
||
var btnGradeAnswer = $('<center id="grade"><button class="btn btn-default">' + getLanguageString('gradeAnswer') + '</button></center>');
|
||
// display grader button only if dev mode by adding URL hash 'dev'
|
||
if (getHashParameter('dev')) {
|
||
$(document.body).append(btnGradeAnswer);
|
||
}
|
||
btnGradeAnswer.click(function() {
|
||
task.getAnswer(function(answer) {
|
||
answer_token.get(answer, function(answer_token) {
|
||
task.gradeAnswer(answer, answer_token, function(score, message, scoreToken) {
|
||
alert("Score : " + score + ", message : " + message);
|
||
});
|
||
})
|
||
}, function() {
|
||
alert("error");
|
||
});
|
||
})
|
||
},
|
||
|
||
reinit: function(views) {
|
||
this.init(views);
|
||
var newShownViews = {};
|
||
for(var viewName in this.lastShownViews) {
|
||
if(!this.lastShownViews[viewName]) { continue; }
|
||
if(views[viewName] && !views[viewName].requires) {
|
||
newShownViews[viewName] = true;
|
||
}
|
||
}
|
||
for(var viewName in views) {
|
||
if(views[viewName].includes) {
|
||
for(var i=0; i<views[viewName].includes.length; i++) {
|
||
if(this.lastShownViews[views[viewName].includes[i]]) {
|
||
newShownViews[viewName] = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
this.update(newShownViews);
|
||
},
|
||
|
||
selectFactory: function(viewName) {
|
||
var that = this;
|
||
return function () {
|
||
that.select(viewName);
|
||
};
|
||
},
|
||
|
||
select: function(viewName) {
|
||
var that = this;
|
||
var shownViews = {};
|
||
shownViews[viewName] = true;
|
||
task.showViews(shownViews, function () {
|
||
that.update(shownViews);
|
||
});
|
||
},
|
||
|
||
update: function(shownViews) {
|
||
this.lastShownViews = shownViews;
|
||
$('.choose-view-button').removeClass('btn-info');
|
||
for(var viewName in shownViews) {
|
||
if(shownViews[viewName]) {
|
||
$('#choose-view-'+viewName).addClass('btn-info');
|
||
}
|
||
};
|
||
}
|
||
};
|
||
})();
|
||
|
||
window.task_token = new TaskToken({
|
||
itemUrl: window.location.href,
|
||
randomSeed: Math.floor(Math.random() * 10)
|
||
}, demo_key);
|
||
|
||
|
||
|
||
$(document).ready(function() {
|
||
var hasPlatform = false;
|
||
try {
|
||
hasPlatform = (inIframe() && (typeof parent.TaskProxyManager !== 'undefined') && (typeof parent.generating == 'undefined' || parent.generating === true));
|
||
var testEdge = parent.TaskProxyManager; // generates an exception on edge when in a platform (parent not available)
|
||
} catch(ex) {
|
||
// iframe from files:// url are considered cross-domain by Chrome
|
||
if(location.protocol !== 'file:') {
|
||
hasPlatform = true;
|
||
}
|
||
}
|
||
if (!hasPlatform) {
|
||
$('head').append('<link rel="stylesheet"type="text/css" href="' + (window.modulesPath?window.modulesPath:'../../../_common/modules') + '/integrationAPI.01/official/miniPlatform.css">');
|
||
var platformLoad = function(task) {
|
||
window.task_token.update({id: taskMetaData.id});
|
||
window.answer_token = new AnswerToken(demo_key)
|
||
|
||
platform.validate = miniPlatformValidate(task);
|
||
platform.updateHeight = function(height,success,error) {if (success) {success();}};
|
||
platform.updateDisplay = function(data,success,error) {
|
||
if(data.views) {
|
||
chooseView.reinit(data.views);
|
||
}
|
||
if (success) {success();}
|
||
};
|
||
var taskOptions = {};
|
||
try {
|
||
var strOptions = getUrlParameter("options");
|
||
if (strOptions !== undefined) {
|
||
taskOptions = $.parseJSON(strOptions);
|
||
}
|
||
} catch(exception) {
|
||
alert("Error: invalid options");
|
||
}
|
||
var minScore = -3;
|
||
if (taskMetaData.fullFeedback) {
|
||
minScore = 0;
|
||
}
|
||
platform.getTaskParams = function(key, defaultValue, success, error) {
|
||
var res = {'minScore': minScore, 'maxScore': 40, 'noScore': 0, 'readOnly': false, 'randomSeed': "0", 'options': taskOptions};
|
||
if (key) {
|
||
if (key !== 'options' && key in res) {
|
||
res = res[key];
|
||
} else if (res.options && key in res.options) {
|
||
res = res.options[key];
|
||
} else {
|
||
res = (typeof defaultValue !== 'undefined') ? defaultValue : null;
|
||
}
|
||
}
|
||
if (success) {
|
||
success(res);
|
||
} else {
|
||
return res;
|
||
}
|
||
};
|
||
platform.askHint = function(hint_params, success, error) {
|
||
/*
|
||
$.post('updateTestToken.php', JSON.stringify({action: 'askHint'}), function(postRes){
|
||
if (success) {success();}
|
||
}, 'json');
|
||
*/
|
||
task_token.addHintRequest(hint_params, function(token) {
|
||
task.updateToken(token, function() {})
|
||
success(token)
|
||
})
|
||
};
|
||
|
||
|
||
var loadedViews = {'task': true, 'solution': true, 'hints': true, 'editor': true, 'grader': true, 'metadata': true, 'submission': true};
|
||
var shownViews = {'task': true};
|
||
// TODO: modifs ARTHUR à relire
|
||
if (taskOptions.showSolutionOnLoad) {
|
||
shownViews.solution = true;
|
||
}
|
||
if (!taskOptions.hideTitle) {
|
||
$("#task h1").show();
|
||
}
|
||
|
||
if (taskMetaData.fullFeedback) {
|
||
loadedViews.grader = true;
|
||
}
|
||
|
||
task.load(
|
||
loadedViews,
|
||
function() {
|
||
platform.trigger('load', [loadedViews]);
|
||
task.getViews(function(views) {
|
||
chooseView.init(views);
|
||
});
|
||
task.showViews(shownViews, function() {
|
||
chooseView.update(shownViews);
|
||
platform.trigger('showViews', [{"task": true}]);
|
||
});
|
||
if ($("#solution").length) {
|
||
$("#task").append("<center id='showSolutionButton'><button type='button' class='btn btn-default' onclick='miniPlatformShowSolution()'>" + getLanguageString('showSolution') + "</button></center>");
|
||
}
|
||
|
||
// add branded header to platformless task depending on avatarType
|
||
// defaults to beaver platform branding
|
||
if(window.displayHelper) {
|
||
if (miniPlatformWrapping[displayHelper.avatarType].header) {
|
||
$('body').prepend(miniPlatformWrapping[displayHelper.avatarType].header);
|
||
} else {
|
||
$('body').prepend(miniPlatformWrapping[beaver].header);
|
||
}
|
||
}
|
||
},
|
||
function(error) {
|
||
console.error(error)
|
||
}
|
||
);
|
||
|
||
|
||
task_token.get(function(token) {
|
||
task.updateToken(token, function() {})
|
||
})
|
||
|
||
|
||
/* For the 'resize' event listener below, we use a cross-browser
|
||
* compatible version for "addEventListener" (modern) and "attachEvent" (old).
|
||
* Source: https://stackoverflow.com/questions/6927637/addeventlistener-in-internet-explorer
|
||
*/
|
||
function addEvent(evnt, elem, func) {
|
||
if (elem.addEventListener) // W3C DOM
|
||
elem.addEventListener(evnt,func,false);
|
||
else if (elem.attachEvent) { // IE DOM
|
||
elem.attachEvent("on"+evnt, func);
|
||
}
|
||
else { // No much to do
|
||
elem[evnt] = func;
|
||
}
|
||
}
|
||
|
||
addEvent('resize', window, function() {
|
||
task.getViews(function(views) {
|
||
chooseView.reinit(views);
|
||
});
|
||
});
|
||
};
|
||
var getMetaDataAndLoad = function(task) {
|
||
task.getMetaData(function(metaData) {
|
||
taskMetaData = metaData;
|
||
platformLoad(task);
|
||
});
|
||
};
|
||
if (window.platform.task || platform.initFailed) {
|
||
// case everything went fine with task loading, or task loading failed
|
||
// (due to missing jschannel and file:// protocol...
|
||
getMetaDataAndLoad(window.task ? window.task : window.platform.task);
|
||
} else {
|
||
// task is not loaded yet
|
||
var oldInit = platform.initWithTask;
|
||
platform.initWithTask = function(task) {
|
||
oldInit(task);
|
||
getMetaDataAndLoad(task);
|
||
};
|
||
}
|
||
}
|
||
});
|
||
|
||
})();
|