* coefficient: number, default 1
* questions: array of
* index: for paper test, like 2.1.a (?!); and quiz: 0, 1, 2, 3...
- * wording: varchar (HTML)
+ * wording: varchar (HTML) with potential placeholders for params
* options: array of varchar --> if present, question type == quiz!
* fixed: bool, options in fixed order (default: false)
- * answer: array of integers (for quiz) or html text (for paper); striped in exam mode
- * active: boolean, is question in current evaluation?
* points: points for this question (default 1)
- * param: parameter (if applicable)
+ * answers:
+ * array of index +
+ * array of integers (for quiz) or
+ * html text (for paper) or
+ * function (as string, for parameterized questions)
* papers : array of
* number: student number
* inputs: array of {index,answer[array of integers or html text],startTime}
introduction: "",
coefficient: 1,
questions: [ ],
+ answers: [ ],
papers: [ ],
},
callback
"papers.password": password,
},
{ $set: {
- "papers.$.endTime": Date.now(),
"papers.$.password": "",
} },
callback
{ $push: { papers: {
number: number,
startTime: Date.now(),
- endTime: undefined,
password: password,
totalDisco: 0,
discoCount: 0,
// 'inputs': object with key = question index and value = text or boolean array
// display: 'all', 'one', 'solution'
// iidx: current level-0 integer index (can match a group of questions / inputs)
- props: ['questions','inputs','display','iidx'],
+ props: ['questions','inputs','answers','display','iidx'],
data: function() {
return {
displayStyle: "compact", //or "all": all on same page
+ parameters: 0, //TODO: DO NOT re-draw parameters for already answered questions
};
}
// Full questions tree is rendered, but some parts hidden depending on display settings
}
)
);
+ const aIdx = (this.answers || [ ]).findIndex( item => { return item.index == q.index; });
optionList.push(
h(
"div",
{
"class": {
option: true,
- choiceCorrect: this.display == "solution" && q.answer.includes(idx),
- choiceWrong: this.display == "solution" && !!this.inputs && this.inputs[q.index][idx] && !q.answer.includes(idx),
+ choiceCorrect: this.display == "solution" && this.answers[aIdx].includes(idx),
+ choiceWrong: this.display == "solution" && !!this.inputs && this.inputs[q.index][idx] && !this.answers[aIdx].includes(idx),
},
},
option
)
);
}
+ else
+ {
+ // Open question, or parameterized: TODO
+ }
const depth = (q.index.match(/\./g) || []).length;
return h(
"div",
/*Draft format (compiled to json)
+ * TODO: separate questions and answers in Evaluation object
<some html question (or/+ exercise intro)>
+ choix 3
- choix4
- <another sub sub>
+ <another sub sub> with params interpolation £ (tout simplement)
+ / params: javascript parameter generator (another function, body only)
* answer 2 (which can
be on
several lines)
<Some second question>
* With answer
-*/
+
+ dans le cas de parametetrized, answer est une fonction javascript !! qui prend en arg le(s) param(s)
+ coté serveur on stock parameterized question + body func
+ une fois côté client, extra work first to 1) execute each func 2) replace (and store!!!) all params
+https://stackoverflow.com/questions/7650071/is-there-a-way-to-create-a-function-from-a-string-with-javascript
+
+ */
new Vue({
el: '#course',
data: {
- display: "evaluations", //or "students", or "grades" (admin mode)
+ display: "evaluations", //or "students" (in admin mode)
course: course,
monitorPwd: "",
newEvaluation: { name: "" },
"wording": "string",
"options": "stringArray", //only for quiz
"fixed": "boolean",
- "answer": "string", //both this and next are mutually exclusive
- "choice": "integerArray",
- "active": "boolean",
"points": "number",
};
+Validator.Answer = {
+ "index": "section",
+ "value": "stringOrIntegerArray",
+};
+
Validator.Input = {
"index": "section",
"input": "stringOrIntegerArray",
// One student response to an exam
Validator.Paper = {
"number": "code",
- // (array of) strings for open questions, arrays of integers for quizzes:
"inputs": Validator.Input,
"startTime": "positiveInteger",
- "endTime": "positiveInteger",
+ "current": "positiveInteger",
"discoTime": "positiveInteger",
"discoCount": "positiveInteger",
"totalDisco": "positiveInteger",
"introduction": "string",
"coefficient": "number",
"questions": Validator.Question,
+ "answers": Validator.Answer,
"papers": Validator.Paper,
};
"_id": "bson",
"email": "email",
"name": "name",
- "initials": "unchecked", //not a user input
- "loginToken": "unchecked",
- "sessionTokens": "unchecked",
- "token": "alphanumeric", //exception: for the purpose of user registration
+ "initials": "alphanumeric",
+ "loginToken": "alphanumeric",
+ "sessionTokens": "alphanumericArray",
};
Validator.Student = {
return "";
},
- "check_stringArray": function(arg)
- {
- return !_.isArray(arg) ? "not an array" : "";
- },
-
"check_alphanumeric": function(arg)
{
return arg.match(/^[\w]{1,32}$/) === null ? "[1,32] alphanumerics" : "";
if (!_.isString(arg))
return "not a string";
if (!/^[\x21-\x7E]{1,16}$/.test(arg))
- return "[1,16] ASCII characters with code in [33,126]";
+ return "{1,16} ASCII characters with code in [33,126]";
return "";
},
return "";
},
+ "check_stringArray": function(arg)
+ {
+ if (!_.isArray(arg))
+ return "not an array";
+ for (let i=0; i<arg.length; i++)
+ {
+ if (!_.isString(arg[i]));
+ return "not a string";
+ }
+ return "";
+ },
+
+ "check_alphanumericArray": function(arg)
+ {
+ if (!_.isArray(arg))
+ return "not an array";
+ for (let i=0; i<arg.length; i++)
+ {
+ let error = Validator["check_alphanumeric"](arg[i]);
+ if (error.length > 0)
+ return error;
+ }
+ return "";
+ },
+
"check_stringOrIntegerArray": function(arg)
{
if (!_.isString(arg))
},
});
-try { module.exports = Validator.checkObject; } catch (err) {} //for server
+try { module.exports = Validator.checkObject; } catch (err) { } //for server