mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 16:36:37 +02:00
MDL-16094 File storage conversion Quiz and Questions
This commit is contained in:
parent
ba206b3a2f
commit
fe6ce23489
80 changed files with 4386 additions and 2214 deletions
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<XMLDB PATH="lib/db" VERSION="20100803" COMMENT="XMLDB file for core Moodle tables"
|
<XMLDB PATH="lib/db" VERSION="20100806" COMMENT="XMLDB file for core Moodle tables"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||||
>
|
>
|
||||||
|
@ -1246,8 +1246,9 @@
|
||||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="name"/>
|
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="name"/>
|
||||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="contextid"/>
|
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="contextid"/>
|
||||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="context that this category is shared in" PREVIOUS="name" NEXT="info"/>
|
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="context that this category is shared in" PREVIOUS="name" NEXT="info"/>
|
||||||
<FIELD NAME="info" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="stamp"/>
|
<FIELD NAME="info" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="infoformat"/>
|
||||||
<FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="info" NEXT="parent"/>
|
<FIELD NAME="infoformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="info" NEXT="stamp"/>
|
||||||
|
<FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="infoformat" NEXT="parent"/>
|
||||||
<FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="stamp" NEXT="sortorder"/>
|
<FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="stamp" NEXT="sortorder"/>
|
||||||
<FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="999" SEQUENCE="false" PREVIOUS="parent"/>
|
<FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="999" SEQUENCE="false" PREVIOUS="parent"/>
|
||||||
</FIELDS>
|
</FIELDS>
|
||||||
|
@ -1266,10 +1267,10 @@
|
||||||
<FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="category" NEXT="name"/>
|
<FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="category" NEXT="name"/>
|
||||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="parent" NEXT="questiontext"/>
|
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="parent" NEXT="questiontext"/>
|
||||||
<FIELD NAME="questiontext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="questiontextformat"/>
|
<FIELD NAME="questiontext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="questiontextformat"/>
|
||||||
<FIELD NAME="questiontextformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="questiontext" NEXT="image"/>
|
<FIELD NAME="questiontextformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="questiontext" NEXT="generalfeedback"/>
|
||||||
<FIELD NAME="image" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="questiontextformat" NEXT="generalfeedback"/>
|
<FIELD NAME="generalfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="to store the question feedback" PREVIOUS="questiontextformat" NEXT="generalfeedbackformat"/>
|
||||||
<FIELD NAME="generalfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="to store the question feedback" PREVIOUS="image" NEXT="defaultgrade"/>
|
<FIELD NAME="generalfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="generalfeedback" NEXT="defaultgrade"/>
|
||||||
<FIELD NAME="defaultgrade" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" DECIMALS="7" PREVIOUS="generalfeedback" NEXT="penalty"/>
|
<FIELD NAME="defaultgrade" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" DECIMALS="7" PREVIOUS="generalfeedbackformat" NEXT="penalty"/>
|
||||||
<FIELD NAME="penalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0.1" SEQUENCE="false" DECIMALS="7" PREVIOUS="defaultgrade" NEXT="qtype"/>
|
<FIELD NAME="penalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0.1" SEQUENCE="false" DECIMALS="7" PREVIOUS="defaultgrade" NEXT="qtype"/>
|
||||||
<FIELD NAME="qtype" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="penalty" NEXT="length"/>
|
<FIELD NAME="qtype" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="penalty" NEXT="length"/>
|
||||||
<FIELD NAME="length" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="qtype" NEXT="stamp"/>
|
<FIELD NAME="length" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="qtype" NEXT="stamp"/>
|
||||||
|
@ -1293,9 +1294,11 @@
|
||||||
<FIELDS>
|
<FIELDS>
|
||||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="question"/>
|
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="question"/>
|
||||||
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="answer"/>
|
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="answer"/>
|
||||||
<FIELD NAME="answer" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="fraction"/>
|
<FIELD NAME="answer" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="answerformat"/>
|
||||||
<FIELD NAME="fraction" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="answer" NEXT="feedback"/>
|
<FIELD NAME="answerformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="answer" NEXT="fraction"/>
|
||||||
<FIELD NAME="feedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="fraction"/>
|
<FIELD NAME="fraction" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="answerformat" NEXT="feedback"/>
|
||||||
|
<FIELD NAME="feedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="fraction" NEXT="feedbackformat"/>
|
||||||
|
<FIELD NAME="feedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="feedback"/>
|
||||||
</FIELDS>
|
</FIELDS>
|
||||||
<KEYS>
|
<KEYS>
|
||||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
||||||
|
@ -1338,8 +1341,9 @@
|
||||||
<FIELD NAME="newest" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="questionid" NEXT="newgraded"/>
|
<FIELD NAME="newest" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="questionid" NEXT="newgraded"/>
|
||||||
<FIELD NAME="newgraded" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="newest" NEXT="sumpenalty"/>
|
<FIELD NAME="newgraded" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="newest" NEXT="sumpenalty"/>
|
||||||
<FIELD NAME="sumpenalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="newgraded" NEXT="manualcomment"/>
|
<FIELD NAME="sumpenalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="newgraded" NEXT="manualcomment"/>
|
||||||
<FIELD NAME="manualcomment" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="sumpenalty" NEXT="flagged"/>
|
<FIELD NAME="manualcomment" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="sumpenalty" NEXT="manualcommentformat"/>
|
||||||
<FIELD NAME="flagged" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="The person attempting the question may mark certain questions within their question_attempt if the module that owns the attempt allow it. This field stores the status of that flag." PREVIOUS="manualcomment"/>
|
<FIELD NAME="manualcommentformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="manualcomment" NEXT="flagged"/>
|
||||||
|
<FIELD NAME="flagged" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="The person attempting the question may mark certain questions within their question_attempt if the module that owns the attempt allow it. This field stores the status of that flag." PREVIOUS="manualcommentformat"/>
|
||||||
</FIELDS>
|
</FIELDS>
|
||||||
<KEYS>
|
<KEYS>
|
||||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="attemptid"/>
|
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="attemptid"/>
|
||||||
|
@ -1575,7 +1579,7 @@
|
||||||
<KEY NAME="handlerid" TYPE="foreign" FIELDS="handlerid" REFTABLE="events_handlers" REFFIELDS="id" PREVIOUS="queuedeventid"/>
|
<KEY NAME="handlerid" TYPE="foreign" FIELDS="handlerid" REFTABLE="events_handlers" REFFIELDS="id" PREVIOUS="queuedeventid"/>
|
||||||
</KEYS>
|
</KEYS>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
<TABLE NAME="grade_outcomes" COMMENT="This table describes the outcomes used in the system. An outcome is a statement tied to a rubric scale from low to high, such as “Not met, Borderline, Met” (stored as 0,1 or 2)" PREVIOUS="events_queue_handlers" NEXT="grade_outcomes_courses">
|
<TABLE NAME="grade_outcomes" COMMENT="This table describes the outcomes used in the system. An outcome is a statement tied to a rubric scale from low to high, such as âNot met, Borderline, Metâ (stored as 0,1 or 2)" PREVIOUS="events_queue_handlers" NEXT="grade_outcomes_courses">
|
||||||
<FIELDS>
|
<FIELDS>
|
||||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" COMMENT="id of the table" NEXT="courseid"/>
|
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" COMMENT="id of the table" NEXT="courseid"/>
|
||||||
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" COMMENT="Mostly these are defined site wide ie NULL" PREVIOUS="id" NEXT="shortname"/>
|
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" COMMENT="Mostly these are defined site wide ie NULL" PREVIOUS="id" NEXT="shortname"/>
|
||||||
|
@ -2709,4 +2713,4 @@
|
||||||
</KEYS>
|
</KEYS>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
</TABLES>
|
</TABLES>
|
||||||
</XMLDB>
|
</XMLDB>
|
||||||
|
|
|
@ -4911,7 +4911,170 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
|
||||||
upgrade_main_savepoint(true, 2010080305);
|
upgrade_main_savepoint(true, 2010080305);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($oldversion < 2010080900) {
|
||||||
|
|
||||||
|
/// Define field generalfeedbackformat to be added to question
|
||||||
|
$table = new xmldb_table('question');
|
||||||
|
$field = new xmldb_field('generalfeedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'generalfeedback');
|
||||||
|
|
||||||
|
/// Conditionally launch add field generalfeedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define field infoformat to be added to question_categories
|
||||||
|
$table = new xmldb_table('question_categories');
|
||||||
|
$field = new xmldb_field('infoformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'info');
|
||||||
|
|
||||||
|
/// Conditionally launch add field infoformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define field answerformat to be added to question_answers
|
||||||
|
$table = new xmldb_table('question_answers');
|
||||||
|
$field = new xmldb_field('answerformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'answer');
|
||||||
|
|
||||||
|
/// Conditionally launch add field answerformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define field feedbackformat to be added to question_answers
|
||||||
|
$field = new xmldb_field('feedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'feedback');
|
||||||
|
|
||||||
|
/// Conditionally launch add field feedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define field manualcommentformat to be added to question_sessions
|
||||||
|
$table = new xmldb_table('question_sessions');
|
||||||
|
$field = new xmldb_field('manualcommentformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'manualcomment');
|
||||||
|
|
||||||
|
/// Conditionally launch add field manualcommentformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Main savepoint reached
|
||||||
|
upgrade_main_savepoint(true, 2010080900);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// updating question image
|
||||||
|
if ($oldversion < 2010080901) {
|
||||||
|
$fs = get_file_storage();
|
||||||
|
$rs = $DB->get_recordset('question');
|
||||||
|
$textlib = textlib_get_instance();
|
||||||
|
foreach ($rs as $question) {
|
||||||
|
if (empty($question->image)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!$category = $DB->get_record('question_categories', array('id'=>$question->category))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$categorycontext = get_context_instance_by_id($category->contextid);
|
||||||
|
// question files are stored in course level
|
||||||
|
// so we have to find course context
|
||||||
|
switch ($categorycontext->contextlevel){
|
||||||
|
case CONTEXT_COURSE :
|
||||||
|
$context = $categorycontext;
|
||||||
|
break;
|
||||||
|
case CONTEXT_MODULE :
|
||||||
|
$courseid = $DB->get_field('course_modules', 'course', array('id'=>$categorycontext->instanceid));
|
||||||
|
$context = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||||
|
break;
|
||||||
|
case CONTEXT_COURSECAT :
|
||||||
|
case CONTEXT_SYSTEM :
|
||||||
|
$context = get_system_context();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($textlib->substr($textlib->strtolower($question->image), 0, 7) == 'http://') {
|
||||||
|
// it is a link, appending to existing question text
|
||||||
|
$question->questiontext .= ' <img src="' . $question->image . '" />';
|
||||||
|
// update question record
|
||||||
|
$DB->update_record('question', $question);
|
||||||
|
} else {
|
||||||
|
$filename = basename($question->image);
|
||||||
|
$filepath = dirname($question->image);
|
||||||
|
if (empty($filepath) or $filepath == '.' or $filepath == '/') {
|
||||||
|
$filepath = '/';
|
||||||
|
} else {
|
||||||
|
// append /
|
||||||
|
$filepath = '/'.trim($filepath, './@#$ ').'/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// course files already moved to file pool by previous upgrade block
|
||||||
|
// so we just create copy from course_legacy area
|
||||||
|
if ($image = $fs->get_file($context->id, 'course', 'legacy', 0, $filepath, $filename)) {
|
||||||
|
// move files to file pool
|
||||||
|
$file_record = array(
|
||||||
|
'contextid'=>$category->contextid,
|
||||||
|
'component'=>'question',
|
||||||
|
'filearea'=>'questiontext',
|
||||||
|
'itemid'=>$question->id
|
||||||
|
);
|
||||||
|
$fs->create_file_from_storedfile($file_record, $image);
|
||||||
|
$question->questiontext .= ' <img src="@@PLUGINFILE@@' . $filepath . $filename . '" />';
|
||||||
|
// update question record
|
||||||
|
$DB->update_record('question', $question);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rs->close();
|
||||||
|
|
||||||
|
// Define field image to be dropped from question
|
||||||
|
$table = new xmldb_table('question');
|
||||||
|
$field = new xmldb_field('image');
|
||||||
|
|
||||||
|
// Conditionally launch drop field image
|
||||||
|
if ($dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->drop_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix fieldformat
|
||||||
|
$sql = 'SELECT a.*, q.qtype FROM {question_answers} a, {question} q WHERE a.question = q.id';
|
||||||
|
$rs = $DB->get_recordset_sql($sql);
|
||||||
|
foreach ($rs as $record) {
|
||||||
|
// generalfeedback should use questiontext format
|
||||||
|
if ($CFG->texteditors !== 'textarea') {
|
||||||
|
if (!empty($record->feedback)) {
|
||||||
|
$record->feedback = text_to_html($record->feedback);
|
||||||
|
}
|
||||||
|
$record->feedbackformat = FORMAT_HTML;
|
||||||
|
} else {
|
||||||
|
$record->feedbackformat = FORMAT_MOODLE;
|
||||||
|
$record->answerformat = FORMAT_MOODLE;
|
||||||
|
}
|
||||||
|
unset($record->qtype);
|
||||||
|
$DB->update_record('question_answers', $record);
|
||||||
|
}
|
||||||
|
$rs->close();
|
||||||
|
|
||||||
|
$rs = $DB->get_recordset('question');
|
||||||
|
foreach ($rs as $record) {
|
||||||
|
if ($CFG->texteditors !== 'textarea') {
|
||||||
|
if (!empty($record->questiontext)) {
|
||||||
|
$record->questiontext = text_to_html($record->questiontext);
|
||||||
|
}
|
||||||
|
$record->questiontextformat = FORMAT_HTML;
|
||||||
|
// conver generalfeedback text to html
|
||||||
|
if (!empty($record->generalfeedback)) {
|
||||||
|
$record->generalfeedback = text_to_html($record->generalfeedback);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$record->questiontextformat = FORMAT_MOODLE;
|
||||||
|
}
|
||||||
|
// generalfeedbackformat should be the save as questiontext format
|
||||||
|
$record->generalfeedbackformat = $record->questiontextformat;
|
||||||
|
$DB->update_record('question', $record);
|
||||||
|
}
|
||||||
|
$rs->close();
|
||||||
|
// Main savepoint reached
|
||||||
|
upgrade_main_savepoint(true, 2010080901);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -851,18 +851,31 @@ function question_delete_activity($cm, $feedback=true) {
|
||||||
*
|
*
|
||||||
* @global object
|
* @global object
|
||||||
* @param string $questionids a comma-separated list of question ids.
|
* @param string $questionids a comma-separated list of question ids.
|
||||||
* @param integer $newcategory the id of the category to move to.
|
* @param integer $newcategoryid the id of the category to move to.
|
||||||
*/
|
*/
|
||||||
function question_move_questions_to_category($questionids, $newcategory) {
|
function question_move_questions_to_category($questionids, $newcategoryid) {
|
||||||
global $DB;
|
global $DB, $QTYPES;
|
||||||
|
|
||||||
$result = true;
|
$result = true;
|
||||||
|
$ids = explode(',', $questionids);
|
||||||
|
foreach ($ids as $questionid) {
|
||||||
|
$questionid = (int)$questionid;
|
||||||
|
$params = array();
|
||||||
|
$params[] = $questionid;
|
||||||
|
$sql = 'SELECT q.*, c.id AS contextid, c.contextlevel, c.instanceid, c.path, c.depth
|
||||||
|
FROM {question} q, {question_categories} qc, {context} c
|
||||||
|
WHERE q.category=qc.id AND q.id=? AND qc.contextid=c.id';
|
||||||
|
$question = $DB->get_record_sql($sql, $params);
|
||||||
|
$category = $DB->get_record('question_categories', array('id'=>$newcategoryid));
|
||||||
|
// process files
|
||||||
|
$QTYPES[$question->qtype]->move_files($question, $category);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Move the questions themselves.
|
// Move the questions themselves.
|
||||||
$result = $result && $DB->set_field_select('question', 'category', $newcategory, "id IN ($questionids)");
|
$result = $result && $DB->set_field_select('question', 'category', $newcategoryid, "id IN ($questionids)");
|
||||||
|
|
||||||
// Move any subquestions belonging to them.
|
// Move any subquestions belonging to them.
|
||||||
$result = $result && $DB->set_field_select('question', 'category', $newcategory, "parent IN ($questionids)");
|
$result = $result && $DB->set_field_select('question', 'category', $newcategoryid, "parent IN ($questionids)");
|
||||||
|
|
||||||
// TODO Deal with datasets.
|
// TODO Deal with datasets.
|
||||||
|
|
||||||
|
@ -1080,6 +1093,7 @@ function question_load_states(&$questions, &$states, $cmoptions, $attempt, $last
|
||||||
$states[$qid]->last_graded = clone($states[$qid]);
|
$states[$qid]->last_graded = clone($states[$qid]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if ($lastattemptid) {
|
if ($lastattemptid) {
|
||||||
// If the new attempt is to be based on this previous attempt.
|
// If the new attempt is to be based on this previous attempt.
|
||||||
// Find the responses from the previous attempt and save them to the new session
|
// Find the responses from the previous attempt and save them to the new session
|
||||||
|
@ -2091,7 +2105,7 @@ function question_init_qengine_js() {
|
||||||
$module = array(
|
$module = array(
|
||||||
'name' => 'core_question_flags',
|
'name' => 'core_question_flags',
|
||||||
'fullpath' => '/question/flags.js',
|
'fullpath' => '/question/flags.js',
|
||||||
'requires' => array('base', 'dom', 'event-delegate', 'io-base'),
|
'requires' => array('base', 'dom', 'event-delegate', 'io-base'),
|
||||||
);
|
);
|
||||||
$actionurl = $CFG->wwwroot . '/question/toggleflag.php';
|
$actionurl = $CFG->wwwroot . '/question/toggleflag.php';
|
||||||
$flagattributes = array(
|
$flagattributes = array(
|
||||||
|
@ -2162,9 +2176,9 @@ function question_get_editing_head_contributions($question) {
|
||||||
* @param object $cmoptions The options specified by the course module
|
* @param object $cmoptions The options specified by the course module
|
||||||
* @param object $options An object specifying the rendering options.
|
* @param object $options An object specifying the rendering options.
|
||||||
*/
|
*/
|
||||||
function print_question(&$question, &$state, $number, $cmoptions, $options=null) {
|
function print_question(&$question, &$state, $number, $cmoptions, $options=null, $context=null) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
$QTYPES[$question->qtype]->print_question($question, $state, $number, $cmoptions, $options);
|
$QTYPES[$question->qtype]->print_question($question, $state, $number, $cmoptions, $options, $context);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Saves question options
|
* Saves question options
|
||||||
|
@ -3191,4 +3205,124 @@ class question_edit_contexts {
|
||||||
print_error('nopermissions', '', '', 'access question edit tab '.$tabname);
|
print_error('nopermissions', '', '', 'access question edit tab '.$tabname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewrite question url, file_rewrite_pluginfile_urls always build url by
|
||||||
|
* $file/$contextid/$component/$filearea/$itemid/$pathname_in_text, so we cannot add
|
||||||
|
* extra questionid and attempted in url by it, so we create quiz_rewrite_question_urls
|
||||||
|
* to build url here
|
||||||
|
*
|
||||||
|
* @param string $text text being processed
|
||||||
|
* @param string $file the php script used to serve files
|
||||||
|
* @param int $contextid
|
||||||
|
* @param string $component component
|
||||||
|
* @param string $filearea filearea
|
||||||
|
* @param array $ids other IDs will be used to check file permission
|
||||||
|
* @param int $itemid
|
||||||
|
* @param array $options
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function quiz_rewrite_question_urls($text, $file, $contextid, $component, $filearea, array $ids, $itemid, array $options=null) {
|
||||||
|
global $CFG;
|
||||||
|
|
||||||
|
$options = (array)$options;
|
||||||
|
if (!isset($options['forcehttps'])) {
|
||||||
|
$options['forcehttps'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$CFG->slasharguments) {
|
||||||
|
$file = $file . '?file=';
|
||||||
|
}
|
||||||
|
|
||||||
|
$baseurl = "$CFG->wwwroot/$file/$contextid/$component/$filearea/";
|
||||||
|
|
||||||
|
if (!empty($ids)) {
|
||||||
|
$baseurl .= (implode('/', $ids) . '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($itemid !== null) {
|
||||||
|
$baseurl .= "$itemid/";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options['forcehttps']) {
|
||||||
|
$baseurl = str_replace('http://', 'https://', $baseurl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace('@@PLUGINFILE@@/', $baseurl, $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by pluginfile.php to serve files related to the 'question' core
|
||||||
|
* component and for files belonging to qtypes.
|
||||||
|
*
|
||||||
|
* For files that relate to questions in a question_attempt, then we delegate to
|
||||||
|
* a function in the component that owns the attempt (for example in the quiz,
|
||||||
|
* or in core question preview) to get necessary inforation.
|
||||||
|
*
|
||||||
|
* (Note that, at the moment, all question file areas relate to questions in
|
||||||
|
* attempts, so the If at the start of the last paragraph is always true.)
|
||||||
|
*
|
||||||
|
* Does not return, either calls send_file_not_found(); or serves the file.
|
||||||
|
*
|
||||||
|
* @param object $course course settings object
|
||||||
|
* @param object $context context object
|
||||||
|
* @param string $component the name of the component we are serving files for.
|
||||||
|
* @param string $filearea the name of the file area.
|
||||||
|
* @param array $args the remaining bits of the file path.
|
||||||
|
* @param bool $forcedownload whether the user must be forced to download the file.
|
||||||
|
*/
|
||||||
|
function question_pluginfile($course, $context, $component, $filearea, $args, $forcedownload) {
|
||||||
|
global $DB, $CFG;
|
||||||
|
|
||||||
|
$attemptid = (int)array_shift($args);
|
||||||
|
$questionid = (int)array_shift($args);
|
||||||
|
|
||||||
|
require_login($course, false);
|
||||||
|
|
||||||
|
if ($attemptid === 0) {
|
||||||
|
// preview
|
||||||
|
require_once($CFG->dirroot . '/question/previewlib.php');
|
||||||
|
return question_preview_question_pluginfile($course, $context,
|
||||||
|
$component, $filearea, $attemptid, $questionid, $args, $forcedownload);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$module = $DB->get_field('question_attempts', 'modulename',
|
||||||
|
array('id' => $attemptid));
|
||||||
|
|
||||||
|
$dir = get_component_directory($module);
|
||||||
|
if (!file_exists("$dir/lib.php")) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
include_once("$dir/lib.php");
|
||||||
|
|
||||||
|
$filefunction = $module . '_question_pluginfile';
|
||||||
|
if (!function_exists($filefunction)) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
$filefunction($course, $context, $component, $filearea, $attemptid, $questionid,
|
||||||
|
$args, $forcedownload);
|
||||||
|
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Final test for whether a studnet should be allowed to see a particular file.
|
||||||
|
* This delegates the decision to the question type plugin.
|
||||||
|
*
|
||||||
|
* @param object $question The question to be rendered.
|
||||||
|
* @param object $state The state to render the question in.
|
||||||
|
* @param object $options An object specifying the rendering options.
|
||||||
|
* @param string $component the name of the component we are serving files for.
|
||||||
|
* @param string $filearea the name of the file area.
|
||||||
|
* @param array $args the remaining bits of the file path.
|
||||||
|
* @param bool $forcedownload whether the user must be forced to download the file.
|
||||||
|
*/
|
||||||
|
function question_check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args, $forcedownload) {
|
||||||
|
global $QTYPES;
|
||||||
|
return $QTYPES[$question->qtype]->check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args, $forcedownload);
|
||||||
|
}
|
||||||
|
|
|
@ -283,6 +283,10 @@ class quiz {
|
||||||
return $this->accessmanager;
|
return $this->accessmanager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_overall_feedback($grade) {
|
||||||
|
return quiz_feedback_for_grade($grade, $this->quiz, $this->context, $this->cm);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper round the has_capability funciton that automatically passes in the quiz context.
|
* Wrapper round the has_capability funciton that automatically passes in the quiz context.
|
||||||
*/
|
*/
|
||||||
|
@ -571,7 +575,7 @@ class quiz_attempt extends quiz {
|
||||||
return $this->attempt->timefinish != 0;
|
return $this->attempt->timefinish != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return boolean whether this attemp is a preview attempt. */
|
/** @return boolean whether this attempt is a preview attempt. */
|
||||||
public function is_preview() {
|
public function is_preview() {
|
||||||
return $this->attempt->preview;
|
return $this->attempt->preview;
|
||||||
}
|
}
|
||||||
|
@ -629,10 +633,12 @@ class quiz_attempt extends quiz {
|
||||||
/**
|
/**
|
||||||
* Wrapper that calls get_render_options with the appropriate arguments.
|
* Wrapper that calls get_render_options with the appropriate arguments.
|
||||||
*
|
*
|
||||||
|
* @param integer questionid the quetsion to get the render options for.
|
||||||
* @return object the render options for this user on this attempt.
|
* @return object the render options for this user on this attempt.
|
||||||
*/
|
*/
|
||||||
public function get_render_options($state) {
|
public function get_render_options($questionid) {
|
||||||
return quiz_get_renderoptions($this->quiz, $this->attempt, $this->context, $state);
|
return quiz_get_renderoptions($this->quiz, $this->attempt, $this->context,
|
||||||
|
$this->get_question_state($questionid));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -669,7 +675,7 @@ class quiz_attempt extends quiz {
|
||||||
case QUESTION_EVENTCLOSEANDGRADE:
|
case QUESTION_EVENTCLOSEANDGRADE:
|
||||||
case QUESTION_EVENTCLOSE:
|
case QUESTION_EVENTCLOSE:
|
||||||
case QUESTION_EVENTMANUALGRADE:
|
case QUESTION_EVENTMANUALGRADE:
|
||||||
$options = $this->get_render_options($this->states[$questionid]);
|
$options = $this->get_render_options($questionid);
|
||||||
if ($options->scores && $this->questions[$questionid]->maxgrade > 0) {
|
if ($options->scores && $this->questions[$questionid]->maxgrade > 0) {
|
||||||
return question_get_feedback_class($state->last_graded->raw_grade /
|
return question_get_feedback_class($state->last_graded->raw_grade /
|
||||||
$this->questions[$questionid]->maxgrade);
|
$this->questions[$questionid]->maxgrade);
|
||||||
|
@ -703,7 +709,7 @@ class quiz_attempt extends quiz {
|
||||||
* @return string the formatted grade, to the number of decimal places specified by the quiz.
|
* @return string the formatted grade, to the number of decimal places specified by the quiz.
|
||||||
*/
|
*/
|
||||||
public function get_question_score($questionid) {
|
public function get_question_score($questionid) {
|
||||||
$options = $this->get_render_options($this->states[$questionid]);
|
$options = $this->get_render_options($questionid);
|
||||||
if ($options->scores) {
|
if ($options->scores) {
|
||||||
return quiz_format_question_grade($this->quiz, $this->states[$questionid]->last_graded->grade);
|
return quiz_format_question_grade($this->quiz, $this->states[$questionid]->last_graded->grade);
|
||||||
} else {
|
} else {
|
||||||
|
@ -805,7 +811,7 @@ class quiz_attempt extends quiz {
|
||||||
if ($reviewing) {
|
if ($reviewing) {
|
||||||
$options = $this->get_review_options();
|
$options = $this->get_review_options();
|
||||||
} else {
|
} else {
|
||||||
$options = $this->get_render_options($this->states[$id]);
|
$options = $this->get_render_options($id);
|
||||||
}
|
}
|
||||||
if ($thispageurl) {
|
if ($thispageurl) {
|
||||||
$this->quiz->thispageurl = $thispageurl;
|
$this->quiz->thispageurl = $thispageurl;
|
||||||
|
@ -816,6 +822,20 @@ class quiz_attempt extends quiz {
|
||||||
$this->quiz, $options);
|
$this->quiz, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function check_file_access($questionid, $isreviewing, $contextid, $component,
|
||||||
|
$filearea, $args, $forcedownload) {
|
||||||
|
if ($isreviewing) {
|
||||||
|
$options = $this->get_review_options();
|
||||||
|
} else {
|
||||||
|
$options = $this->get_render_options($questionid);
|
||||||
|
}
|
||||||
|
// XXX: mulitichoice type needs quiz id to get maxgrade
|
||||||
|
$options->quizid = $this->attempt->quiz;
|
||||||
|
return question_check_file_access($this->questions[$questionid],
|
||||||
|
$this->get_question_state($questionid), $options, $contextid,
|
||||||
|
$component, $filearea, $args, $forcedownload);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers the sending of the notification emails at the end of this attempt.
|
* Triggers the sending of the notification emails at the end of this attempt.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<XMLDB PATH="mod/quiz/db" VERSION="20100220" COMMENT="XMLDB file for Moodle mod/quiz"
|
<XMLDB PATH="mod/quiz/db" VERSION="20100722" COMMENT="XMLDB file for Moodle mod/quiz"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||||
>
|
>
|
||||||
|
@ -100,8 +100,9 @@
|
||||||
<FIELDS>
|
<FIELDS>
|
||||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="quizid"/>
|
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="quizid"/>
|
||||||
<FIELD NAME="quizid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references quiz.id." PREVIOUS="id" NEXT="feedbacktext"/>
|
<FIELD NAME="quizid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references quiz.id." PREVIOUS="id" NEXT="feedbacktext"/>
|
||||||
<FIELD NAME="feedbacktext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="The feedback to show for a attempt where mingrade <= attempt grade < maxgrade. See function quiz_feedback_for_grade in mod/quiz/locallib.php." PREVIOUS="quizid" NEXT="mingrade"/>
|
<FIELD NAME="feedbacktext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="The feedback to show for a attempt where mingrade <= attempt grade < maxgrade. See function quiz_feedback_for_grade in mod/quiz/locallib.php." PREVIOUS="quizid" NEXT="feedbacktextformat"/>
|
||||||
<FIELD NAME="mingrade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="The lower limit of this grade band. Inclusive." PREVIOUS="feedbacktext" NEXT="maxgrade"/>
|
<FIELD NAME="feedbacktextformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="feedbacktext" NEXT="mingrade"/>
|
||||||
|
<FIELD NAME="mingrade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="The lower limit of this grade band. Inclusive." PREVIOUS="feedbacktextformat" NEXT="maxgrade"/>
|
||||||
<FIELD NAME="maxgrade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="The upper limit of this grade band. Exclusive." PREVIOUS="mingrade"/>
|
<FIELD NAME="maxgrade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="The upper limit of this grade band. Exclusive." PREVIOUS="mingrade"/>
|
||||||
</FIELDS>
|
</FIELDS>
|
||||||
<KEYS>
|
<KEYS>
|
||||||
|
|
|
@ -341,6 +341,22 @@ function xmldb_quiz_upgrade($oldversion) {
|
||||||
upgrade_mod_savepoint(true, 2010051800, 'quiz');
|
upgrade_mod_savepoint(true, 2010051800, 'quiz');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($oldversion < 2010080600) {
|
||||||
|
|
||||||
|
// Define field feedbacktextformat to be added to quiz_feedback
|
||||||
|
$table = new xmldb_table('quiz_feedback');
|
||||||
|
$field = new xmldb_field('feedbacktextformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'feedbacktext');
|
||||||
|
|
||||||
|
// Conditionally launch add field feedbacktextformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// quiz savepoint reached
|
||||||
|
upgrade_mod_savepoint(true, 2010080600, 'quiz');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@
|
||||||
$grade = get_string('outofshort', 'quiz', $a);
|
$grade = get_string('outofshort', 'quiz', $a);
|
||||||
}
|
}
|
||||||
if ($alloptions->overallfeedback) {
|
if ($alloptions->overallfeedback) {
|
||||||
$feedback = quiz_feedback_for_grade($scores[$quiz->id], $quiz->id);
|
$feedback = quiz_feedback_for_grade($scores[$quiz->id], $quiz, $context, $cm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$data[] = $grade;
|
$data[] = $grade;
|
||||||
|
|
163
mod/quiz/lib.php
163
mod/quiz/lib.php
|
@ -104,6 +104,7 @@ define("QUIZ_MAX_EVENT_LENGTH", 5*24*60*60); // 5 days maximum
|
||||||
*/
|
*/
|
||||||
function quiz_add_instance($quiz) {
|
function quiz_add_instance($quiz) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
$cmid = $quiz->coursemodule;
|
||||||
|
|
||||||
// Process the options from the form.
|
// Process the options from the form.
|
||||||
$quiz->created = time();
|
$quiz->created = time();
|
||||||
|
@ -982,10 +983,10 @@ function quiz_process_options(&$quiz) {
|
||||||
if (isset($quiz->feedbacktext)) {
|
if (isset($quiz->feedbacktext)) {
|
||||||
// Clean up the boundary text.
|
// Clean up the boundary text.
|
||||||
for ($i = 0; $i < count($quiz->feedbacktext); $i += 1) {
|
for ($i = 0; $i < count($quiz->feedbacktext); $i += 1) {
|
||||||
if (empty($quiz->feedbacktext[$i])) {
|
if (empty($quiz->feedbacktext[$i]['text'])) {
|
||||||
$quiz->feedbacktext[$i] = '';
|
$quiz->feedbacktext[$i]['text'] = '';
|
||||||
} else {
|
} else {
|
||||||
$quiz->feedbacktext[$i] = trim($quiz->feedbacktext[$i]);
|
$quiz->feedbacktext[$i]['text'] = trim($quiz->feedbacktext[$i]['text']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1023,7 +1024,7 @@ function quiz_process_options(&$quiz) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ($i = $numboundaries + 1; $i < count($quiz->feedbacktext); $i += 1) {
|
for ($i = $numboundaries + 1; $i < count($quiz->feedbacktext); $i += 1) {
|
||||||
if (!empty($quiz->feedbacktext[$i]) && trim($quiz->feedbacktext[$i]) != '') {
|
if (!empty($quiz->feedbacktext[$i]['text']) && trim($quiz->feedbacktext[$i]['text']) != '') {
|
||||||
return get_string('feedbackerrorjunkinfeedback', 'quiz', $i + 1);
|
return get_string('feedbackerrorjunkinfeedback', 'quiz', $i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1145,17 +1146,25 @@ function quiz_process_options(&$quiz) {
|
||||||
*/
|
*/
|
||||||
function quiz_after_add_or_update($quiz) {
|
function quiz_after_add_or_update($quiz) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
$cmid = $quiz->coursemodule;
|
||||||
|
|
||||||
|
// we need to use context now, so we need to make sure all needed info is already in db
|
||||||
|
$DB->set_field('course_modules', 'instance', $quiz->id, array('id'=>$cmid));
|
||||||
|
$context = get_context_instance(CONTEXT_MODULE, $cmid);
|
||||||
|
|
||||||
// Save the feedback
|
// Save the feedback
|
||||||
$DB->delete_records('quiz_feedback', array('quizid' => $quiz->id));
|
$DB->delete_records('quiz_feedback', array('quizid' => $quiz->id));
|
||||||
|
|
||||||
for ($i = 0; $i <= $quiz->feedbackboundarycount; $i += 1) {
|
for ($i = 0; $i <= $quiz->feedbackboundarycount; $i++) {
|
||||||
$feedback = new stdClass;
|
$feedback = new stdClass;
|
||||||
$feedback->quizid = $quiz->id;
|
$feedback->quizid = $quiz->id;
|
||||||
$feedback->feedbacktext = $quiz->feedbacktext[$i];
|
$feedback->feedbacktext = $quiz->feedbacktext[$i]['text'];
|
||||||
|
$feedback->feedbacktextformat = $quiz->feedbacktext[$i]['format'];
|
||||||
$feedback->mingrade = $quiz->feedbackboundaries[$i];
|
$feedback->mingrade = $quiz->feedbackboundaries[$i];
|
||||||
$feedback->maxgrade = $quiz->feedbackboundaries[$i - 1];
|
$feedback->maxgrade = $quiz->feedbackboundaries[$i - 1];
|
||||||
$DB->insert_record('quiz_feedback', $feedback, false);
|
$feedback->id = $DB->insert_record('quiz_feedback', $feedback);
|
||||||
|
$feedbacktext = file_save_draft_area_files((int)$quiz->feedbacktext[$i]['itemid'], $context->id, 'mod_quiz', 'feedback', $feedback->id, array('subdirs'=>false, 'maxfiles'=>-1, 'maxbytes'=>0), $quiz->feedbacktext[$i]['text']);
|
||||||
|
$DB->set_field('quiz_feedback', 'feedbacktext', $feedbacktext, array('id'=>$feedback->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the events relating to this quiz.
|
// Update the events relating to this quiz.
|
||||||
|
@ -1421,23 +1430,44 @@ function quiz_reset_userdata($data) {
|
||||||
* @param int $questionid int question id
|
* @param int $questionid int question id
|
||||||
* @return boolean to indicate access granted or denied
|
* @return boolean to indicate access granted or denied
|
||||||
*/
|
*/
|
||||||
function quiz_check_file_access($attemptuniqueid, $questionid) {
|
function quiz_check_file_access($attemptuniqueid, $questionid, $context = null) {
|
||||||
global $USER, $DB;
|
global $USER, $DB, $CFG;
|
||||||
|
require_once(dirname(__FILE__).'/attemptlib.php');
|
||||||
|
require_once(dirname(__FILE__).'/locallib.php');
|
||||||
|
|
||||||
$attempt = $DB->get_record('quiz_attempts', array('uniqueid' => $attemptuniqueid));
|
$attempt = $DB->get_record('quiz_attempts', array('uniqueid' => $attemptuniqueid));
|
||||||
$quiz = $DB->get_record('quiz', array('id' => $attempt->quiz));
|
$attemptobj = quiz_attempt::create($attempt->id);
|
||||||
$context = get_context_instance(CONTEXT_COURSE, $quiz->course);
|
|
||||||
|
|
||||||
// access granted if the current user submitted this file
|
// does question exist?
|
||||||
if ($attempt->userid == $USER->id) {
|
if (!$question = $DB->get_record('question', array('id' => $questionid))) {
|
||||||
return true;
|
return false;
|
||||||
// access granted if the current user has permission to grade quizzes in this course
|
|
||||||
} else if (has_capability('mod/quiz:viewreports', $context) || has_capability('mod/quiz:grade', $context)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, this user does not have permission
|
if ($context === null) {
|
||||||
return false;
|
$quiz = $DB->get_record('quiz', array('id' => $attempt->quiz));
|
||||||
|
$cm = get_coursemodule_from_id('quiz', $quiz->id);
|
||||||
|
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load those questions and the associated states.
|
||||||
|
$attemptobj->load_questions(array($questionid));
|
||||||
|
$attemptobj->load_question_states(array($questionid));
|
||||||
|
|
||||||
|
// obtain state
|
||||||
|
$state = $attemptobj->get_question_state($questionid);
|
||||||
|
// obtain questoin
|
||||||
|
$question = $attemptobj->get_question($questionid);
|
||||||
|
|
||||||
|
// access granted if the current user submitted this file
|
||||||
|
if ($attempt->userid != $USER->id) {
|
||||||
|
return false;
|
||||||
|
// access granted if the current user has permission to grade quizzes in this course
|
||||||
|
}
|
||||||
|
if (!(has_capability('mod/quiz:viewreports', $context) || has_capability('mod/quiz:grade', $context))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($question, $state, array());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1682,3 +1712,98 @@ function quiz_extend_settings_navigation($settings, $quiznode) {
|
||||||
|
|
||||||
question_extend_settings_navigation($quiznode, $PAGE->cm->context)->trim_if_empty();
|
question_extend_settings_navigation($quiznode, $PAGE->cm->context)->trim_if_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serves the quiz files.
|
||||||
|
*
|
||||||
|
* @param object $course
|
||||||
|
* @param object $cm
|
||||||
|
* @param object $context
|
||||||
|
* @param string $filearea
|
||||||
|
* @param array $args
|
||||||
|
* @param bool $forcedownload
|
||||||
|
* @return bool false if file not found, does not return if found - justsend the file
|
||||||
|
*/
|
||||||
|
function quiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $CFG, $DB;
|
||||||
|
|
||||||
|
if ($context->contextlevel != CONTEXT_MODULE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_login($course, false, $cm);
|
||||||
|
|
||||||
|
if (!$quiz = $DB->get_record('quiz', array('id'=>$cm->instance))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'intro' area is served by pluginfile.php
|
||||||
|
$fileareas = array('feedback');
|
||||||
|
if (!in_array($filearea, $fileareas)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$feedbackid = (int)array_shift($args);
|
||||||
|
if (!$feedback = $DB->get_record('quiz_feedback', array('id'=>$feedbackid))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
$relativepath = implode('/', $args);
|
||||||
|
$fullpath = "/$context->id/mod_quiz/$filearea/$feedbackid/$relativepath";
|
||||||
|
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
send_stored_file($file, 0, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called via pluginfile.php -> question_pluginfile to serve files belonging to
|
||||||
|
* a question in a question_attempt when that attempt is a quiz attempt.
|
||||||
|
*
|
||||||
|
* @param object $course course settings object
|
||||||
|
* @param object $context context object
|
||||||
|
* @param string $component the name of the component we are serving files for.
|
||||||
|
* @param string $filearea the name of the file area.
|
||||||
|
* @param array $args the remaining bits of the file path.
|
||||||
|
* @param bool $forcedownload whether the user must be forced to download the file.
|
||||||
|
* @return bool false if file not found, does not return if found - justsend the file
|
||||||
|
*/
|
||||||
|
function quiz_question_pluginfile($course, $context, $component,
|
||||||
|
$filearea, $attemptid, $questionid, $args, $forcedownload) {
|
||||||
|
global $USER, $CFG;
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||||
|
|
||||||
|
$attemptobj = quiz_attempt::create($attemptid);
|
||||||
|
require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm());
|
||||||
|
$questionids = array($questionid);
|
||||||
|
$attemptobj->load_questions($questionids);
|
||||||
|
$attemptobj->load_question_states($questionids);
|
||||||
|
|
||||||
|
if ($attemptobj->is_own_attempt() && !$attemptobj->is_finished()) {
|
||||||
|
// In the middle of an attempt.
|
||||||
|
if (!$attemptobj->is_preview_user()) {
|
||||||
|
$attemptobj->require_capability('mod/quiz:attempt');
|
||||||
|
}
|
||||||
|
$isreviewing = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Reviewing an attempt.
|
||||||
|
$attemptobj->check_review_capability();
|
||||||
|
$isreviewing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$attemptobj->check_file_access($questionid, $isreviewing, $context->id,
|
||||||
|
$component, $filearea, $args, $forcedownload)) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
$relativepath = implode('/', $args);
|
||||||
|
$fullpath = "/$context->id/$component/$filearea/$relativepath";
|
||||||
|
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
send_stored_file($file, 0, 0, $forcedownload);
|
||||||
|
}
|
||||||
|
|
|
@ -456,21 +456,22 @@ function quiz_rescale_grade($rawgrade, $quiz, $round = true) {
|
||||||
* @param integer $quizid the id of the quiz object.
|
* @param integer $quizid the id of the quiz object.
|
||||||
* @return string the comment that corresponds to this grade (empty string if there is not one.
|
* @return string the comment that corresponds to this grade (empty string if there is not one.
|
||||||
*/
|
*/
|
||||||
function quiz_feedback_for_grade($grade, $quizid) {
|
function quiz_feedback_for_grade($grade, $quiz, $context, $cm=null) {
|
||||||
global $DB;
|
global $DB;
|
||||||
$feedback = $DB->get_field_select('quiz_feedback', 'feedbacktext',
|
|
||||||
"quizid = ? AND mingrade <= ? AND $grade < maxgrade", array($quizid, $grade));
|
|
||||||
|
|
||||||
if (empty($feedback)) {
|
$feedback = $DB->get_record_select('quiz_feedback', "quizid = ? AND mingrade <= ? AND $grade < maxgrade", array($quiz->id, $grade));
|
||||||
$feedback = '';
|
|
||||||
|
if (empty($feedback->feedbacktext)) {
|
||||||
|
$feedback->feedbacktext = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean the text, ready for display.
|
// Clean the text, ready for display.
|
||||||
$formatoptions = new stdClass;
|
$formatoptions = new stdClass;
|
||||||
$formatoptions->noclean = true;
|
$formatoptions->noclean = true;
|
||||||
$feedback = format_text($feedback, FORMAT_MOODLE, $formatoptions);
|
$feedbacktext = file_rewrite_pluginfile_urls($feedback->feedbacktext, 'pluginfile.php', $context->id, 'mod_quiz', 'feedback', $feedback->id);
|
||||||
|
$feedbacktext = format_text($feedbacktext, $feedback->feedbacktextformat, $formatoptions);
|
||||||
|
|
||||||
return $feedback;
|
return $feedbacktext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1263,4 +1264,4 @@ function quiz_get_js_module() {
|
||||||
array('flagged', 'question'),
|
array('flagged', 'question'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -296,7 +296,7 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||||
$mform->addElement('static', 'gradeboundarystatic1', get_string('gradeboundary', 'quiz'), '100%');
|
$mform->addElement('static', 'gradeboundarystatic1', get_string('gradeboundary', 'quiz'), '100%');
|
||||||
|
|
||||||
$repeatarray = array();
|
$repeatarray = array();
|
||||||
$repeatarray[] = &MoodleQuickForm::createElement('text', 'feedbacktext', get_string('feedback', 'quiz'), array('size' => 50));
|
$repeatarray[] = &MoodleQuickForm::createElement('editor', 'feedbacktext', get_string('feedback', 'quiz'), null, array('maxfiles'=>EDITOR_UNLIMITED_FILES, 'noclean'=>true, 'context'=>$this->context));
|
||||||
$mform->setType('feedbacktext', PARAM_RAW);
|
$mform->setType('feedbacktext', PARAM_RAW);
|
||||||
$repeatarray[] = &MoodleQuickForm::createElement('text', 'feedbackboundaries', get_string('gradeboundary', 'quiz'), array('size' => 10));
|
$repeatarray[] = &MoodleQuickForm::createElement('text', 'feedbackboundaries', get_string('gradeboundary', 'quiz'), array('size' => 10));
|
||||||
$mform->setType('feedbackboundaries', PARAM_NOTAGS);
|
$mform->setType('feedbackboundaries', PARAM_NOTAGS);
|
||||||
|
@ -313,7 +313,7 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||||
get_string('addmoreoverallfeedbacks', 'quiz'), true);
|
get_string('addmoreoverallfeedbacks', 'quiz'), true);
|
||||||
|
|
||||||
// Put some extra elements in before the button
|
// Put some extra elements in before the button
|
||||||
$insertEl = &MoodleQuickForm::createElement('text', "feedbacktext[$nextel]", get_string('feedback', 'quiz'), array('size' => 50));
|
$insertEl = &MoodleQuickForm::createElement('editor', "feedbacktext[$nextel]", get_string('feedback', 'quiz'), null, array('maxfiles'=>EDITOR_UNLIMITED_FILES, 'noclean'=>true, 'context'=>$this->context));
|
||||||
$mform->insertElementBefore($insertEl, 'boundary_add_fields');
|
$mform->insertElementBefore($insertEl, 'boundary_add_fields');
|
||||||
|
|
||||||
$insertEl = &MoodleQuickForm::createElement('static', 'gradeboundarystatic2', get_string('gradeboundary', 'quiz'), '0%');
|
$insertEl = &MoodleQuickForm::createElement('static', 'gradeboundarystatic2', get_string('gradeboundary', 'quiz'), '0%');
|
||||||
|
@ -342,7 +342,19 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||||
if (count($this->_feedbacks)) {
|
if (count($this->_feedbacks)) {
|
||||||
$key = 0;
|
$key = 0;
|
||||||
foreach ($this->_feedbacks as $feedback){
|
foreach ($this->_feedbacks as $feedback){
|
||||||
$default_values['feedbacktext['.$key.']'] = $feedback->feedbacktext;
|
$draftid = file_get_submitted_draft_itemid('feedbacktext['.$key.']');
|
||||||
|
$default_values['feedbacktext['.$key.']']['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'mod_quiz', // component
|
||||||
|
'feedback', // filarea
|
||||||
|
!empty($feedback->id)?(int)$feedback->id:null, // itemid
|
||||||
|
null,
|
||||||
|
$feedback->feedbacktext // text
|
||||||
|
);
|
||||||
|
$default_values['feedbacktext['.$key.']']['format'] = $feedback->feedbacktextformat;
|
||||||
|
$default_values['feedbacktext['.$key.']']['itemid'] = $draftid;
|
||||||
|
|
||||||
if ($feedback->mingrade > 0) {
|
if ($feedback->mingrade > 0) {
|
||||||
$default_values['feedbackboundaries['.$key.']'] = (100.0 * $feedback->mingrade / $default_values['grade']) . '%';
|
$default_values['feedbackboundaries['.$key.']'] = (100.0 * $feedback->mingrade / $default_values['grade']) . '%';
|
||||||
}
|
}
|
||||||
|
@ -433,7 +445,7 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ($i = $numboundaries + 1; $i < count($data['feedbacktext']); $i += 1) {
|
for ($i = $numboundaries + 1; $i < count($data['feedbacktext']); $i += 1) {
|
||||||
if (!empty($data['feedbacktext'][$i] ) && trim($data['feedbacktext'][$i] ) != '') {
|
if (!empty($data['feedbacktext'][$i]['text']) && trim($data['feedbacktext'][$i]['text'] ) != '') {
|
||||||
$errors["feedbacktext[$i]"] = get_string('feedbackerrorjunkinfeedback', 'quiz', $i + 1);
|
$errors["feedbacktext[$i]"] = get_string('feedbackerrorjunkinfeedback', 'quiz', $i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,7 +200,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feedback if there is any, and the user is allowed to see it now.
|
/// Feedback if there is any, and the user is allowed to see it now.
|
||||||
$feedback = quiz_feedback_for_grade($grade, $attempt->quiz);
|
$feedback = $attemptobj->get_overall_feedback($grade);
|
||||||
if ($options->overallfeedback && $feedback) {
|
if ($options->overallfeedback && $feedback) {
|
||||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('feedback', 'quiz') .
|
$rows[] = '<tr><th scope="row" class="cell">' . get_string('feedback', 'quiz') .
|
||||||
'</th><td class="cell">' . $feedback . '</td></tr>';
|
'</th><td class="cell">' . $feedback . '</td></tr>';
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// This fragment is called by moodle_needs_upgrading() and /admin/index.php
|
// This fragment is called by moodle_needs_upgrading() and /admin/index.php
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
$module->version = 2010051801; // The (date) version of this module
|
$module->version = 2010080600; // The (date) version of this module
|
||||||
$module->requires = 2010080300; // Requires this Moodle version
|
$module->requires = 2010080300; // Requires this Moodle version
|
||||||
$module->cron = 0; // How often should cron check this module (seconds)?
|
$module->cron = 0; // How often should cron check this module (seconds)?
|
||||||
|
|
||||||
|
|
|
@ -277,7 +277,7 @@
|
||||||
|
|
||||||
if ($feedbackcolumn && $attempt->timefinish > 0) {
|
if ($feedbackcolumn && $attempt->timefinish > 0) {
|
||||||
if ($attemptoptions->overallfeedback) {
|
if ($attemptoptions->overallfeedback) {
|
||||||
$row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id);
|
$row[] = quiz_feedback_for_grade($attemptgrade, $quiz, $context, $cm);
|
||||||
} else {
|
} else {
|
||||||
$row[] = '';
|
$row[] = '';
|
||||||
}
|
}
|
||||||
|
@ -330,7 +330,7 @@
|
||||||
}
|
}
|
||||||
if ($feedbackcolumn) {
|
if ($feedbackcolumn) {
|
||||||
$resultinfo .= $OUTPUT->heading(get_string('overallfeedback', 'quiz'), 3, 'main');
|
$resultinfo .= $OUTPUT->heading(get_string('overallfeedback', 'quiz'), 3, 'main');
|
||||||
$resultinfo .= '<p class="quizgradefeedback">'.quiz_feedback_for_grade($mygrade, $quiz->id)."</p>\n";
|
$resultinfo .= '<p class="quizgradefeedback">'.quiz_feedback_for_grade($mygrade, $quiz, $context, $cm)."</p>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($resultinfo) {
|
if ($resultinfo) {
|
||||||
|
|
|
@ -630,6 +630,12 @@ if ($component === 'blog') {
|
||||||
send_file_not_found();
|
send_file_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================================================================
|
||||||
|
} else if ($component === 'question') {
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'question', $filearea, $args, $forcedownload);
|
||||||
|
send_file_not_found();
|
||||||
|
|
||||||
// ========================================================================================================================
|
// ========================================================================================================================
|
||||||
} else if (strpos($component, 'mod_') === 0) {
|
} else if (strpos($component, 'mod_') === 0) {
|
||||||
$modname = substr($component, 4);
|
$modname = substr($component, 4);
|
||||||
|
|
|
@ -12,7 +12,7 @@ require_once(dirname(__FILE__) . '/../config.php');
|
||||||
require_once(dirname(__FILE__) . '/editlib.php');
|
require_once(dirname(__FILE__) . '/editlib.php');
|
||||||
require_once($CFG->dirroot.'/question/contextmoveq_form.php');
|
require_once($CFG->dirroot.'/question/contextmoveq_form.php');
|
||||||
|
|
||||||
$ids = required_param('ids',PARAM_SEQUENCE); // question ids
|
$ids = required_param('ids', PARAM_SEQUENCE); // question ids
|
||||||
|
|
||||||
if (!$cmid = optional_param('cmid', 0, PARAM_INT)){
|
if (!$cmid = optional_param('cmid', 0, PARAM_INT)){
|
||||||
$courseid = required_param('courseid', PARAM_INT);
|
$courseid = required_param('courseid', PARAM_INT);
|
||||||
|
@ -165,6 +165,9 @@ if ($contextmoveform->is_cancelled()){
|
||||||
if (!question_move_questions_to_category($ids, $tocat->id)) {
|
if (!question_move_questions_to_category($ids, $tocat->id)) {
|
||||||
print_error('errormovingquestions', 'question', $returnurl, $ids);
|
print_error('errormovingquestions', 'question', $returnurl, $ids);
|
||||||
}
|
}
|
||||||
|
if ($returnurl) {
|
||||||
|
$returnurl = new moodle_url('/' . $returnurl);
|
||||||
|
}
|
||||||
redirect($returnurl);
|
redirect($returnurl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page to edit the question bank
|
* Page to edit the question bank
|
||||||
*
|
*
|
||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||||
* @package questionbank
|
* @package questionbank
|
||||||
*//** */
|
*/
|
||||||
|
|
||||||
require_once("../config.php");
|
require_once("../config.php");
|
||||||
require_once("editlib.php");
|
require_once("editlib.php");
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
|
|
||||||
$context = $contexts->lowest();
|
$context = $contexts->lowest();
|
||||||
$streditingquestions = get_string('editquestions', "quiz");
|
$streditingquestions = get_string('editquestions', "quiz");
|
||||||
$PAGE->set_title($streditingquestions);
|
$PAGE->set_title($streditingquestions);
|
||||||
$PAGE->set_heading($COURSE->fullname);
|
$PAGE->set_heading($COURSE->fullname);
|
||||||
echo $OUTPUT->header();
|
echo $OUTPUT->header();
|
||||||
|
|
||||||
|
|
|
@ -1402,7 +1402,7 @@ class question_bank_view {
|
||||||
$questionids[] = $key;
|
$questionids[] = $key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($questionids){
|
if ($questionids) {
|
||||||
list($usql, $params) = $DB->get_in_or_equal($questionids);
|
list($usql, $params) = $DB->get_in_or_equal($questionids);
|
||||||
$sql = "SELECT q.*, c.contextid FROM {question} q, {question_categories} c WHERE q.id $usql AND c.id = q.category";
|
$sql = "SELECT q.*, c.contextid FROM {question} q, {question_categories} c WHERE q.id $usql AND c.id = q.category";
|
||||||
if (!$questions = $DB->get_records_sql($sql, $params)){
|
if (!$questions = $DB->get_records_sql($sql, $params)){
|
||||||
|
@ -1426,8 +1426,9 @@ class question_bank_view {
|
||||||
} else {
|
} else {
|
||||||
$returnurl = str_replace($CFG->wwwroot . '/', '', $returnurl);
|
$returnurl = str_replace($CFG->wwwroot . '/', '', $returnurl);
|
||||||
$movecontexturl = new moodle_url('/question/contextmoveq.php',
|
$movecontexturl = new moodle_url('/question/contextmoveq.php',
|
||||||
array('returnurl' => $returnurl, 'ids' => $questionids,
|
array('returnurl' => $returnurl,
|
||||||
'tocatid' => $tocategoryid));
|
'ids' => implode(',', $questionids),
|
||||||
|
'tocatid' => $tocategoryid));
|
||||||
if (!empty($cm->id)){
|
if (!empty($cm->id)){
|
||||||
$movecontexturl->param('cmid', $cm->id);
|
$movecontexturl->param('cmid', $cm->id);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -862,6 +862,7 @@ class qformat_default {
|
||||||
* performs the conversion.
|
* performs the conversion.
|
||||||
*/
|
*/
|
||||||
function format_question_text($question) {
|
function format_question_text($question) {
|
||||||
|
global $DB;
|
||||||
$formatoptions = new stdClass;
|
$formatoptions = new stdClass;
|
||||||
$formatoptions->noclean = true;
|
$formatoptions->noclean = true;
|
||||||
$formatoptions->para = false;
|
$formatoptions->para = false;
|
||||||
|
@ -870,10 +871,7 @@ class qformat_default {
|
||||||
} else {
|
} else {
|
||||||
$format = $question->questiontextformat;
|
$format = $question->questiontextformat;
|
||||||
}
|
}
|
||||||
return format_text($question->questiontext, $format, $formatoptions);
|
$text = $question->questiontext;
|
||||||
|
return format_text(html_to_text($text), $format, $formatoptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
$PAGE->set_title($strpreview);
|
$PAGE->set_title($strpreview);
|
||||||
$PAGE->set_heading($COURSE->fullname);
|
$PAGE->set_heading($COURSE->fullname);
|
||||||
echo $OUTPUT->header();
|
echo $OUTPUT->header();
|
||||||
|
|
||||||
if (!empty($quizid)) {
|
if (!empty($quizid)) {
|
||||||
echo '<p class="quemodname">'.get_string('modulename', 'quiz') . ': ';
|
echo '<p class="quemodname">'.get_string('modulename', 'quiz') . ': ';
|
||||||
p(format_string($quiz->name));
|
p(format_string($quiz->name));
|
||||||
|
@ -219,7 +219,7 @@
|
||||||
}
|
}
|
||||||
$number = 1;
|
$number = 1;
|
||||||
echo '<form method="post" action="'.$url->out_omit_querystring().'" enctype="multipart/form-data" id="responseform">', "\n";
|
echo '<form method="post" action="'.$url->out_omit_querystring().'" enctype="multipart/form-data" id="responseform">', "\n";
|
||||||
print_question($questions[$id], $curstate, $number, $quiz, $options);
|
print_question($questions[$id], $curstate, $number, $quiz, $options, $context);
|
||||||
|
|
||||||
echo '<div class="controls">';
|
echo '<div class="controls">';
|
||||||
echo html_writer::input_hidden_params($url);
|
echo html_writer::input_hidden_params($url);
|
||||||
|
|
108
question/previewlib.php
Normal file
108
question/previewlib.php
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Library functions used by question/preview.php.
|
||||||
|
*
|
||||||
|
* @package core
|
||||||
|
* @subpackage questionengine
|
||||||
|
* @copyright 2010 The Open University
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called via pluginfile.php -> question_pluginfile to serve files belonging to
|
||||||
|
* a question in a question_attempt when that attempt is a preview.
|
||||||
|
*
|
||||||
|
* @param object $course course settings object
|
||||||
|
* @param object $context context object
|
||||||
|
* @param string $component the name of the component we are serving files for.
|
||||||
|
* @param string $filearea the name of the file area.
|
||||||
|
* @param array $args the remaining bits of the file path.
|
||||||
|
* @param bool $forcedownload whether the user must be forced to download the file.
|
||||||
|
* @return bool false if file not found, does not return if found - justsend the file
|
||||||
|
*/
|
||||||
|
function question_preview_question_pluginfile($course, $context, $component,
|
||||||
|
$filearea, $attemptid, $questionid, $args, $forcedownload) {
|
||||||
|
global $USER, $SESSION, $DB, $CFG;
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||||
|
|
||||||
|
if (!$question = $DB->get_record('question', array('id' => $questionid))) {
|
||||||
|
return send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!question_has_capability_on($question, 'use', $question->category)) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($SESSION->quizpreview->states) || $SESSION->quizpreview->questionid != $questionid) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
$states = end($SESSION->quizpreview->states);
|
||||||
|
if (!array_key_exists($question->id, $states)) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
$state = $states[$question->id];
|
||||||
|
|
||||||
|
// Build fake cmoptions
|
||||||
|
$quiz = new cmoptions;
|
||||||
|
$quiz->id = 0;
|
||||||
|
$quiz->review = get_config('quiz', 'review');
|
||||||
|
if (empty($course->id)) {
|
||||||
|
$quiz->course = SITEID;
|
||||||
|
} else {
|
||||||
|
$quiz->course = $course->id;
|
||||||
|
}
|
||||||
|
$quiz->decimalpoints = get_config('quiz', 'decimalpoints');
|
||||||
|
|
||||||
|
$questions[$question->id] = $question;
|
||||||
|
get_question_options($questions);
|
||||||
|
|
||||||
|
// Build fake attempt
|
||||||
|
$timenow = time();
|
||||||
|
$attempt = new stdclass;
|
||||||
|
$attempt->quiz = $quiz->id;
|
||||||
|
$attempt->userid = $USER->id;
|
||||||
|
$attempt->attempt = 0;
|
||||||
|
$attempt->sumgrades = 0;
|
||||||
|
$attempt->timestart = $timenow;
|
||||||
|
$attempt->timefinish = 0;
|
||||||
|
$attempt->timemodified = $timenow;
|
||||||
|
$attempt->uniqueid = 0;
|
||||||
|
$attempt->id = 0;
|
||||||
|
$attempt->layout = $question->id;
|
||||||
|
|
||||||
|
$options = quiz_get_renderoptions($quiz, $attempt, $context, $state);
|
||||||
|
$options->noeditlink = true;
|
||||||
|
// XXX: mulitichoice type needs quiz id to get maxgrade
|
||||||
|
$options->quizid = 0;
|
||||||
|
|
||||||
|
if (!question_check_file_access($question, $state, $options, $context->id, $component,
|
||||||
|
$filearea, $args, $forcedownload)) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
$relativepath = implode('/', $args);
|
||||||
|
$fullpath = "/$context->id/$component/$filearea/$relativepath";
|
||||||
|
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
|
||||||
|
send_file_not_found();
|
||||||
|
}
|
||||||
|
|
||||||
|
send_stored_file($file, 0, 0, $forcedownload);
|
||||||
|
}
|
|
@ -75,6 +75,7 @@ if ($cmid){
|
||||||
$thiscontext = get_context_instance(CONTEXT_MODULE, $cmid);
|
$thiscontext = get_context_instance(CONTEXT_MODULE, $cmid);
|
||||||
} elseif ($courseid) {
|
} elseif ($courseid) {
|
||||||
require_login($courseid, false);
|
require_login($courseid, false);
|
||||||
|
$PAGE->set_pagelayout('course');
|
||||||
$thiscontext = get_context_instance(CONTEXT_COURSE, $courseid);
|
$thiscontext = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||||
$module = null;
|
$module = null;
|
||||||
$cm = null;
|
$cm = null;
|
||||||
|
@ -106,7 +107,7 @@ if ($id) {
|
||||||
|
|
||||||
} else if ($categoryid) {
|
} else if ($categoryid) {
|
||||||
// Category, but no qtype. They probably came from the addquestion.php
|
// Category, but no qtype. They probably came from the addquestion.php
|
||||||
// script without choosing a question type. Send them back.
|
// script without choosing a question type. Send them back.
|
||||||
$addurl = new moodle_url('/question/addquestion.php', $url->params());
|
$addurl = new moodle_url('/question/addquestion.php', $url->params());
|
||||||
$addurl->param('validationerror', 1);
|
$addurl->param('validationerror', 1);
|
||||||
redirect($addurl);
|
redirect($addurl);
|
||||||
|
@ -151,6 +152,8 @@ if ($id) {
|
||||||
} else { // creating a new question
|
} else { // creating a new question
|
||||||
require_capability('moodle/question:add', $categorycontext);
|
require_capability('moodle/question:add', $categorycontext);
|
||||||
$formeditable = true;
|
$formeditable = true;
|
||||||
|
$question->formoptions->canedit = question_has_capability_on($question, 'edit');
|
||||||
|
$question->formoptions->canmove = (question_has_capability_on($question, 'move') && $addpermission);
|
||||||
$question->formoptions->repeatelements = true;
|
$question->formoptions->repeatelements = true;
|
||||||
$question->formoptions->movecontext = false;
|
$question->formoptions->movecontext = false;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +192,9 @@ if ($cm !== null){
|
||||||
} else {
|
} else {
|
||||||
$toform->courseid = $COURSE->id;
|
$toform->courseid = $COURSE->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$toform->inpopup = $inpopup;
|
$toform->inpopup = $inpopup;
|
||||||
|
|
||||||
$mform->set_data($toform);
|
$mform->set_data($toform);
|
||||||
|
|
||||||
if ($mform->is_cancelled()){
|
if ($mform->is_cancelled()){
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<XMLDB PATH="question/type/calculated/db" VERSION="20100208" COMMENT="XMLDB file for Moodle question/type/calculated. This question type also relies on the question_numerical_units table created by the numerical question type, and the tables created by the datasetdependent question type base class."
|
<XMLDB PATH="question/type/calculated/db" VERSION="20100720" COMMENT="XMLDB file for Moodle question/type/calculated. This question type also relies on the question_numerical_units table created by the numerical question type, and the tables created by the datasetdependent question type base class."
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
||||||
>
|
>
|
||||||
|
@ -29,10 +29,13 @@
|
||||||
<FIELD NAME="synchronize" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="question" NEXT="single"/>
|
<FIELD NAME="synchronize" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="question" NEXT="single"/>
|
||||||
<FIELD NAME="single" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="If 0 it multiple response (checkboxes). Otherwise it is radio buttons." PREVIOUS="synchronize" NEXT="shuffleanswers"/>
|
<FIELD NAME="single" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="If 0 it multiple response (checkboxes). Otherwise it is radio buttons." PREVIOUS="synchronize" NEXT="shuffleanswers"/>
|
||||||
<FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Whether the choices can be randomly shuffled." PREVIOUS="single" NEXT="correctfeedback"/>
|
<FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Whether the choices can be randomly shuffled." PREVIOUS="single" NEXT="correctfeedback"/>
|
||||||
<FIELD NAME="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="partiallycorrectfeedback"/>
|
<FIELD NAME="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="correctfeedbackformat"/>
|
||||||
<FIELD NAME="partiallycorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any partially correct response." PREVIOUS="correctfeedback" NEXT="incorrectfeedback"/>
|
<FIELD NAME="correctfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="correctfeedback" NEXT="partiallycorrectfeedback"/>
|
||||||
<FIELD NAME="incorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="partiallycorrectfeedback" NEXT="answernumbering"/>
|
<FIELD NAME="partiallycorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any partially correct response." PREVIOUS="correctfeedbackformat" NEXT="partiallycorrectfeedbackformat"/>
|
||||||
<FIELD NAME="answernumbering" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="abc" SEQUENCE="false" COMMENT="Indicates how and whether the choices should be numbered." PREVIOUS="incorrectfeedback"/>
|
<FIELD NAME="partiallycorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="partiallycorrectfeedback" NEXT="incorrectfeedback"/>
|
||||||
|
<FIELD NAME="incorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="partiallycorrectfeedbackformat" NEXT="incorrectfeedbackformat"/>
|
||||||
|
<FIELD NAME="incorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="incorrectfeedback" NEXT="answernumbering"/>
|
||||||
|
<FIELD NAME="answernumbering" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="abc" SEQUENCE="false" COMMENT="Indicates how and whether the choices should be numbered." PREVIOUS="incorrectfeedbackformat"/>
|
||||||
</FIELDS>
|
</FIELDS>
|
||||||
<KEYS>
|
<KEYS>
|
||||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
||||||
|
|
|
@ -138,6 +138,62 @@ function xmldb_qtype_calculated_upgrade($oldversion) {
|
||||||
upgrade_plugin_savepoint(true, 2010020800, 'qtype', 'calculated');
|
upgrade_plugin_savepoint(true, 2010020800, 'qtype', 'calculated');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($oldversion < 2010020801) {
|
||||||
|
|
||||||
|
// Define field correctfeedbackformat to be added to question_calculated_options
|
||||||
|
$table = new xmldb_table('question_calculated_options');
|
||||||
|
$field = new xmldb_field('correctfeedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'correctfeedback');
|
||||||
|
|
||||||
|
// Conditionally launch add field correctfeedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define field partiallycorrectfeedbackformat to be added to question_calculated_options
|
||||||
|
$field = new xmldb_field('partiallycorrectfeedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'partiallycorrectfeedback');
|
||||||
|
|
||||||
|
// Conditionally launch add field partiallycorrectfeedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define field incorrectfeedbackformat to be added to question_calculated_options
|
||||||
|
$field = new xmldb_field('incorrectfeedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'incorrectfeedback');
|
||||||
|
|
||||||
|
// Conditionally launch add field incorrectfeedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix fieldformat
|
||||||
|
$rs = $DB->get_recordset('question_calculated_options');
|
||||||
|
foreach ($rs as $record) {
|
||||||
|
if ($CFG->texteditors !== 'textarea') {
|
||||||
|
if (!empty($record->correctfeedback)) {
|
||||||
|
$record->correctfeedback = text_to_html($record->correctfeedback);
|
||||||
|
}
|
||||||
|
$record->correctfeedbackformat = FORMAT_HTML;
|
||||||
|
if (!empty($record->partiallycorrectfeedback)) {
|
||||||
|
$record->partiallycorrectfeedback = text_to_html($record->partiallycorrectfeedback);
|
||||||
|
}
|
||||||
|
$record->partiallycorrectfeedbackformat = FORMAT_HTML;
|
||||||
|
if (!empty($record->incorrectfeedback)) {
|
||||||
|
$record->incorrectfeedback = text_to_html($record->incorrectfeedback);
|
||||||
|
}
|
||||||
|
$record->incorrectfeedbackformat = FORMAT_HTML;
|
||||||
|
} else {
|
||||||
|
$record->correctfeedbackformat = FORMAT_MOODLE;
|
||||||
|
$record->partiallycorrectfeedbackformat = FORMAT_MOODLE;
|
||||||
|
$record->incorrectfeedbackformat = FORMAT_MOODLE;
|
||||||
|
}
|
||||||
|
$DB->update_record('question_calculated_options', $record);
|
||||||
|
}
|
||||||
|
$rs->close();
|
||||||
|
|
||||||
|
// calculated savepoint reached
|
||||||
|
upgrade_plugin_savepoint(true, 2010020801, 'qtype', 'calculated');
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the calculated question type.
|
* Defines the editing form for the calculated question type.
|
||||||
*
|
*
|
||||||
|
@ -19,12 +35,12 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
* @var question_calculated_qtype
|
* @var question_calculated_qtype
|
||||||
*/
|
*/
|
||||||
public $qtypeobj;
|
public $qtypeobj;
|
||||||
public $questiondisplay ;
|
public $questiondisplay;
|
||||||
public $activecategory ;
|
public $activecategory;
|
||||||
public $categorychanged = false ;
|
public $categorychanged = false;
|
||||||
public $initialname = '';
|
public $initialname = '';
|
||||||
public $reload = false ;
|
public $reload = false;
|
||||||
|
|
||||||
function question_edit_calculated_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
function question_edit_calculated_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
||||||
global $QTYPES, $SESSION, $CFG, $DB;
|
global $QTYPES, $SESSION, $CFG, $DB;
|
||||||
$this->question = $question;
|
$this->question = $question;
|
||||||
|
@ -42,20 +58,20 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
$regs= array();
|
$regs= array();
|
||||||
if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
|
if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
|
||||||
$question->name = str_replace($regs[0], '', $question->name);
|
$question->name = str_replace($regs[0], '', $question->name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
}
|
}
|
||||||
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
||||||
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
||||||
$repeated = array();
|
$repeated = array();
|
||||||
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
||||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
||||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
$repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
|
||||||
array('course' => $this->coursefilesid));
|
|
||||||
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
||||||
$repeatedoptions['fraction']['default'] = 0;
|
$repeatedoptions['fraction']['default'] = 0;
|
||||||
$answersoption = 'answers';
|
$answersoption = 'answers';
|
||||||
|
@ -63,8 +79,8 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
$mform->setType('answer', PARAM_NOTAGS);
|
$mform->setType('answer', PARAM_NOTAGS);
|
||||||
|
|
||||||
$addrepeated = array();
|
$addrepeated = array();
|
||||||
$addrepeated[] =& $mform->createElement('text', 'tolerance', get_string('tolerance', 'qtype_calculated'));
|
$addrepeated[] =& $mform->createElement('text', 'tolerance', get_string('tolerance', 'qtype_calculated'));
|
||||||
$addrepeated[] =& $mform->createElement('select', 'tolerancetype', get_string('tolerancetype', 'quiz'), $this->qtypeobj->tolerance_types());
|
$addrepeated[] =& $mform->createElement('select', 'tolerancetype', get_string('tolerancetype', 'quiz'), $this->qtypeobj->tolerance_types());
|
||||||
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
|
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
|
||||||
$repeatedoptions['tolerance']['default'] = 0.01;
|
$repeatedoptions['tolerance']['default'] = 0.01;
|
||||||
|
|
||||||
|
@ -74,7 +90,7 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
$answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
|
$answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
|
||||||
$addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
|
$addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
|
||||||
array_splice($repeated, 3, 0, $addrepeated);
|
array_splice($repeated, 3, 0, $addrepeated);
|
||||||
$repeated[1]->setLabel(get_string('correctanswerformula', 'quiz').'=');
|
$repeated[1]->setLabel(get_string('correctanswerformula', 'quiz').'=');
|
||||||
|
|
||||||
return $repeated;
|
return $repeated;
|
||||||
}
|
}
|
||||||
|
@ -87,8 +103,8 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
function definition_inner(&$mform) {
|
function definition_inner(&$mform) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
$this->qtypeobj =& $QTYPES[$this->qtype()];
|
$this->qtypeobj =& $QTYPES[$this->qtype()];
|
||||||
// echo code left for testing period
|
// echo code left for testing period
|
||||||
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
||||||
$label = get_string('sharedwildcards', 'qtype_calculated');
|
$label = get_string('sharedwildcards', 'qtype_calculated');
|
||||||
$mform->addElement('hidden', 'initialcategory', 1);
|
$mform->addElement('hidden', 'initialcategory', 1);
|
||||||
$mform->addElement('hidden', 'reload', 1);
|
$mform->addElement('hidden', 'reload', 1);
|
||||||
|
@ -100,43 +116,42 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
};
|
};
|
||||||
$addfieldsname='updatecategory';
|
$addfieldsname='updatecategory';
|
||||||
$addstring=get_string("updatecategory", "qtype_calculated");
|
$addstring=get_string("updatecategory", "qtype_calculated");
|
||||||
$mform->registerNoSubmitButton($addfieldsname);
|
$mform->registerNoSubmitButton($addfieldsname);
|
||||||
|
|
||||||
$mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
$mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
||||||
$mform->registerNoSubmitButton('createoptionbutton');
|
$mform->registerNoSubmitButton('createoptionbutton');
|
||||||
|
|
||||||
//editing as regular
|
//editing as regular
|
||||||
$mform->setType('single', PARAM_INT);
|
$mform->setType('single', PARAM_INT);
|
||||||
|
|
||||||
$mform->addElement('hidden','shuffleanswers', '1');
|
$mform->addElement('hidden','shuffleanswers', '1');
|
||||||
$mform->setType('shuffleanswers', PARAM_INT);
|
$mform->setType('shuffleanswers', PARAM_INT);
|
||||||
$mform->addElement('hidden','answernumbering', 'abc');
|
$mform->addElement('hidden','answernumbering', 'abc');
|
||||||
$mform->setType('answernumbering', PARAM_SAFEDIR);
|
$mform->setType('answernumbering', PARAM_SAFEDIR);
|
||||||
|
|
||||||
$creategrades = get_grade_options();
|
$creategrades = get_grade_options();
|
||||||
|
|
||||||
$this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
|
$this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'), $creategrades->gradeoptions, 1, 1);
|
||||||
$creategrades->gradeoptions, 1, 1);
|
|
||||||
|
|
||||||
|
|
||||||
$repeated = array();
|
$repeated = array();
|
||||||
|
|
||||||
$QTYPES['numerical']->add_units_options($mform,$this);
|
$QTYPES['numerical']->add_units_options($mform,$this);
|
||||||
$QTYPES['numerical']->add_units_elements($mform,$this);
|
$QTYPES['numerical']->add_units_elements($mform,$this);
|
||||||
|
|
||||||
|
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
||||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||||
$mform->addElement('hidden', $feedbackname);
|
$mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_calculated'), null, $this->editoroptions);
|
||||||
$mform->setType($feedbackname, PARAM_RAW);
|
$mform->setType($feedbackname, PARAM_RAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
//hidden elements
|
//hidden elements
|
||||||
$mform->addElement('hidden', 'synchronize', '');
|
$mform->addElement('hidden', 'synchronize', '');
|
||||||
$mform->setType('synchronize', PARAM_INT);
|
$mform->setType('synchronize', PARAM_INT);
|
||||||
$mform->addElement('hidden', 'wizard', 'datasetdefinitions');
|
$mform->addElement('hidden', 'wizard', 'datasetdefinitions');
|
||||||
$mform->setType('wizard', PARAM_ALPHA);
|
$mform->setType('wizard', PARAM_ALPHA);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
|
|
||||||
$default_values = array();
|
$default_values = array();
|
||||||
|
@ -145,26 +160,58 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
if (count($answers)) {
|
if (count($answers)) {
|
||||||
$key = 0;
|
$key = 0;
|
||||||
foreach ($answers as $answer){
|
foreach ($answers as $answer){
|
||||||
|
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||||
$default_values['answer['.$key.']'] = $answer->answer;
|
$default_values['answer['.$key.']'] = $answer->answer;
|
||||||
$default_values['fraction['.$key.']'] = $answer->fraction;
|
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||||
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
||||||
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
||||||
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
||||||
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
||||||
$default_values['feedback['.$key.']'] = $answer->feedback;
|
$default_values['feedback['.$key.']'] = array();
|
||||||
|
$default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'question', // component
|
||||||
|
'answerfeedback', // filarea
|
||||||
|
!empty($answer->id)?(int)$answer->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$answer->feedback // text
|
||||||
|
);
|
||||||
|
$default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
|
||||||
|
$default_values['feedback['.$key.']']['itemid'] = $draftid;
|
||||||
$key++;
|
$key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$default_values['synchronize'] = $question->options->synchronize ;
|
$default_values['synchronize'] = $question->options->synchronize ;
|
||||||
$QTYPES['numerical']->set_numerical_unit_data($question,$default_values);
|
// set unit data, prepare files in instruction area
|
||||||
|
$QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
|
||||||
}
|
}
|
||||||
if (isset($question->options->single)){
|
if (isset($question->options->single)){
|
||||||
$default_values['single'] = $question->options->single;
|
$default_values['single'] = $question->options->single;
|
||||||
$default_values['answernumbering'] = $question->options->answernumbering;
|
$default_values['answernumbering'] = $question->options->answernumbering;
|
||||||
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
||||||
$default_values['correctfeedback'] = $question->options->correctfeedback;
|
//$default_values['correctfeedback'] = $question->options->correctfeedback;
|
||||||
$default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback;
|
//$default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback;
|
||||||
$default_values['incorrectfeedback'] = $question->options->incorrectfeedback;
|
//$default_values['incorrectfeedback'] = $question->options->incorrectfeedback;
|
||||||
|
// prepare feedback editor to display files in draft area
|
||||||
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||||
|
$draftid = file_get_submitted_draft_itemid($feedbackname);
|
||||||
|
$text = $question->options->$feedbackname;
|
||||||
|
$feedbackformat = $feedbackname . 'format';
|
||||||
|
$format = $question->options->$feedbackformat;
|
||||||
|
$default_values[$feedbackname] = array();
|
||||||
|
$default_values[$feedbackname]['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'qtype_calculated', // component
|
||||||
|
$feedbackname, // filarea
|
||||||
|
!empty($question->id)?(int)$question->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$text // text
|
||||||
|
);
|
||||||
|
$default_values[$feedbackname]['format'] = $format;
|
||||||
|
$default_values[$feedbackname]['itemid'] = $draftid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated');
|
$default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated');
|
||||||
$default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated');
|
$default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated');
|
||||||
|
@ -173,16 +220,16 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
update category button. The value can be obtain by
|
update category button. The value can be obtain by
|
||||||
$qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0];
|
$qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0];
|
||||||
but is coded using existing functions
|
but is coded using existing functions
|
||||||
*/
|
*/
|
||||||
$qu = new stdClass;
|
$qu = new stdClass;
|
||||||
$el = new stdClass;
|
$el = new stdClass;
|
||||||
/* no need to call elementExists() here */
|
/* no need to call elementExists() here */
|
||||||
if ($this->_form->elementExists('category')){
|
if ($this->_form->elementExists('category')){
|
||||||
$el=$this->_form->getElement('category');
|
$el=$this->_form->getElement('category');
|
||||||
} else {
|
} else {
|
||||||
$el=$this->_form->getElement('categorymoveto');
|
$el=$this->_form->getElement('categorymoveto');
|
||||||
}
|
}
|
||||||
if($value =$el->getSelected()) {
|
if($value =$el->getSelected()) {
|
||||||
$qu->category =$value[0];
|
$qu->category =$value[0];
|
||||||
}else {
|
}else {
|
||||||
$qu->category=$question->category;// on load $question->category is set by question.php
|
$qu->category=$question->category;// on load $question->category is set by question.php
|
||||||
|
@ -191,7 +238,7 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
$this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
|
$this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
|
||||||
$question = (object)((array)$question + $default_values);
|
$question = (object)((array)$question + $default_values);
|
||||||
|
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
|
@ -200,21 +247,21 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
|
|
||||||
function validation($data, $files) {
|
function validation($data, $files) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
// echo code left for testing period
|
// echo code left for testing period
|
||||||
|
|
||||||
// echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
|
// echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
|
||||||
// echo "<p>data <pre>";print_r($data);echo "</pre></p>";
|
// echo "<p>data <pre>";print_r($data);echo "</pre></p>";
|
||||||
|
|
||||||
$errors = parent::validation($data, $files);
|
$errors = parent::validation($data, $files);
|
||||||
//verifying for errors in {=...} in question text;
|
//verifying for errors in {=...} in question text;
|
||||||
$qtext = "";
|
$qtext = "";
|
||||||
$qtextremaining = $data['questiontext'] ;
|
$qtextremaining = $data['questiontext']['text'];
|
||||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||||
foreach ($possibledatasets as $name => $value) {
|
foreach ($possibledatasets as $name => $value) {
|
||||||
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
||||||
}
|
}
|
||||||
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
||||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||||
$qtext =$qtext.$qtextsplits[0];
|
$qtext =$qtext.$qtextsplits[0];
|
||||||
$qtextremaining = $qtextsplits[1];
|
$qtextremaining = $qtextsplits[1];
|
||||||
|
@ -229,45 +276,45 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
$answers = $data['answer'];
|
$answers = $data['answer'];
|
||||||
$answercount = 0;
|
$answercount = 0;
|
||||||
$maxgrade = false;
|
$maxgrade = false;
|
||||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||||
$mandatorydatasets = array();
|
$mandatorydatasets = array();
|
||||||
foreach ($answers as $key => $answer){
|
foreach ($answers as $key => $answer){
|
||||||
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
||||||
}
|
}
|
||||||
if ( count($mandatorydatasets )==0){
|
if ( count($mandatorydatasets )==0){
|
||||||
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||||
foreach ($answers as $key => $answer){
|
foreach ($answers as $key => $answer){
|
||||||
$errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
|
$errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// regular calculated
|
// regular calculated
|
||||||
foreach ($answers as $key => $answer){
|
foreach ($answers as $key => $answer){
|
||||||
//check no of choices
|
//check no of choices
|
||||||
// the * for everykind of answer not actually implemented
|
// the * for everykind of answer not actually implemented
|
||||||
$trimmedanswer = trim($answer);
|
$trimmedanswer = trim($answer);
|
||||||
if (($trimmedanswer!='')||$answercount==0){
|
if (($trimmedanswer!='')||$answercount==0){
|
||||||
$eqerror = qtype_calculated_find_formula_errors($trimmedanswer);
|
$eqerror = qtype_calculated_find_formula_errors($trimmedanswer);
|
||||||
if (FALSE !== $eqerror){
|
if (FALSE !== $eqerror){
|
||||||
$errors['answer['.$key.']'] = $eqerror;
|
$errors['answer['.$key.']'] = $eqerror;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ($trimmedanswer!=''){
|
}
|
||||||
if ('2' == $data['correctanswerformat'][$key]
|
if ($trimmedanswer!=''){
|
||||||
&& '0' == $data['correctanswerlength'][$key]) {
|
if ('2' == $data['correctanswerformat'][$key]
|
||||||
|
&& '0' == $data['correctanswerlength'][$key]) {
|
||||||
$errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
|
$errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
|
||||||
}
|
}
|
||||||
if (!is_numeric($data['tolerance'][$key])){
|
if (!is_numeric($data['tolerance'][$key])){
|
||||||
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
|
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
|
||||||
}
|
}
|
||||||
if ($data['fraction'][$key] == 1) {
|
if ($data['fraction'][$key] == 1) {
|
||||||
$maxgrade = true;
|
$maxgrade = true;
|
||||||
}
|
|
||||||
|
|
||||||
$answercount++;
|
|
||||||
}
|
}
|
||||||
//check grades
|
|
||||||
|
|
||||||
//TODO how should grade checking work here??
|
$answercount++;
|
||||||
|
}
|
||||||
|
//check grades
|
||||||
|
|
||||||
|
//TODO how should grade checking work here??
|
||||||
/*if ($answer != '') {
|
/*if ($answer != '') {
|
||||||
if ($data['fraction'][$key] > 0) {
|
if ($data['fraction'][$key] > 0) {
|
||||||
$totalfraction += $data['fraction'][$key];
|
$totalfraction += $data['fraction'][$key];
|
||||||
|
@ -276,10 +323,10 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
$maxfraction = $data['fraction'][$key];
|
$maxfraction = $data['fraction'][$key];
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//grade checking :
|
//grade checking :
|
||||||
/// Perform sanity checks on fractional grades
|
/// Perform sanity checks on fractional grades
|
||||||
/*if ( ) {
|
/*if ( ) {
|
||||||
if ($maxfraction != 1) {
|
if ($maxfraction != 1) {
|
||||||
$maxfraction = $maxfraction * 100;
|
$maxfraction = $maxfraction * 100;
|
||||||
|
@ -292,7 +339,7 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
$errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
|
$errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$units = $data['unit'];
|
$units = $data['unit'];
|
||||||
if (count($units)) {
|
if (count($units)) {
|
||||||
foreach ($units as $key => $unit){
|
foreach ($units as $key => $unit){
|
||||||
if (is_numeric($unit)){
|
if (is_numeric($unit)){
|
||||||
|
@ -309,18 +356,17 @@ class question_edit_calculated_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
$QTYPES['numerical']->validate_numerical_options($data, $errors) ;
|
$QTYPES['numerical']->validate_numerical_options($data, $errors) ;
|
||||||
if ($answercount==0){
|
if ($answercount==0){
|
||||||
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
||||||
}
|
}
|
||||||
if ($maxgrade == false) {
|
if ($maxgrade == false) {
|
||||||
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ $string['choosedatasetproperties'] = 'Choose wildcards dataset properties';
|
||||||
$string['choosedatasetproperties_help'] = 'A dataset is a set of values inserted in place of a wildcard. You can create a private dataset for a specific question, or a shared dataset that can be used for other calculated questions within the category.';
|
$string['choosedatasetproperties_help'] = 'A dataset is a set of values inserted in place of a wildcard. You can create a private dataset for a specific question, or a shared dataset that can be used for other calculated questions within the category.';
|
||||||
$string['correctanswershows'] = 'Correct answer shows';
|
$string['correctanswershows'] = 'Correct answer shows';
|
||||||
$string['correctanswershowsformat'] = 'Format';
|
$string['correctanswershowsformat'] = 'Format';
|
||||||
|
$string['correctfeedback'] = 'For any correct response';
|
||||||
$string['dataitemdefined']='with {$a} numerical values already defined is available';
|
$string['dataitemdefined']='with {$a} numerical values already defined is available';
|
||||||
$string['datasetrole']= ' The wild cards <strong>{x..}</strong> will be substituted by a numerical value from their dataset';
|
$string['datasetrole']= ' The wild cards <strong>{x..}</strong> will be substituted by a numerical value from their dataset';
|
||||||
$string['deleteitem'] = 'Delete Item';
|
$string['deleteitem'] = 'Delete Item';
|
||||||
|
@ -61,6 +62,7 @@ $string['forceregenerationall'] = 'forceregeneration of all wildcards';
|
||||||
$string['forceregenerationshared'] = 'forceregeneration of only non-shared wildcards';
|
$string['forceregenerationshared'] = 'forceregeneration of only non-shared wildcards';
|
||||||
$string['getnextnow'] = 'Get New \'Item to Add\' Now';
|
$string['getnextnow'] = 'Get New \'Item to Add\' Now';
|
||||||
$string['hexanotallowed'] = 'Dataset <strong>{$a->name}</strong> hexadecimal format value $a->value is not allowed' ;
|
$string['hexanotallowed'] = 'Dataset <strong>{$a->name}</strong> hexadecimal format value $a->value is not allowed' ;
|
||||||
|
$string['incorrectfeedback'] = 'For any incorrect response';
|
||||||
$string['item(s)'] = 'item(s)';
|
$string['item(s)'] = 'item(s)';
|
||||||
$string['itemno'] = 'Item {$a}';
|
$string['itemno'] = 'Item {$a}';
|
||||||
$string['itemscount']='Items<br />Count';
|
$string['itemscount']='Items<br />Count';
|
||||||
|
@ -91,8 +93,9 @@ $string['nocommaallowed'] = 'The , cannot be used, use . as in 0.013 or 1.3e-2'
|
||||||
$string['nodataset'] = 'nothing - it is not a wild card';
|
$string['nodataset'] = 'nothing - it is not a wild card';
|
||||||
$string['nosharedwildcard'] = 'No shared wild card in this category';
|
$string['nosharedwildcard'] = 'No shared wild card in this category';
|
||||||
$string['notvalidnumber'] = 'Wild card value is not a valid number ' ;
|
$string['notvalidnumber'] = 'Wild card value is not a valid number ' ;
|
||||||
$string['oneanswertrueansweroutsidelimits'] = 'At least one correct answer outside the true value limits.<br />Modify the answers tolerance settings available as Advanced parameters';
|
$string['oneanswertrueansweroutsidelimits'] = 'At least one correct answer outside the true value limits.<br />Modify the answers tolerance settings available as Advanced parameters';
|
||||||
$string['param'] = 'Param {<strong>{$a}</strong>}';
|
$string['param'] = 'Param {<strong>{$a}</strong>}';
|
||||||
|
$string['partiallycorrectfeedback'] = 'For any partially correct response';
|
||||||
$string['possiblehdr'] = 'Possible wild cards present only in the question text';
|
$string['possiblehdr'] = 'Possible wild cards present only in the question text';
|
||||||
$string['questiondatasets'] = 'Question datasets';
|
$string['questiondatasets'] = 'Question datasets';
|
||||||
$string['questiondatasets_help'] = 'Question datasets of wild cards that will be used in each individual question';
|
$string['questiondatasets_help'] = 'Question datasets of wild cards that will be used in each individual question';
|
||||||
|
|
31
question/type/calculated/lib.php
Normal file
31
question/type/calculated/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_calculated_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_calculated', $filearea, $args, $forcedownload);
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
||||||
<?PHP
|
<?PHP
|
||||||
|
|
||||||
$plugin->version = 2010020800;
|
$plugin->version = 2010020801;
|
||||||
$plugin->requires = 2007101000;
|
$plugin->requires = 2007101000;
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
*
|
*
|
||||||
* @var question_calculatedmulti_qtype
|
* @var question_calculatedmulti_qtype
|
||||||
*/
|
*/
|
||||||
var $qtypeobj;
|
public $qtypeobj;
|
||||||
public $questiondisplay ;
|
public $questiondisplay ;
|
||||||
public $initialname = '';
|
public $initialname = '';
|
||||||
public $reload = false ;
|
public $reload = false ;
|
||||||
function question_edit_calculatedmulti_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
function question_edit_calculatedmulti_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true) {
|
||||||
global $QTYPES, $SESSION, $CFG, $DB;
|
global $QTYPES, $SESSION, $CFG, $DB;
|
||||||
$this->question = $question;
|
$this->question = $question;
|
||||||
$this->qtypeobj =& $QTYPES[$this->question->qtype];
|
$this->qtypeobj =& $QTYPES[$this->question->qtype];
|
||||||
|
@ -38,22 +38,21 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
$regs= array();
|
$regs= array();
|
||||||
if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
|
if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
|
||||||
$question->name = str_replace($regs[0], '', $question->name);
|
$question->name = str_replace($regs[0], '', $question->name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
}
|
}
|
||||||
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
||||||
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
||||||
$repeated = array();
|
$repeated = array();
|
||||||
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
||||||
// if ($this->editasmultichoice == 1){
|
// if ($this->editasmultichoice == 1){
|
||||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
||||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
$repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
|
||||||
array('course' => $this->coursefilesid));
|
|
||||||
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
||||||
$repeatedoptions['fraction']['default'] = 0;
|
$repeatedoptions['fraction']['default'] = 0;
|
||||||
$answersoption = 'answers';
|
$answersoption = 'answers';
|
||||||
|
@ -61,8 +60,8 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
$mform->setType('answer', PARAM_NOTAGS);
|
$mform->setType('answer', PARAM_NOTAGS);
|
||||||
|
|
||||||
$addrepeated = array();
|
$addrepeated = array();
|
||||||
$addrepeated[] =& $mform->createElement('hidden', 'tolerance');
|
$addrepeated[] =& $mform->createElement('hidden', 'tolerance');
|
||||||
$addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
|
$addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
|
||||||
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
|
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
|
||||||
$repeatedoptions['tolerance']['default'] = 0.01;
|
$repeatedoptions['tolerance']['default'] = 0.01;
|
||||||
|
|
||||||
|
@ -72,7 +71,7 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
$answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
|
$answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
|
||||||
$addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
|
$addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
|
||||||
array_splice($repeated, 3, 0, $addrepeated);
|
array_splice($repeated, 3, 0, $addrepeated);
|
||||||
$repeated[1]->setLabel('...<strong>{={x}+..}</strong>...');
|
$repeated[1]->setLabel('...<strong>{={x}+..}</strong>...');
|
||||||
|
|
||||||
return $repeated;
|
return $repeated;
|
||||||
}
|
}
|
||||||
|
@ -85,79 +84,78 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
function definition_inner(&$mform) {
|
function definition_inner(&$mform) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
$this->qtypeobj =& $QTYPES[$this->qtype()];
|
$this->qtypeobj =& $QTYPES[$this->qtype()];
|
||||||
// echo code left for testing period
|
// echo code left for testing period
|
||||||
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
||||||
$label = get_string("sharedwildcards", "qtype_calculated");
|
$label = get_string("sharedwildcards", "qtype_calculated");
|
||||||
$mform->addElement('hidden', 'initialcategory', 1);
|
$mform->addElement('hidden', 'initialcategory', 1);
|
||||||
$mform->addElement('hidden', 'reload', 1);
|
$mform->addElement('hidden', 'reload', 1);
|
||||||
$mform->setType('initialcategory', PARAM_INT);
|
$mform->setType('initialcategory', PARAM_INT);
|
||||||
|
|
||||||
// $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
|
// $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
|
||||||
$html2 ="";
|
$html2 ="";
|
||||||
$mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name');
|
$mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name');
|
||||||
if(isset($this->question->id )){
|
if(isset($this->question->id )){
|
||||||
$mform->insertElementBefore($mform->createElement('static','initialname',get_string('questionstoredname','qtype_calculated'),$this->initialname),'name');
|
$mform->insertElementBefore($mform->createElement('static','initialname',get_string('questionstoredname','qtype_calculated'),$this->initialname),'name');
|
||||||
};
|
};
|
||||||
$addfieldsname='updatecategory';
|
$addfieldsname='updatecategory';
|
||||||
$addstring=get_string("updatecategory", "qtype_calculated");
|
$addstring=get_string("updatecategory", "qtype_calculated");
|
||||||
$mform->registerNoSubmitButton($addfieldsname);
|
$mform->registerNoSubmitButton($addfieldsname);
|
||||||
$this->editasmultichoice = 1 ;
|
$this->editasmultichoice = 1 ;
|
||||||
|
|
||||||
|
|
||||||
$mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
$mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
||||||
$mform->registerNoSubmitButton('createoptionbutton');
|
$mform->registerNoSubmitButton('createoptionbutton');
|
||||||
$mform->addElement('hidden', 'multichoice',$this->editasmultichoice);
|
$mform->addElement('hidden', 'multichoice',$this->editasmultichoice);
|
||||||
$mform->setType('multichoice', PARAM_INT);
|
$mform->setType('multichoice', PARAM_INT);
|
||||||
|
|
||||||
|
|
||||||
// $mform->addElement('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated'));
|
|
||||||
$menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice'));
|
// $mform->addElement('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated'));
|
||||||
$mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu);
|
$menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice'));
|
||||||
$mform->setDefault('single', 1);
|
$mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu);
|
||||||
|
$mform->setDefault('single', 1);
|
||||||
$mform->addElement('advcheckbox', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'), null, null, array(0,1));
|
|
||||||
$mform->addHelpButton('shuffleanswers', 'shuffleanswers', 'qtype_multichoice');
|
$mform->addElement('advcheckbox', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'), null, null, array(0,1));
|
||||||
$mform->setDefault('shuffleanswers', 1);
|
$mform->setHelpButton('shuffleanswers', array('multichoiceshuffle', get_string('shuffleanswers','qtype_multichoice'), 'qtype_multichoice'));
|
||||||
|
$mform->setDefault('shuffleanswers', 1);
|
||||||
$numberingoptions = $QTYPES['multichoice']->get_numbering_styles();
|
|
||||||
$menu = array();
|
$numberingoptions = $QTYPES['multichoice']->get_numbering_styles();
|
||||||
foreach ($numberingoptions as $numberingoption) {
|
$menu = array();
|
||||||
$menu[$numberingoption] = get_string('answernumbering' . $numberingoption, 'qtype_multichoice');
|
foreach ($numberingoptions as $numberingoption) {
|
||||||
}
|
$menu[$numberingoption] = get_string('answernumbering' . $numberingoption, 'qtype_multichoice');
|
||||||
$mform->addElement('select', 'answernumbering', get_string('answernumbering', 'qtype_multichoice'), $menu);
|
}
|
||||||
$mform->setDefault('answernumbering', 'abc');
|
$mform->addElement('select', 'answernumbering', get_string('answernumbering', 'qtype_multichoice'), $menu);
|
||||||
|
$mform->setDefault('answernumbering', 'abc');
|
||||||
|
|
||||||
$creategrades = get_grade_options();
|
$creategrades = get_grade_options();
|
||||||
$this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'),
|
$this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'),
|
||||||
$creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START));
|
$creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START));
|
||||||
|
|
||||||
|
|
||||||
$repeated = array();
|
$repeated = array();
|
||||||
// if ($this->editasmultichoice == 1){
|
// if ($this->editasmultichoice == 1){
|
||||||
$nounits = optional_param('nounits', 1, PARAM_INT);
|
$nounits = optional_param('nounits', 1, PARAM_INT);
|
||||||
$mform->addElement('hidden', 'nounits', $nounits);
|
$mform->addElement('hidden', 'nounits', $nounits);
|
||||||
$mform->setType('nounits', PARAM_INT);
|
$mform->setType('nounits', PARAM_INT);
|
||||||
$mform->setConstants(array('nounits'=>$nounits));
|
$mform->setConstants(array('nounits'=>$nounits));
|
||||||
for ($i=0; $i< $nounits; $i++) {
|
for ($i=0; $i< $nounits; $i++) {
|
||||||
$mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS));
|
$mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS));
|
||||||
$mform->setType('unit'."[$i]", PARAM_NOTAGS);
|
$mform->setType('unit'."[$i]", PARAM_NOTAGS);
|
||||||
$mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER));
|
$mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER));
|
||||||
$mform->setType('multiplier'."[$i]", PARAM_NUMBER);
|
$mform->setType('multiplier'."[$i]", PARAM_NUMBER);
|
||||||
}
|
}
|
||||||
$mform->addElement('hidden','unitgradingtype',optional_param('unitgradingtype', '', PARAM_INT)) ;
|
$mform->addElement('hidden','unitgradingtype',optional_param('unitgradingtype', '', PARAM_INT)) ;
|
||||||
$mform->addElement('hidden','unitpenalty',optional_param('unitpenalty', '', PARAM_NUMBER)) ;
|
$mform->addElement('hidden','unitpenalty',optional_param('unitpenalty', '', PARAM_NUMBER)) ;
|
||||||
$mform->addElement('hidden','showunits',optional_param('showunits', '', PARAM_INT)) ;
|
$mform->addElement('hidden','showunits',optional_param('showunits', '', PARAM_INT)) ;
|
||||||
$mform->addElement('hidden','unitsleft',optional_param('unitsleft', '', PARAM_INT)) ;
|
$mform->addElement('hidden','unitsleft',optional_param('unitsleft', '', PARAM_INT)) ;
|
||||||
$mform->addElement('hidden','instructions',optional_param('instructions', '', PARAM_RAW)) ;
|
$mform->addElement('hidden','instructions',optional_param('instructions', '', PARAM_RAW)) ;
|
||||||
|
|
||||||
$mform->setType('addunits','hidden');
|
$mform->setType('addunits','hidden');
|
||||||
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
||||||
|
|
||||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||||
$mform->addElement('htmleditor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'),
|
$mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'), null, $this->editoroptions);
|
||||||
array('course' => $this->coursefilesid));
|
$mform->setType($feedbackname, PARAM_RAW);
|
||||||
$mform->setType($feedbackname, PARAM_RAW);
|
}
|
||||||
}
|
|
||||||
//hidden elements
|
//hidden elements
|
||||||
$mform->addElement('hidden', 'synchronize', '');
|
$mform->addElement('hidden', 'synchronize', '');
|
||||||
$mform->setType('synchronize', PARAM_INT);
|
$mform->setType('synchronize', PARAM_INT);
|
||||||
|
@ -168,40 +166,43 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
$mform->addElement('hidden', 'wizard', 'datasetdefinitions');
|
$mform->addElement('hidden', 'wizard', 'datasetdefinitions');
|
||||||
$mform->setType('wizard', PARAM_ALPHA);
|
$mform->setType('wizard', PARAM_ALPHA);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
$default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ;
|
$default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ;
|
||||||
if (isset($question->options)){
|
if (isset($question->options)){
|
||||||
$answers = $question->options->answers;
|
$answers = $question->options->answers;
|
||||||
if (count($answers)) {
|
if (count($answers)) {
|
||||||
$key = 0;
|
$key = 0;
|
||||||
foreach ($answers as $answer){
|
foreach ($answers as $answer){
|
||||||
|
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||||
$default_values['answer['.$key.']'] = $answer->answer;
|
$default_values['answer['.$key.']'] = $answer->answer;
|
||||||
$default_values['fraction['.$key.']'] = $answer->fraction;
|
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||||
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
||||||
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
||||||
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
||||||
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
||||||
$default_values['feedback['.$key.']'] = $answer->feedback;
|
$default_values['feedback['.$key.']'] = array();
|
||||||
|
// prepare draftarea
|
||||||
|
$default_values['feedback['.$key.']']['text'] = file_prepare_draft_area($draftid, $this->context->id, 'question', 'answerfeedback', empty($answer->id)?null:(int)$answer->id, null, $answer->feedback);
|
||||||
|
$default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
|
||||||
|
$default_values['feedback['.$key.']']['itemid'] = $draftid;
|
||||||
$key++;
|
$key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// $default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
// $default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
||||||
// $default_values['unitpenalty'] = $question->options->unitpenalty ;
|
// $default_values['unitpenalty'] = $question->options->unitpenalty ;
|
||||||
// $default_values['showunits'] = $question->options->showunits ;
|
// $default_values['showunits'] = $question->options->showunits ;
|
||||||
// $default_values['unitsleft'] = $question->options->unitsleft ;
|
// $default_values['unitsleft'] = $question->options->unitsleft ;
|
||||||
// $default_values['instructions'] = $question->options->instructions ;
|
// $default_values['instructions'] = $question->options->instructions ;
|
||||||
$default_values['synchronize'] = $question->options->synchronize ;
|
$default_values['synchronize'] = $question->options->synchronize ;
|
||||||
|
|
||||||
if (isset($question->options->units)){
|
if (isset($question->options->units)){
|
||||||
$units = array_values($question->options->units);
|
$units = array_values($question->options->units);
|
||||||
// make sure the default unit is at index 0
|
// make sure the default unit is at index 0
|
||||||
usort($units, create_function('$a, $b',
|
usort($units, create_function('$a, $b',
|
||||||
'if (1.0 === (float)$a->multiplier) { return -1; } else '.
|
'if (1.0 === (float)$a->multiplier) { return -1; } else '.
|
||||||
'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
|
'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
|
||||||
if (count($units)) {
|
if (count($units)) {
|
||||||
$key = 0;
|
$key = 0;
|
||||||
foreach ($units as $unit){
|
foreach ($units as $unit){
|
||||||
|
@ -213,30 +214,51 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($question->options->single)){
|
if (isset($question->options->single)){
|
||||||
$default_values['single'] = $question->options->single;
|
$default_values['single'] = $question->options->single;
|
||||||
$default_values['answernumbering'] = $question->options->answernumbering;
|
$default_values['answernumbering'] = $question->options->answernumbering;
|
||||||
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
||||||
$default_values['correctfeedback'] = $question->options->correctfeedback;
|
}
|
||||||
$default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback;
|
|
||||||
$default_values['incorrectfeedback'] = $question->options->incorrectfeedback;
|
|
||||||
}
|
|
||||||
$default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated');
|
$default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated');
|
||||||
$default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated');
|
$default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated');
|
||||||
/* set the wild cards category display given that on loading the category element is
|
|
||||||
unselected when processing this function but have a valid value when processing the
|
// prepare draft files
|
||||||
update category button. The value can be obtain by
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||||
$qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0];
|
if (!isset($question->options->$feedbackname)) {
|
||||||
but is coded using existing functions
|
continue;
|
||||||
*/
|
}
|
||||||
$qu = new stdClass;
|
$text = $question->options->$feedbackname;
|
||||||
$el = new stdClass;
|
$draftid = file_get_submitted_draft_itemid($feedbackname);
|
||||||
/* no need to call elementExists() here */
|
$feedbackformat = $feedbackname . 'format';
|
||||||
if ($this->_form->elementExists('category')){
|
$format = $question->options->$feedbackformat;
|
||||||
|
$default_values[$feedbackname] = array();
|
||||||
|
$default_values[$feedbackname]['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'qtype_calculatedmulti', // component
|
||||||
|
$feedbackname, // filarea
|
||||||
|
!empty($question->id)?(int)$question->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$text // text
|
||||||
|
);
|
||||||
|
$default_values[$feedbackname]['format'] = $format;
|
||||||
|
$default_values[$feedbackname]['itemid'] = $draftid;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* set the wild cards category display given that on loading the category element is
|
||||||
|
* unselected when processing this function but have a valid value when processing the
|
||||||
|
* update category button. The value can be obtain by
|
||||||
|
* $qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0];
|
||||||
|
* but is coded using existing functions
|
||||||
|
*/
|
||||||
|
$qu = new stdClass;
|
||||||
|
$el = new stdClass;
|
||||||
|
/* no need to call elementExists() here */
|
||||||
|
if ($this->_form->elementExists('category')){
|
||||||
$el=$this->_form->getElement('category');
|
$el=$this->_form->getElement('category');
|
||||||
} else {
|
} else {
|
||||||
$el=$this->_form->getElement('categorymoveto');
|
$el=$this->_form->getElement('categorymoveto');
|
||||||
}
|
}
|
||||||
if($value =$el->getSelected()) {
|
if($value =$el->getSelected()) {
|
||||||
$qu->category =$value[0];
|
$qu->category =$value[0];
|
||||||
}else {
|
}else {
|
||||||
$qu->category=$question->category;// on load $question->category is set by question.php
|
$qu->category=$question->category;// on load $question->category is set by question.php
|
||||||
|
@ -244,8 +266,7 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
$html2 = $this->qtypeobj->print_dataset_definitions_category($qu);
|
$html2 = $this->qtypeobj->print_dataset_definitions_category($qu);
|
||||||
$this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
|
$this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
|
||||||
$question = (object)((array)$question + $default_values);
|
$question = (object)((array)$question + $default_values);
|
||||||
|
return $question;
|
||||||
parent::set_data($question);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
|
@ -253,21 +274,20 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
|
|
||||||
function validation($data, $files) {
|
function validation($data, $files) {
|
||||||
// echo code left for testing period
|
// echo code left for testing period
|
||||||
|
// echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
|
||||||
// echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
|
// echo "<p>data <pre>";print_r($data);echo "</pre></p>";
|
||||||
// echo "<p>data <pre>";print_r($data);echo "</pre></p>";
|
|
||||||
|
|
||||||
$errors = parent::validation($data, $files);
|
$errors = parent::validation($data, $files);
|
||||||
//verifying for errors in {=...} in question text;
|
//verifying for errors in {=...} in question text;
|
||||||
$qtext = "";
|
$qtext = "";
|
||||||
$qtextremaining = $data['questiontext'] ;
|
$qtextremaining = $data['questiontext']['text'];
|
||||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||||
foreach ($possibledatasets as $name => $value) {
|
foreach ($possibledatasets as $name => $value) {
|
||||||
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
||||||
}
|
}
|
||||||
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
||||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||||
$qtext =$qtext.$qtextsplits[0];
|
$qtext =$qtext.$qtextsplits[0];
|
||||||
$qtextremaining = $qtextsplits[1];
|
$qtextremaining = $qtextsplits[1];
|
||||||
|
@ -282,13 +302,13 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
$answers = $data['answer'];
|
$answers = $data['answer'];
|
||||||
$answercount = 0;
|
$answercount = 0;
|
||||||
$maxgrade = false;
|
$maxgrade = false;
|
||||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||||
$mandatorydatasets = array();
|
$mandatorydatasets = array();
|
||||||
foreach ($answers as $key => $answer){
|
foreach ($answers as $key => $answer){
|
||||||
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
||||||
}
|
}
|
||||||
if ( count($mandatorydatasets )==0){
|
if ( count($mandatorydatasets )==0){
|
||||||
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||||
foreach ($answers as $key => $answer){
|
foreach ($answers as $key => $answer){
|
||||||
$errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
|
$errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||||
}
|
}
|
||||||
|
@ -296,15 +316,15 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
if ($data['multichoice']== 1 ){
|
if ($data['multichoice']== 1 ){
|
||||||
foreach ($answers as $key => $answer){
|
foreach ($answers as $key => $answer){
|
||||||
$trimmedanswer = trim($answer);
|
$trimmedanswer = trim($answer);
|
||||||
if (($trimmedanswer!='')||$answercount==0){
|
if (($trimmedanswer!='')||$answercount==0){
|
||||||
//verifying for errors in {=...} in answer text;
|
//verifying for errors in {=...} in answer text;
|
||||||
$qanswer = "";
|
$qanswer = "";
|
||||||
$qanswerremaining = $trimmedanswer ;
|
$qanswerremaining = $trimmedanswer ;
|
||||||
$possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer);
|
$possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer);
|
||||||
foreach ($possibledatasets as $name => $value) {
|
foreach ($possibledatasets as $name => $value) {
|
||||||
$qanswerremaining = str_replace('{'.$name.'}', '1', $qanswerremaining);
|
$qanswerremaining = str_replace('{'.$name.'}', '1', $qanswerremaining);
|
||||||
}
|
}
|
||||||
// echo "numericalquestion qanswerremaining <pre>";print_r($possibledatasets);
|
// echo "numericalquestion qanswerremaining <pre>";print_r($possibledatasets);
|
||||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qanswerremaining, $regs1)) {
|
while (preg_match('~\{=([^[:space:]}]*)}~', $qanswerremaining, $regs1)) {
|
||||||
$qanswersplits = explode($regs1[0], $qanswerremaining, 2);
|
$qanswersplits = explode($regs1[0], $qanswerremaining, 2);
|
||||||
$qanswer =$qanswer.$qanswersplits[0];
|
$qanswer =$qanswer.$qanswersplits[0];
|
||||||
|
@ -320,16 +340,16 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
if ($trimmedanswer!=''){
|
if ($trimmedanswer!=''){
|
||||||
if ('2' == $data['correctanswerformat'][$key]
|
if ('2' == $data['correctanswerformat'][$key]
|
||||||
&& '0' == $data['correctanswerlength'][$key]) {
|
&& '0' == $data['correctanswerlength'][$key]) {
|
||||||
$errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
|
$errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
|
||||||
}
|
}
|
||||||
if (!is_numeric($data['tolerance'][$key])){
|
if (!is_numeric($data['tolerance'][$key])){
|
||||||
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
|
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
|
||||||
}
|
}
|
||||||
if ($data['fraction'][$key] == 1) {
|
if ($data['fraction'][$key] == 1) {
|
||||||
$maxgrade = true;
|
$maxgrade = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$answercount++;
|
$answercount++;
|
||||||
}
|
}
|
||||||
//check grades
|
//check grades
|
||||||
|
@ -342,14 +362,14 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
if ($data['fraction'][$key] > $maxfraction) {
|
if ($data['fraction'][$key] > $maxfraction) {
|
||||||
$maxfraction = $data['fraction'][$key];
|
$maxfraction = $data['fraction'][$key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($answercount==0){
|
if ($answercount==0){
|
||||||
$errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
$errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
||||||
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
||||||
} elseif ($answercount==1){
|
} elseif ($answercount==1){
|
||||||
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform sanity checks on fractional grades
|
/// Perform sanity checks on fractional grades
|
||||||
|
@ -365,17 +385,15 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
||||||
$errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
|
$errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($answercount==0){
|
if ($answercount==0){
|
||||||
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
||||||
}
|
}
|
||||||
if ($maxgrade == false) {
|
if ($maxgrade == false) {
|
||||||
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
question/type/calculatedmulti/lib.php
Normal file
31
question/type/calculatedmulti/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_calculatedmulti_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $DB, $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_calculatedmulti', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -1,17 +1,30 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
// CALCULATED ///
|
// CALCULATED ///
|
||||||
/////////////////
|
/////////////////
|
||||||
|
|
||||||
/// QUESTION TYPE CLASS //////////////////
|
/// QUESTION TYPE CLASS //////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class question_calculatedmulti_qtype extends question_calculated_qtype {
|
class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
|
|
||||||
// Used by the function custom_generator_tools:
|
// Used by the function custom_generator_tools:
|
||||||
var $calcgenerateidhasbeenadded = false;
|
public $calcgenerateidhasbeenadded = false;
|
||||||
public $virtualqtype = false;
|
public $virtualqtype = false;
|
||||||
|
|
||||||
function name() {
|
function name() {
|
||||||
|
@ -28,14 +41,13 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
|
|
||||||
|
|
||||||
function save_question_options($question) {
|
function save_question_options($question) {
|
||||||
//$options = $question->subtypeoptions;
|
|
||||||
// Get old answers:
|
|
||||||
global $CFG, $DB, $QTYPES ;
|
global $CFG, $DB, $QTYPES ;
|
||||||
|
$context = $question->context;
|
||||||
if (isset($question->answer) && !isset($question->answers)) {
|
if (isset($question->answer) && !isset($question->answers)) {
|
||||||
$question->answers = $question->answer;
|
$question->answers = $question->answer;
|
||||||
}
|
}
|
||||||
// calculated options
|
// calculated options
|
||||||
$update = true ;
|
$update = true ;
|
||||||
$options = $DB->get_record("question_calculated_options", array("question" => $question->id));
|
$options = $DB->get_record("question_calculated_options", array("question" => $question->id));
|
||||||
if (!$options) {
|
if (!$options) {
|
||||||
$update = false;
|
$update = false;
|
||||||
|
@ -46,19 +58,20 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
$options->single = $question->single;
|
$options->single = $question->single;
|
||||||
$options->answernumbering = $question->answernumbering;
|
$options->answernumbering = $question->answernumbering;
|
||||||
$options->shuffleanswers = $question->shuffleanswers;
|
$options->shuffleanswers = $question->shuffleanswers;
|
||||||
$options->correctfeedback = trim($question->correctfeedback);
|
|
||||||
$options->partiallycorrectfeedback = trim($question->partiallycorrectfeedback);
|
// save question feedback files
|
||||||
$options->incorrectfeedback = trim($question->incorrectfeedback);
|
foreach (array('correct', 'partiallycorrect', 'incorrect') as $feedbacktype) {
|
||||||
|
$feedbackname = $feedbacktype . 'feedback';
|
||||||
|
$feedbackformat = $feedbackname . 'format';
|
||||||
|
$feedback = $question->$feedbackname;
|
||||||
|
$options->$feedbackformat = $feedback['format'];
|
||||||
|
$options->$feedbackname = file_save_draft_area_files($feedback['itemid'], $context->id, 'qtype_calculatedmulti', $feedbackname, $question->id, self::$fileoptions, trim($feedback['text']));
|
||||||
|
}
|
||||||
|
|
||||||
if ($update) {
|
if ($update) {
|
||||||
if (!$DB->update_record("question_calculated_options", $options)) {
|
$DB->update_record("question_calculated_options", $options);
|
||||||
$result->error = "Could not update calculated question options! (id=$options->id)";
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!$DB->insert_record("question_calculated_options", $options)) {
|
$DB->insert_record("question_calculated_options", $options);
|
||||||
$result->error = "Could not insert calculated question options!";
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get old versions of the objects
|
// Get old versions of the objects
|
||||||
|
@ -71,8 +84,9 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the units.
|
// Save the units.
|
||||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
$virtualqtype = $this->get_virtual_qtype($question);
|
||||||
// $result = $virtualqtype->save_numerical_units($question);
|
// TODO: What is this?
|
||||||
|
// $result = $virtualqtype->save_numerical_units($question);
|
||||||
if (isset($result->error)) {
|
if (isset($result->error)) {
|
||||||
return $result;
|
return $result;
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,21 +94,25 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
}
|
}
|
||||||
// Insert all the new answers
|
// Insert all the new answers
|
||||||
if (isset($question->answer) && !isset($question->answers)) {
|
if (isset($question->answer) && !isset($question->answers)) {
|
||||||
$question->answers=$question->answer;
|
$question->answers = $question->answer;
|
||||||
}
|
}
|
||||||
foreach ($question->answers as $key => $dataanswer) {
|
foreach ($question->answers as $key => $dataanswer) {
|
||||||
if ( trim($dataanswer) != '' ) {
|
if ( trim($dataanswer) != '' ) {
|
||||||
$answer = new stdClass;
|
$answer = new stdClass;
|
||||||
$answer->question = $question->id;
|
$answer->question = $question->id;
|
||||||
$answer->answer = trim($dataanswer);
|
$answer->answer = trim($dataanswer);
|
||||||
$answer->fraction = $question->fraction[$key];
|
$answer->fraction = $question->fraction[$key];
|
||||||
$answer->feedback = trim($question->feedback[$key]);
|
$answer->feedback = trim($question->feedback[$key]['text']);
|
||||||
|
$answer->feedbackformat = $question->feedback[$key]['format'];
|
||||||
|
|
||||||
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||||
$answer->id = $oldanswer->id;
|
$answer->id = $oldanswer->id;
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $answer->feedback);
|
||||||
$DB->update_record("question_answers", $answer);
|
$DB->update_record("question_answers", $answer);
|
||||||
} else { // This is a completely new answer
|
} else { // This is a completely new answer
|
||||||
$answer->id = $DB->insert_record("question_answers", $answer);
|
$answer->id = $DB->insert_record("question_answers", $answer);
|
||||||
|
$feedbacktext = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $answer->feedback);
|
||||||
|
$DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$answer->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the options object
|
// Set up the options object
|
||||||
|
@ -129,15 +147,15 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
$DB->delete_records('question_calculated', array('id' => $oo->id));
|
$DB->delete_records('question_calculated', array('id' => $oo->id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// $result = $QTYPES['numerical']->save_numerical_options($question);
|
// $result = $QTYPES['numerical']->save_numerical_options($question);
|
||||||
// if (isset($result->error)) {
|
// if (isset($result->error)) {
|
||||||
// return $result;
|
// return $result;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
if( isset($question->import_process)&&$question->import_process){
|
if( isset($question->import_process)&&$question->import_process){
|
||||||
$this->import_datasets($question);
|
$this->import_datasets($question);
|
||||||
}
|
}
|
||||||
// Report any problems.
|
// Report any problems.
|
||||||
if (!empty($result->notice)) {
|
if (!empty($result->notice)) {
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -148,30 +166,25 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
|
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
|
||||||
// Find out how many datasets are available
|
// Find out how many datasets are available
|
||||||
global $CFG, $DB, $QTYPES, $OUTPUT ;
|
global $CFG, $DB, $QTYPES, $OUTPUT ;
|
||||||
if(!$maxnumber = (int)$DB->get_field_sql(
|
$maxnumber = (int)$DB->get_field_sql(
|
||||||
"SELECT MIN(a.itemcount)
|
"SELECT MIN(a.itemcount)
|
||||||
FROM {question_dataset_definitions} a,
|
FROM {question_dataset_definitions} a, {question_datasets} b
|
||||||
{question_datasets} b
|
WHERE b.question = ? AND a.id = b.datasetdefinition", array($question->id));
|
||||||
WHERE b.question = ?
|
if (!$maxnumber) {
|
||||||
AND a.id = b.datasetdefinition", array($question->id))) {
|
|
||||||
print_error('cannotgetdsforquestion', 'question', '', $question->id);
|
print_error('cannotgetdsforquestion', 'question', '', $question->id);
|
||||||
}
|
}
|
||||||
$sql = "SELECT i.*
|
$sql = "SELECT i.*
|
||||||
FROM {question_datasets} d,
|
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||||
{question_dataset_definitions} i
|
WHERE d.question = ? AND d.datasetdefinition = i.id AND i.category != 0";
|
||||||
WHERE d.question = ?
|
|
||||||
AND d.datasetdefinition = i.id
|
|
||||||
AND i.category != 0
|
|
||||||
";
|
|
||||||
if (!$question->options->synchronize || !$records = $DB->get_records_sql($sql, array($question->id))) {
|
if (!$question->options->synchronize || !$records = $DB->get_records_sql($sql, array($question->id))) {
|
||||||
$synchronize_calculated = false ;
|
$synchronize_calculated = false ;
|
||||||
}else {
|
} else {
|
||||||
// i.e records is true so test coherence
|
// i.e records is true so test coherence
|
||||||
$coherence = true ;
|
$coherence = true ;
|
||||||
$a = new stdClass ;
|
$a = new stdClass ;
|
||||||
$a->qid = $question->id ;
|
$a->qid = $question->id ;
|
||||||
$a->qcat = $question->category ;
|
$a->qcat = $question->category ;
|
||||||
foreach($records as $def ){
|
foreach($records as $def ){
|
||||||
if ($def->category != $question->category){
|
if ($def->category != $question->category){
|
||||||
$a->name = $def->name;
|
$a->name = $def->name;
|
||||||
$a->sharedcat = $def->category ;
|
$a->sharedcat = $def->category ;
|
||||||
|
@ -180,11 +193,11 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!$coherence){
|
if(!$coherence){
|
||||||
echo $OUTPUT->notification(get_string('nocoherencequestionsdatyasetcategory','qtype_calculated',$a));
|
echo $OUTPUT->notification(get_string('nocoherencequestionsdatyasetcategory','qtype_calculated',$a));
|
||||||
}
|
}
|
||||||
|
|
||||||
$synchronize_calculated = true ;
|
$synchronize_calculated = true ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose a random dataset
|
// Choose a random dataset
|
||||||
// maxnumber sould not be breater than 100
|
// maxnumber sould not be breater than 100
|
||||||
|
@ -194,41 +207,40 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
if ( $synchronize_calculated === false ) {
|
if ( $synchronize_calculated === false ) {
|
||||||
$state->options->datasetitem = rand(1, $maxnumber);
|
$state->options->datasetitem = rand(1, $maxnumber);
|
||||||
}else{
|
}else{
|
||||||
$state->options->datasetitem = intval( $maxnumber * substr($attempt->timestart,-2) /100 ) ;
|
$state->options->datasetitem = intval( $maxnumber * substr($attempt->timestart,-2) /100 ) ;
|
||||||
if ($state->options->datasetitem < 1) {
|
if ($state->options->datasetitem < 1) {
|
||||||
$state->options->datasetitem =1 ;
|
$state->options->datasetitem =1 ;
|
||||||
} else if ($state->options->datasetitem > $maxnumber){
|
} else if ($state->options->datasetitem > $maxnumber){
|
||||||
$state->options->datasetitem = $maxnumber ;
|
$state->options->datasetitem = $maxnumber ;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
$state->options->dataset =
|
$state->options->dataset =
|
||||||
$this->pick_question_dataset($question,$state->options->datasetitem);
|
$this->pick_question_dataset($question,$state->options->datasetitem);
|
||||||
// create an array of answerids ??? why so complicated ???
|
// create an array of answerids ??? why so complicated ???
|
||||||
$answerids = array_values(array_map(create_function('$val',
|
$answerids = array_values(array_map(create_function('$val',
|
||||||
'return $val->id;'), $question->options->answers));
|
'return $val->id;'), $question->options->answers));
|
||||||
// Shuffle the answers if required
|
// Shuffle the answers if required
|
||||||
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
|
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
|
||||||
$answerids = swapshuffle($answerids);
|
$answerids = swapshuffle($answerids);
|
||||||
}
|
}
|
||||||
$state->options->order = $answerids;
|
$state->options->order = $answerids;
|
||||||
// Create empty responses
|
// Create empty responses
|
||||||
if ($question->options->single) {
|
if ($question->options->single) {
|
||||||
$state->responses = array('' => '');
|
$state->responses = array('' => '');
|
||||||
} else {
|
} else {
|
||||||
$state->responses = array();
|
$state->responses = array();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function save_session_and_responses(&$question, &$state) {
|
function save_session_and_responses(&$question, &$state) {
|
||||||
global $DB;
|
global $DB;
|
||||||
$responses = 'dataset'.$state->options->datasetitem.'-' ;
|
$responses = 'dataset'.$state->options->datasetitem.'-' ;
|
||||||
$responses .= implode(',', $state->options->order) . ':';
|
$responses .= implode(',', $state->options->order) . ':';
|
||||||
$responses .= implode(',', $state->responses);
|
$responses .= implode(',', $state->responses);
|
||||||
|
|
||||||
// Set the legacy answer field
|
// Set the legacy answer field
|
||||||
if (!$DB->set_field('question_states', 'answer', $responses, array('id'=> $state->id))) {
|
if (!$DB->set_field('question_states', 'answer', $responses, array('id'=> $state->id))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +253,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
foreach ($form->answers as $key => $answer) {
|
foreach ($form->answers as $key => $answer) {
|
||||||
$a->answer = trim($form->answer[$key]);
|
$a->answer = trim($form->answer[$key]);
|
||||||
$a->fraction = $form->fraction[$key];//new
|
$a->fraction = $form->fraction[$key];//new
|
||||||
$a->tolerance = $form->tolerance[$key];
|
$a->tolerance = $form->tolerance[$key];
|
||||||
$a->tolerancetype = $form->tolerancetype[$key];
|
$a->tolerancetype = $form->tolerancetype[$key];
|
||||||
$a->correctanswerlength = $form->correctanswerlength[$key];
|
$a->correctanswerlength = $form->correctanswerlength[$key];
|
||||||
$a->correctanswerformat = $form->correctanswerformat[$key];
|
$a->correctanswerformat = $form->correctanswerformat[$key];
|
||||||
|
@ -251,57 +263,53 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
return $question;
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function convert_answers (&$question, &$state){
|
function convert_answers (&$question, &$state){
|
||||||
foreach ($question->options->answers as $key => $answer) {
|
foreach ($question->options->answers as $key => $answer) {
|
||||||
$answer->answer = $this->substitute_variables($answer->answer, $state->options->dataset);
|
$answer->answer = $this->substitute_variables($answer->answer, $state->options->dataset);
|
||||||
//evaluate the equations i.e {=5+4)
|
//evaluate the equations i.e {=5+4)
|
||||||
$qtext = "";
|
$qtext = "";
|
||||||
$qtextremaining = $answer->answer ;
|
$qtextremaining = $answer->answer ;
|
||||||
// while (preg_match('~\{(=)|%[[:digit]]\.=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
// while (preg_match('~\{(=)|%[[:digit]]\.=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||||
|
|
||||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||||
$qtext =$qtext.$qtextsplits[0];
|
$qtext = $qtext.$qtextsplits[0];
|
||||||
$qtextremaining = $qtextsplits[1];
|
$qtextremaining = $qtextsplits[1];
|
||||||
if (empty($regs1[1])) {
|
if (empty($regs1[1])) {
|
||||||
$str = '';
|
$str = '';
|
||||||
} else {
|
} else {
|
||||||
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
||||||
$str=$formulaerrors ;
|
$str=$formulaerrors ;
|
||||||
}else {
|
}else {
|
||||||
eval('$str = '.$regs1[1].';');
|
eval('$str = '.$regs1[1].';');
|
||||||
$texteval= qtype_calculated_calculate_answer(
|
$texteval= qtype_calculated_calculate_answer(
|
||||||
$str, $state->options->dataset, $answer->tolerance,
|
$str, $state->options->dataset, $answer->tolerance,
|
||||||
$answer->tolerancetype, $answer->correctanswerlength,
|
$answer->tolerancetype, $answer->correctanswerlength,
|
||||||
$answer->correctanswerformat, '');
|
$answer->correctanswerformat, '');
|
||||||
$str = $texteval->answer;
|
$str = $texteval->answer;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$qtext = $qtext.$str ;
|
|
||||||
}
|
}
|
||||||
$answer->answer = $qtext.$qtextremaining ; ;
|
$qtext = $qtext.$str ;
|
||||||
}
|
}
|
||||||
|
$answer->answer = $qtext.$qtextremaining ; ;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function get_default_numerical_unit($question,$virtualqtype){
|
function get_default_numerical_unit($question, $virtualqtype){
|
||||||
$unit = '';
|
$unit = '';
|
||||||
return $unit ;
|
return $unit ;
|
||||||
}
|
}
|
||||||
function grade_responses(&$question, &$state, $cmoptions) {
|
function grade_responses(&$question, &$state, $cmoptions) {
|
||||||
// Forward the grading to the virtual qtype
|
// Forward the grading to the virtual qtype
|
||||||
// We modify the question to look like a multichoice question
|
// We modify the question to look like a multichoice question
|
||||||
// for grading nothing to do
|
// for grading nothing to do
|
||||||
/* $numericalquestion = fullclone($question);
|
/* $numericalquestion = fullclone($question);
|
||||||
foreach ($numericalquestion->options->answers as $key => $answer) {
|
foreach ($numericalquestion->options->answers as $key => $answer) {
|
||||||
$answer = $numericalquestion->options->answers[$key]->answer; // for PHP 4.x
|
$answer = $numericalquestion->options->answers[$key]->answer; // for PHP 4.x
|
||||||
$numericalquestion->options->answers[$key]->answer = $this->substitute_variables_and_eval($answer,
|
$numericalquestion->options->answers[$key]->answer = $this->substitute_variables_and_eval($answer,
|
||||||
$state->options->dataset);
|
$state->options->dataset);
|
||||||
}*/
|
}*/
|
||||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||||
return $virtualqtype->grade_responses($question, $state, $cmoptions) ;
|
return $virtualqtype->grade_responses($question, $state, $cmoptions) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +327,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
$this->convert_answers ($numericalquestion, $state);
|
$this->convert_answers ($numericalquestion, $state);
|
||||||
$this->convert_questiontext ($numericalquestion, $state);
|
$this->convert_questiontext ($numericalquestion, $state);
|
||||||
/* $numericalquestion->questiontext = $this->substitute_variables_and_eval(
|
/* $numericalquestion->questiontext = $this->substitute_variables_and_eval(
|
||||||
$numericalquestion->questiontext, $state->options->dataset);*/
|
$numericalquestion->questiontext, $state->options->dataset);*/
|
||||||
$responses = $virtualqtype->get_all_responses($numericalquestion, $state);
|
$responses = $virtualqtype->get_all_responses($numericalquestion, $state);
|
||||||
$response = reset($responses->responses);
|
$response = reset($responses->responses);
|
||||||
$correct = $response->answer.' : ';
|
$correct = $response->answer.' : ';
|
||||||
|
@ -335,8 +343,8 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
|
|
||||||
function create_virtual_qtype() {
|
function create_virtual_qtype() {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
require_once("$CFG->dirroot/question/type/multichoice/questiontype.php");
|
require_once("$CFG->dirroot/question/type/multichoice/questiontype.php");
|
||||||
return new question_multichoice_qtype();
|
return new question_multichoice_qtype();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,7 +361,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
} else {
|
} else {
|
||||||
$strheader .= $delimiter.$answer->answer;
|
$strheader .= $delimiter.$answer->answer;
|
||||||
}
|
}
|
||||||
$delimiter = '<br/>';
|
$delimiter = '<br/>';
|
||||||
}
|
}
|
||||||
return $strheader;
|
return $strheader;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +377,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
$unit = $unit->unit;
|
$unit = $unit->unit;
|
||||||
} else {
|
} else {
|
||||||
$unit = '';
|
$unit = '';
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
$answers = fullclone($answers);
|
$answers = fullclone($answers);
|
||||||
$strmin = get_string('min', 'quiz');
|
$strmin = get_string('min', 'quiz');
|
||||||
|
@ -377,29 +385,29 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
$errors = '';
|
$errors = '';
|
||||||
$delimiter = ': ';
|
$delimiter = ': ';
|
||||||
foreach ($answers as $key => $answer) {
|
foreach ($answers as $key => $answer) {
|
||||||
$answer->answer = $this->substitute_variables($answer->answer, $data);
|
$answer->answer = $this->substitute_variables($answer->answer, $data);
|
||||||
//evaluate the equations i.e {=5+4)
|
//evaluate the equations i.e {=5+4)
|
||||||
$qtext = "";
|
$qtext = "";
|
||||||
$qtextremaining = $answer->answer ;
|
$qtextremaining = $answer->answer ;
|
||||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||||
$qtext =$qtext.$qtextsplits[0];
|
$qtext =$qtext.$qtextsplits[0];
|
||||||
$qtextremaining = $qtextsplits[1];
|
$qtextremaining = $qtextsplits[1];
|
||||||
if (empty($regs1[1])) {
|
if (empty($regs1[1])) {
|
||||||
$str = '';
|
$str = '';
|
||||||
} else {
|
} else {
|
||||||
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
||||||
$str=$formulaerrors ;
|
$str=$formulaerrors ;
|
||||||
}else {
|
}else {
|
||||||
eval('$str = '.$regs1[1].';');
|
eval('$str = '.$regs1[1].';');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$qtext = $qtext.$str ;
|
|
||||||
}
|
}
|
||||||
$answer->answer = $qtext.$qtextremaining ; ;
|
$qtext = $qtext.$str ;
|
||||||
$comment->stranswers[$key]= $answer->answer ;
|
}
|
||||||
|
$answer->answer = $qtext.$qtextremaining;
|
||||||
|
$comment->stranswers[$key] = $answer->answer;
|
||||||
|
|
||||||
|
|
||||||
/* $formula = $this->substitute_variables($answer->answer,$data);
|
/* $formula = $this->substitute_variables($answer->answer,$data);
|
||||||
$formattedanswer = qtype_calculated_calculate_answer(
|
$formattedanswer = qtype_calculated_calculate_answer(
|
||||||
$answer->answer, $data, $answer->tolerance,
|
$answer->answer, $data, $answer->tolerance,
|
||||||
|
@ -411,7 +419,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
}else {
|
}else {
|
||||||
eval('$answer->answer = '.$formula.';') ;
|
eval('$answer->answer = '.$formula.';') ;
|
||||||
$virtualqtype->get_tolerance_interval($answer);
|
$virtualqtype->get_tolerance_interval($answer);
|
||||||
}
|
}
|
||||||
if ($answer->min === '') {
|
if ($answer->min === '') {
|
||||||
// This should mean that something is wrong
|
// This should mean that something is wrong
|
||||||
$comment->stranswers[$key] = " $formattedanswer->answer".'<br/><br/>';
|
$comment->stranswers[$key] = " $formattedanswer->answer".'<br/><br/>';
|
||||||
|
@ -432,15 +440,11 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
$comment->stranswers[$key] .=get_string('trueanswerinsidelimits','qtype_calculated',$correcttrue);//' True answer :'.$calculated->trueanswer.' inside limits';
|
$comment->stranswers[$key] .=get_string('trueanswerinsidelimits','qtype_calculated',$correcttrue);//' True answer :'.$calculated->trueanswer.' inside limits';
|
||||||
}
|
}
|
||||||
$comment->stranswers[$key] .='';
|
$comment->stranswers[$key] .='';
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
return fullclone($comment);
|
return fullclone($comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function get_correct_responses1(&$question, &$state) {
|
function get_correct_responses1(&$question, &$state) {
|
||||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||||
/* if ($question->options->multichoice != 1 ) {
|
/* if ($question->options->multichoice != 1 ) {
|
||||||
|
@ -464,71 +468,148 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||||
return $correct;
|
return $correct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{**/
|
}else{**/
|
||||||
return $virtualqtype->get_correct_responses($question, $state) ;
|
return $virtualqtype->get_correct_responses($question, $state) ;
|
||||||
// }
|
// }
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_virtual_qtype() {
|
function get_virtual_qtype() {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
// if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){
|
// if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){
|
||||||
$this->virtualqtype =& $QTYPES['multichoice'];
|
$this->virtualqtype =& $QTYPES['multichoice'];
|
||||||
// }else {
|
// }else {
|
||||||
// $this->virtualqtype =& $QTYPES['numerical'];
|
// $this->virtualqtype =& $QTYPES['numerical'];
|
||||||
// }
|
// }
|
||||||
return $this->virtualqtype;
|
return $this->virtualqtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs all the code required to set up and save an essay question for testing purposes.
|
* Runs all the code required to set up and save an essay question for testing purposes.
|
||||||
* Alternate DB table prefix may be used to facilitate data deletion.
|
* Alternate DB table prefix may be used to facilitate data deletion.
|
||||||
*/
|
*/
|
||||||
function generate_test($name, $courseid = null) {
|
function generate_test($name, $courseid = null) {
|
||||||
global $DB;
|
global $DB;
|
||||||
list($form, $question) = parent::generate_test($name, $courseid);
|
list($form, $question) = parent::generate_test($name, $courseid);
|
||||||
$form->feedback = 1;
|
$form->feedback = 1;
|
||||||
$form->multiplier = array(1, 1);
|
$form->multiplier = array(1, 1);
|
||||||
$form->shuffleanswers = 1;
|
$form->shuffleanswers = 1;
|
||||||
$form->noanswers = 1;
|
$form->noanswers = 1;
|
||||||
$form->qtype ='calculatedmulti';
|
$form->qtype ='calculatedmulti';
|
||||||
$question->qtype ='calculatedmulti';
|
$question->qtype ='calculatedmulti';
|
||||||
$form->answers = array('{a} + {b}');
|
$form->answers = array('{a} + {b}');
|
||||||
$form->fraction = array(1);
|
$form->fraction = array(1);
|
||||||
$form->tolerance = array(0.01);
|
$form->tolerance = array(0.01);
|
||||||
$form->tolerancetype = array(1);
|
$form->tolerancetype = array(1);
|
||||||
$form->correctanswerlength = array(2);
|
$form->correctanswerlength = array(2);
|
||||||
$form->correctanswerformat = array(1);
|
$form->correctanswerformat = array(1);
|
||||||
$form->questiontext = "What is {a} + {b}?";
|
$form->questiontext = "What is {a} + {b}?";
|
||||||
|
|
||||||
if ($courseid) {
|
if ($courseid) {
|
||||||
$course = $DB->get_record('course', array('id'=> $courseid));
|
$course = $DB->get_record('course', array('id'=> $courseid));
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_question = $this->save_question($question, $form, $course);
|
$new_question = $this->save_question($question, $form, $course);
|
||||||
|
|
||||||
$dataset_form = new stdClass();
|
$dataset_form = new stdClass();
|
||||||
$dataset_form->nextpageparam["forceregeneration"]= 1;
|
$dataset_form->nextpageparam["forceregeneration"]= 1;
|
||||||
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
||||||
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
||||||
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
||||||
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
||||||
$dataset_form->itemid = array(1 => '' , 2 => '');
|
$dataset_form->itemid = array(1 => '' , 2 => '');
|
||||||
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
||||||
$dataset_form->definition = array(1 => "1-0-a",
|
$dataset_form->definition = array(1 => "1-0-a",
|
||||||
2 => "1-0-b");
|
2 => "1-0-b");
|
||||||
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
||||||
$dataset_form->addbutton = 1;
|
$dataset_form->addbutton = 1;
|
||||||
$dataset_form->selectadd = 1;
|
$dataset_form->selectadd = 1;
|
||||||
$dataset_form->courseid = $courseid;
|
$dataset_form->courseid = $courseid;
|
||||||
$dataset_form->cmid = 0;
|
$dataset_form->cmid = 0;
|
||||||
$dataset_form->id = $new_question->id;
|
$dataset_form->id = $new_question->id;
|
||||||
$this->save_dataset_items($new_question, $dataset_form);
|
$this->save_dataset_items($new_question, $dataset_form);
|
||||||
|
|
||||||
return $new_question;
|
return $new_question;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
// move files belonging to question component
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
// move files belonging to qtype_calculatedmulti
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
$component = 'question';
|
||||||
|
$filearea = 'answerfeedback';
|
||||||
|
foreach ($oldanswers as $answer) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$component = 'qtype_calculatedmulti';
|
||||||
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $filearea) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
$itemid = reset($args);
|
||||||
|
|
||||||
|
if (empty($question->maxgrade)) {
|
||||||
|
$question->maxgrade = $question->defaultgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($filearea, array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'))) {
|
||||||
|
$result = $options->feedback && ($itemid == $question->id);
|
||||||
|
if (!$result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($state->raw_grade >= $question->maxgrade/1.01) {
|
||||||
|
$feedbacktype = 'correctfeedback';
|
||||||
|
} else if ($state->raw_grade > 0) {
|
||||||
|
$feedbacktype = 'partiallycorrectfeedback';
|
||||||
|
} else {
|
||||||
|
$feedbacktype = 'incorrectfeedback';
|
||||||
|
}
|
||||||
|
if ($feedbacktype != $filearea) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||||
|
return $options->feedback && (array_key_exists($itemid, $question->options->answers));
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//// END OF CLASS ////
|
//// END OF CLASS ////
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the calculated simplequestion type.
|
* Defines the editing form for the calculated simplequestion type.
|
||||||
*
|
*
|
||||||
|
@ -8,21 +24,17 @@
|
||||||
* @package questionbank
|
* @package questionbank
|
||||||
* @subpackage questiontypes
|
* @subpackage questiontypes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* calculatedsimple editing form definition.
|
|
||||||
*/
|
|
||||||
class question_edit_calculatedsimple_form extends question_edit_form {
|
class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
/**
|
/**
|
||||||
* Handle to the question type for this question.
|
* Handle to the question type for this question.
|
||||||
*
|
*
|
||||||
* @var question_calculatedsimple_qtype
|
* @var question_calculatedsimple_qtype
|
||||||
*/
|
*/
|
||||||
var $qtypeobj;
|
public $qtypeobj;
|
||||||
|
|
||||||
var $wildcarddisplay ;
|
public $wildcarddisplay ;
|
||||||
|
|
||||||
var $questiondisplay ;
|
public $questiondisplay ;
|
||||||
|
|
||||||
public $datasetdefs;
|
public $datasetdefs;
|
||||||
|
|
||||||
|
@ -46,8 +58,6 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
|
|
||||||
public $formdata = array();
|
public $formdata = array();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function question_edit_calculatedsimple_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
function question_edit_calculatedsimple_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
||||||
global $QTYPES, $SESSION, $CFG, $DB;
|
global $QTYPES, $SESSION, $CFG, $DB;
|
||||||
$this->regenerate = true;
|
$this->regenerate = true;
|
||||||
|
@ -60,17 +70,17 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
//so this should be removed from here
|
//so this should be removed from here
|
||||||
// get priority to paramdatasets
|
// get priority to paramdatasets
|
||||||
|
|
||||||
if ( "1" == optional_param('reload','', PARAM_INT )) {
|
if ("1" == optional_param('reload','', PARAM_INT )) {
|
||||||
$this->reload = true ;
|
$this->reload = true;
|
||||||
}else {
|
}else {
|
||||||
$this->reload = false ;
|
$this->reload = false;
|
||||||
}
|
}
|
||||||
if(!$this->reload ){ // use database data as this is first pass
|
if (!$this->reload) { // use database data as this is first pass
|
||||||
// question->id == 0 so no stored datasets
|
// question->id == 0 so no stored datasets
|
||||||
// else get datasets
|
// else get datasets
|
||||||
// echo "<p>question <pre>";print_r($question);echo "</pre></p>";
|
// echo "<p>question <pre>";print_r($question);echo "</pre></p>";
|
||||||
if ( !empty($question->id)) {
|
if (!empty($question->id)) {
|
||||||
|
|
||||||
/* if (empty($question->options)) {
|
/* if (empty($question->options)) {
|
||||||
$this->get_question_options($question);
|
$this->get_question_options($question);
|
||||||
}*/
|
}*/
|
||||||
|
@ -127,7 +137,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
$mandatorydatasets = array();
|
$mandatorydatasets = array();
|
||||||
// should not test on adding a new answer
|
// should not test on adding a new answer
|
||||||
// should test if there are already olddatasets or if the 'analyzequestion' submit button has been clicked
|
// should test if there are already olddatasets or if the 'analyzequestion' submit button has been clicked
|
||||||
if ('' != optional_param('datasetdef', '', PARAM_RAW) || '' != optional_param('analyzequestion', '', PARAM_RAW)){
|
if ('' != optional_param('datasetdef', '', PARAM_RAW) || '' != optional_param('analyzequestion', '', PARAM_RAW)){
|
||||||
|
|
||||||
if ( $dummyform->answer = optional_param('answer', '', PARAM_NOTAGS)) { // there is always at least one answer...
|
if ( $dummyform->answer = optional_param('answer', '', PARAM_NOTAGS)) { // there is always at least one answer...
|
||||||
$fraction = optional_param('fraction', '', PARAM_NUMBER);
|
$fraction = optional_param('fraction', '', PARAM_NUMBER);
|
||||||
|
@ -297,12 +307,12 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
$addfieldsname='updatequestion value';
|
$addfieldsname='updatequestion value';
|
||||||
$addstring=get_string("updatecategory", "qtype_calculated");
|
$addstring=get_string("updatecategory", "qtype_calculated");
|
||||||
$mform->registerNoSubmitButton($addfieldsname);
|
$mform->registerNoSubmitButton($addfieldsname);
|
||||||
//put a submit button to stop supplementary answers on update answers parameters
|
// put a submit button to stop supplementary answers on update answers parameters
|
||||||
// $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
// $mform->insertElementBefore($mform->createElement('submit', $addfieldsname, $addstring), 'listcategory');
|
||||||
|
|
||||||
$creategrades = get_grade_options();
|
$creategrades = get_grade_options();
|
||||||
$this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
|
$this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
|
||||||
$creategrades->gradeoptions, 1, 1);
|
$creategrades->gradeoptions, 1, 1);
|
||||||
|
|
||||||
$QTYPES['numerical']->add_units_options($mform,$this);
|
$QTYPES['numerical']->add_units_options($mform,$this);
|
||||||
|
|
||||||
|
@ -327,7 +337,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
$this->noofitems = 0;
|
$this->noofitems = 0;
|
||||||
}
|
}
|
||||||
if(!empty($this->datasetdefs)){//So there are some datadefs
|
if(!empty($this->datasetdefs)){//So there are some datadefs
|
||||||
// we put them on the page
|
// we put them on the page
|
||||||
$key = 0;
|
$key = 0;
|
||||||
$mform->addElement('header', 'additemhdr', get_string('wildcardparam', 'qtype_calculatedsimple'));
|
$mform->addElement('header', 'additemhdr', get_string('wildcardparam', 'qtype_calculatedsimple'));
|
||||||
$idx = 1;
|
$idx = 1;
|
||||||
|
@ -347,180 +357,183 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
//this should be done before the elements are created and stored as $this->formdata ;
|
//this should be done before the elements are created and stored as $this->formdata ;
|
||||||
//fill out all data sets and also the fields for the next item to add.
|
//fill out all data sets and also the fields for the next item to add.
|
||||||
/*Here we do already the values error analysis so that
|
/*Here we do already the values error analysis so that
|
||||||
* we could force all wild cards values display if there is an error in values.
|
* we could force all wild cards values display if there is an error in values.
|
||||||
* as using a , in a number */
|
* as using a , in a number */
|
||||||
$this->numbererrors = array();
|
$this->numbererrors = array();
|
||||||
if(!empty($this->datasetdefs)){
|
if(!empty($this->datasetdefs)){
|
||||||
$j = $this->noofitems * count($this->datasetdefs);
|
$j = $this->noofitems * count($this->datasetdefs);
|
||||||
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
||||||
$data = array();
|
$data = array();
|
||||||
$numbererrors = array() ;
|
$numbererrors = array() ;
|
||||||
$comment = new stdClass;
|
$comment = new stdClass;
|
||||||
$comment->stranswers = array();
|
$comment->stranswers = array();
|
||||||
$comment->outsidelimit = false ;
|
$comment->outsidelimit = false ;
|
||||||
$comment->answers = array();
|
$comment->answers = array();
|
||||||
|
|
||||||
foreach ($this->datasetdefs as $defid => $datasetdef){
|
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||||
if (isset($datasetdef->items[$itemnumber])){
|
if (isset($datasetdef->items[$itemnumber])){
|
||||||
$this->formdata["definition[$j]"] = $defid;
|
$this->formdata["definition[$j]"] = $defid;
|
||||||
$this->formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
|
$this->formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
|
||||||
$data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
|
$data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
|
||||||
$this->formdata["number[$j]"] = $number = $datasetdef->items[$itemnumber]->value;
|
$this->formdata["number[$j]"] = $number = $datasetdef->items[$itemnumber]->value;
|
||||||
if(! is_numeric($number)){
|
if(! is_numeric($number)){
|
||||||
$a = new stdClass;
|
$a = new stdClass;
|
||||||
$a->name = '{'.$datasetdef->name.'}' ;
|
$a->name = '{'.$datasetdef->name.'}' ;
|
||||||
$a->value = $datasetdef->items[$itemnumber]->value ;
|
$a->value = $datasetdef->items[$itemnumber]->value ;
|
||||||
if (stristr($number,',')){
|
if (stristr($number,',')){
|
||||||
$this->numbererrors["number[$j]"]=get_string('nocommaallowed', 'qtype_calculated');
|
$this->numbererrors["number[$j]"]=get_string('nocommaallowed', 'qtype_calculated');
|
||||||
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
$this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
|
$this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
|
||||||
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
||||||
//$comment->outsidelimit = false ;
|
//$comment->outsidelimit = false ;
|
||||||
}
|
|
||||||
}else if( stristr($number,'x')){ // hexa will pass the test
|
|
||||||
$a = new stdClass;
|
|
||||||
$a->name = '{'.$datasetdef->name.'}' ;
|
|
||||||
$a->value = $datasetdef->items[$itemnumber]->value ;
|
|
||||||
$this->numbererrors['number['.$j.']']= get_string('hexanotallowed','qtype_calculated',$a);
|
|
||||||
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
|
||||||
} else if( is_nan($number)){
|
|
||||||
$a = new stdClass;
|
|
||||||
$a->name = '{'.$datasetdef->name.'}' ;
|
|
||||||
$a->value = $datasetdef->items[$itemnumber]->value ;
|
|
||||||
$this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
|
|
||||||
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
|
||||||
// $val = 1.0 ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$j--;
|
|
||||||
}
|
|
||||||
if($this->noofitems != 0 ) {
|
|
||||||
if (empty($numbererrors )){
|
|
||||||
if(!isset($this->question->id)) $this->question->id = 0 ;
|
|
||||||
$comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj,$this->question->id,$this->question->questiontext,$this->nonemptyanswer, $data, $itemnumber);//$this->
|
|
||||||
if ($comment->outsidelimit) {
|
|
||||||
$this->outsidelimit=$comment->outsidelimit ;
|
|
||||||
}
|
|
||||||
$totalcomment='';
|
|
||||||
|
|
||||||
foreach ($this->nonemptyanswer as $key => $answer) {
|
|
||||||
$totalcomment .= $comment->stranswers[$key].'<br/>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
|
|
||||||
}
|
}
|
||||||
|
}else if( stristr($number,'x')){ // hexa will pass the test
|
||||||
|
$a = new stdClass;
|
||||||
|
$a->name = '{'.$datasetdef->name.'}' ;
|
||||||
|
$a->value = $datasetdef->items[$itemnumber]->value ;
|
||||||
|
$this->numbererrors['number['.$j.']']= get_string('hexanotallowed','qtype_calculated',$a);
|
||||||
|
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
||||||
|
} else if( is_nan($number)){
|
||||||
|
$a = new stdClass;
|
||||||
|
$a->name = '{'.$datasetdef->name.'}' ;
|
||||||
|
$a->value = $datasetdef->items[$itemnumber]->value ;
|
||||||
|
$this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
|
||||||
|
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
||||||
|
// $val = 1.0 ;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
$j--;
|
||||||
}
|
}
|
||||||
$this->formdata['selectdelete'] = '1';
|
if($this->noofitems != 0 ) {
|
||||||
$this->formdata['selectadd'] = '1';
|
if (empty($numbererrors)) {
|
||||||
$j = $this->noofitems * count($this->datasetdefs)+1;
|
if (!isset($this->question->id)) {
|
||||||
$data = array(); // data for comment_on_datasetitems later
|
$this->question->id = 0 ;
|
||||||
|
}
|
||||||
|
$this->question->questiontext = !empty($this->question->questiontext)?$this->question->questiontext:'';
|
||||||
|
$comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $this->question->id, $this->question->questiontext, $this->nonemptyanswer, $data, $itemnumber);
|
||||||
|
if ($comment->outsidelimit) {
|
||||||
|
$this->outsidelimit=$comment->outsidelimit ;
|
||||||
|
}
|
||||||
|
$totalcomment='';
|
||||||
|
|
||||||
|
foreach ($this->nonemptyanswer as $key => $answer) {
|
||||||
|
$totalcomment .= $comment->stranswers[$key].'<br/>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->formdata['selectdelete'] = '1';
|
||||||
|
$this->formdata['selectadd'] = '1';
|
||||||
|
$j = $this->noofitems * count($this->datasetdefs)+1;
|
||||||
|
$data = array(); // data for comment_on_datasetitems later
|
||||||
$idx =1 ;
|
$idx =1 ;
|
||||||
foreach ($this->datasetdefs as $defid => $datasetdef){
|
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||||
$this->formdata["datasetdef[$idx]"] = $defid;
|
$this->formdata["datasetdef[$idx]"] = $defid;
|
||||||
$idx++;
|
$idx++;
|
||||||
}
|
}
|
||||||
$this->formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $this->formdata);
|
$this->formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $this->formdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$addoptions = Array();
|
||||||
|
$addoptions['1']='1';
|
||||||
|
for ($i=10; $i<=100 ; $i+=10){
|
||||||
|
$addoptions["$i"]="$i";
|
||||||
|
}
|
||||||
|
$showoptions = Array();
|
||||||
|
$showoptions['1']='1';
|
||||||
|
$showoptions['2']='2';
|
||||||
|
$showoptions['5']='5';
|
||||||
|
for ($i=10; $i<=100 ; $i+=10){
|
||||||
|
$showoptions["$i"]="$i";
|
||||||
|
}
|
||||||
|
$mform->closeHeaderBefore('additemhdr');
|
||||||
|
$addgrp = array();
|
||||||
|
$addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('generatenewitemsset', 'qtype_calculatedsimple'));
|
||||||
|
$addgrp[] =& $mform->createElement('select', "selectadd", '', $addoptions);
|
||||||
|
$addgrp[] = & $mform->createElement('static',"stat",'',get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
|
||||||
|
$mform->addGroup($addgrp, 'addgrp', '', ' ', false);
|
||||||
|
$mform->registerNoSubmitButton('addbutton');
|
||||||
|
$mform->closeHeaderBefore('addgrp');
|
||||||
|
$addgrp1 = array();
|
||||||
|
$addgrp1[] =& $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculatedsimple'));
|
||||||
|
$addgrp1[] =& $mform->createElement('select', "selectshow",'' , $showoptions);
|
||||||
|
$addgrp1[] = & $mform->createElement('static',"stat",'',get_string('setwildcardvalues', 'qtype_calculatedsimple'));
|
||||||
|
$mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
|
||||||
|
$mform->registerNoSubmitButton('showbutton');
|
||||||
|
$mform->closeHeaderBefore('addgrp1');
|
||||||
|
$mform->addElement('static', "divideradd", '', '');
|
||||||
|
if ($this->noofitems == 0) {
|
||||||
|
$mform->addElement('static','warningnoitems','','<span class="error">'.get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple').'</span>');
|
||||||
|
$mform->closeHeaderBefore('warningnoitems');
|
||||||
|
}else {
|
||||||
|
$mform->addElement('header', 'additemhdr1', get_string('wildcardvalues', 'qtype_calculatedsimple'));
|
||||||
|
$mform->closeHeaderBefore('additemhdr1');
|
||||||
|
// $mform->addElement('header', '', get_string('itemno', 'qtype_calculated', ""));
|
||||||
|
if( !empty($this->numbererrors) || $this->outsidelimit) {
|
||||||
|
$mform->addElement('static', "alert", '', '<span class="error">'.get_string('useadvance', 'qtype_calculatedsimple').'</span>');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$mform->addElement('submit', 'updatedatasets', get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
|
||||||
|
$mform->registerNoSubmitButton('updatedatasets');
|
||||||
|
$mform->setAdvanced("updatedatasets",true);
|
||||||
|
|
||||||
$addoptions = Array();
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
$addoptions['1']='1';
|
$j = $this->noofitems * count($this->datasetdefs);
|
||||||
for ($i=10; $i<=100 ; $i+=10){
|
$k = 1 ;
|
||||||
$addoptions["$i"]="$i";
|
if ("" != optional_param('selectshow')){
|
||||||
}
|
$k = optional_param('selectshow', '', PARAM_INT);
|
||||||
$showoptions = Array();
|
}
|
||||||
$showoptions['1']='1';
|
|
||||||
$showoptions['2']='2';
|
for ($i = $this->noofitems; $i >= 1 ; $i--){
|
||||||
$showoptions['5']='5';
|
foreach ($this->datasetdefs as $defkey => $datasetdef){
|
||||||
for ($i=10; $i<=100 ; $i+=10){
|
if($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ){
|
||||||
$showoptions["$i"]="$i";
|
$mform->addElement('text',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
|
||||||
}
|
$mform->setAdvanced("number[$j]",true);
|
||||||
$mform->closeHeaderBefore('additemhdr');
|
if(!empty($this->numbererrors['number['.$j.']']) ){
|
||||||
$addgrp = array();
|
$mform->addElement('static', "numbercomment[$j]",'','<span class="error">'.$this->numbererrors['number['.$j.']'].'</span>');
|
||||||
$addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('generatenewitemsset', 'qtype_calculatedsimple'));
|
$mform->setAdvanced("numbercomment[$j]",true);
|
||||||
$addgrp[] =& $mform->createElement('select', "selectadd", '', $addoptions);
|
}
|
||||||
$addgrp[] = & $mform->createElement('static',"stat",'',get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
|
}else {
|
||||||
$mform->addGroup($addgrp, 'addgrp', '', ' ', false);
|
$mform->addElement('hidden',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
|
||||||
$mform->registerNoSubmitButton('addbutton');
|
}
|
||||||
$mform->closeHeaderBefore('addgrp');
|
$mform->setType("number[$j]", PARAM_NUMBER);
|
||||||
$addgrp1 = array();
|
|
||||||
$addgrp1[] =& $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculatedsimple'));
|
$mform->addElement('hidden', "itemid[$j]");
|
||||||
$addgrp1[] =& $mform->createElement('select', "selectshow",'' , $showoptions);
|
$mform->setType("itemid[$j]", PARAM_INT);
|
||||||
$addgrp1[] = & $mform->createElement('static',"stat",'',get_string('setwildcardvalues', 'qtype_calculatedsimple'));
|
|
||||||
$mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
|
$mform->addElement('hidden', "definition[$j]");
|
||||||
$mform->registerNoSubmitButton('showbutton');
|
$mform->setType("definition[$j]", PARAM_NOTAGS);
|
||||||
$mform->closeHeaderBefore('addgrp1');
|
|
||||||
$mform->addElement('static', "divideradd", '', '');
|
$j--;
|
||||||
if ($this->noofitems == 0) {
|
}
|
||||||
$mform->addElement('static','warningnoitems','','<span class="error">'.get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple').'</span>');
|
if (!empty( $strquestionlabel) && ($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ) ){
|
||||||
$mform->closeHeaderBefore('warningnoitems');
|
// $repeated[] =& $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
|
||||||
|
$mform->addElement('static', "answercomment[$i]", "<b>".get_string('setno', 'qtype_calculatedsimple', $i)."</b> ".$strquestionlabel);
|
||||||
|
|
||||||
|
}
|
||||||
|
if($k > 0 || $this->outsidelimit || !empty($this->numbererrors )){
|
||||||
|
$mform->addElement('static', "divider1[$j]", '', '<hr />');
|
||||||
|
|
||||||
|
}
|
||||||
|
$k-- ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if ($this->outsidelimit){
|
||||||
|
// $mform->addElement('static','outsidelimit','','');
|
||||||
|
// }
|
||||||
}else {
|
}else {
|
||||||
$mform->addElement('header', 'additemhdr1', get_string('wildcardvalues', 'qtype_calculatedsimple'));
|
$mform->addElement('static','warningnowildcards','','<span class="error">'.get_string('atleastonewildcard', 'qtype_calculatedsimple').'</span>');
|
||||||
$mform->closeHeaderBefore('additemhdr1');
|
$mform->closeHeaderBefore('warningnowildcards');
|
||||||
// $mform->addElement('header', '', get_string('itemno', 'qtype_calculated', ""));
|
|
||||||
if( !empty($this->numbererrors) || $this->outsidelimit) {
|
|
||||||
$mform->addElement('static', "alert", '', '<span class="error">'.get_string('useadvance', 'qtype_calculatedsimple').'</span>');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$mform->addElement('submit', 'updatedatasets', get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
|
|
||||||
$mform->registerNoSubmitButton('updatedatasets');
|
|
||||||
$mform->setAdvanced("updatedatasets",true);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
$j = $this->noofitems * count($this->datasetdefs);
|
|
||||||
$k = 1 ;
|
|
||||||
if ("" != optional_param('selectshow')){
|
|
||||||
$k = optional_param('selectshow', '', PARAM_INT);
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($i = $this->noofitems; $i >= 1 ; $i--){
|
|
||||||
foreach ($this->datasetdefs as $defkey => $datasetdef){
|
|
||||||
if($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ){
|
|
||||||
$mform->addElement('text',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
|
|
||||||
$mform->setAdvanced("number[$j]",true);
|
|
||||||
if(!empty($this->numbererrors['number['.$j.']']) ){
|
|
||||||
$mform->addElement('static', "numbercomment[$j]",'','<span class="error">'.$this->numbererrors['number['.$j.']'].'</span>');
|
|
||||||
$mform->setAdvanced("numbercomment[$j]",true);
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
$mform->addElement('hidden',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
|
|
||||||
}
|
|
||||||
$mform->setType("number[$j]", PARAM_NUMBER);
|
|
||||||
|
|
||||||
$mform->addElement('hidden', "itemid[$j]");
|
|
||||||
$mform->setType("itemid[$j]", PARAM_INT);
|
|
||||||
|
|
||||||
$mform->addElement('hidden', "definition[$j]");
|
|
||||||
$mform->setType("definition[$j]", PARAM_NOTAGS);
|
|
||||||
|
|
||||||
$j--;
|
|
||||||
}
|
|
||||||
if (!empty( $strquestionlabel) && ($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ) ){
|
|
||||||
// $repeated[] =& $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
|
|
||||||
$mform->addElement('static', "answercomment[$i]", "<b>".get_string('setno', 'qtype_calculatedsimple', $i)."</b> ".$strquestionlabel);
|
|
||||||
|
|
||||||
}
|
|
||||||
if($k > 0 || $this->outsidelimit || !empty($this->numbererrors )){
|
|
||||||
$mform->addElement('static', "divider1[$j]", '', '<hr />');
|
|
||||||
|
|
||||||
}
|
|
||||||
$k-- ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if ($this->outsidelimit){
|
|
||||||
// $mform->addElement('static','outsidelimit','','');
|
|
||||||
// }
|
|
||||||
}else {
|
|
||||||
$mform->addElement('static','warningnowildcards','','<span class="error">'.get_string('atleastonewildcard', 'qtype_calculatedsimple').'</span>');
|
|
||||||
$mform->closeHeaderBefore('warningnowildcards');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
//non standard name for button element needed so not using add_action_buttons
|
//non standard name for button element needed so not using add_action_buttons
|
||||||
//hidden elements
|
//hidden elements
|
||||||
|
|
||||||
|
@ -536,50 +549,64 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
$mform->setDefault('cmid', 0);
|
$mform->setDefault('cmid', 0);
|
||||||
if (!empty($this->question->id)){
|
if (!empty($this->question->id)){
|
||||||
if ($this->question->formoptions->cansaveasnew){
|
if ($this->question->formoptions->cansaveasnew){
|
||||||
$mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
|
$mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
|
||||||
$mform->closeHeaderBefore('additemhdr');
|
$mform->closeHeaderBefore('additemhdr');
|
||||||
|
|
||||||
$mform->addElement('checkbox', 'convert','' ,get_string('willconverttocalculated', 'qtype_calculatedsimple'));
|
$mform->addElement('checkbox', 'convert','' ,get_string('willconverttocalculated', 'qtype_calculatedsimple'));
|
||||||
$mform->setDefault('convert', 0);
|
$mform->setDefault('convert', 0);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
|
$answer = $this->answer;
|
||||||
|
$default_values = array();
|
||||||
|
if (count($answer)) {
|
||||||
|
$key = 0;
|
||||||
|
foreach ($answer as $answer){
|
||||||
|
$default_values['answer['.$key.']'] = $answer->answer; // is necessary ? to-do test it
|
||||||
|
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||||
|
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
||||||
|
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
||||||
|
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
||||||
|
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
||||||
|
|
||||||
$answer = $this->answer;
|
// prepare draft files
|
||||||
$default_values = array();
|
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||||
if (count($answer)) {
|
$default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
|
||||||
$key = 0;
|
$draftid, // draftid
|
||||||
foreach ($answer as $answer){
|
$this->context->id, // context
|
||||||
$default_values['answer['.$key.']'] = $answer->answer; // is necessary ? to-do test it
|
'question', // component
|
||||||
$default_values['fraction['.$key.']'] = $answer->fraction;
|
'answerfeedback', // filarea
|
||||||
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
!empty($answer->id)?(int)$answer->id:null, // itemid
|
||||||
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
$this->fileoptions, // options
|
||||||
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
!empty($answer->feedback)?$answer->feedback:'' // text
|
||||||
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
);
|
||||||
$key++;
|
$default_values['feedback['.$key.']']['format'] = !empty($answer->feedbackformat)?$answer->feedbackformat:editors_get_preferred_format();
|
||||||
}
|
$default_values['feedback['.$key.']']['itemid'] = $draftid;
|
||||||
|
|
||||||
|
$key++;
|
||||||
}
|
}
|
||||||
$default_values['synchronize'] = 0 ;
|
}
|
||||||
$QTYPES['numerical']->set_numerical_unit_data($question,$default_values);
|
$default_values['synchronize'] = 0 ;
|
||||||
/* if (isset($question->options)){
|
$QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
|
||||||
|
/* if (isset($question->options)){
|
||||||
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
||||||
$default_values['unitpenalty'] = $question->options->unitpenalty ;
|
$default_values['unitpenalty'] = $question->options->unitpenalty ;
|
||||||
switch ($question->options->showunits){
|
switch ($question->options->showunits){
|
||||||
case 'O' :
|
case 'O' :
|
||||||
case '1' :
|
case '1' :
|
||||||
$default_values['showunits0'] = $question->options->showunits ;
|
$default_values['showunits0'] = $question->options->showunits ;
|
||||||
$default_values['unitrole'] = 0 ;
|
$default_values['unitrole'] = 0 ;
|
||||||
break;
|
break;
|
||||||
case '2' :
|
case '2' :
|
||||||
case '3' :
|
case '3' :
|
||||||
$default_values['showunits1'] = $question->options->showunits ;
|
$default_values['showunits1'] = $question->options->showunits ;
|
||||||
$default_values['unitrole'] = 1 ;
|
$default_values['unitrole'] = 1 ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$default_values['unitsleft'] = $question->options->unitsleft ;
|
$default_values['unitsleft'] = $question->options->unitsleft ;
|
||||||
$default_values['instructions'] = $question->options->instructions ;
|
$default_values['instructions'] = $question->options->instructions ;
|
||||||
|
|
||||||
|
@ -593,16 +620,16 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
$key = 0 ;
|
$key = 0 ;
|
||||||
|
|
||||||
$formdata = array();
|
$formdata = array();
|
||||||
$fromform = new stdClass();
|
$fromform = new stdClass();
|
||||||
//this should be done before the elements are created and stored as $this->formdata ;
|
//this should be done before the elements are created and stored as $this->formdata ;
|
||||||
//fill out all data sets and also the fields for the next item to add.
|
//fill out all data sets and also the fields for the next item to add.
|
||||||
/* if(!empty($this->datasetdefs)){
|
/* if(!empty($this->datasetdefs)){
|
||||||
$j = $this->noofitems * count($this->datasetdefs);
|
$j = $this->noofitems * count($this->datasetdefs);
|
||||||
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
||||||
$data = array();
|
$data = array();
|
||||||
foreach ($this->datasetdefs as $defid => $datasetdef){
|
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||||
if (isset($datasetdef->items[$itemnumber])){
|
if (isset($datasetdef->items[$itemnumber])){
|
||||||
|
@ -613,27 +640,27 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
$j--;
|
$j--;
|
||||||
}
|
}
|
||||||
// echo "<p>answers avant comment <pre>";print_r($answer);echo"</pre></p>";
|
// echo "<p>answers avant comment <pre>";print_r($answer);echo"</pre></p>";
|
||||||
// echo "<p>data avant comment <pre>";print_r($data);echo"</pre></p>";
|
// echo "<p>data avant comment <pre>";print_r($data);echo"</pre></p>";
|
||||||
|
|
||||||
if($this->noofitems != 0 ) {
|
if($this->noofitems != 0 ) {
|
||||||
if(!isset($question->id)) $question->id = 0 ;
|
if(!isset($question->id)) $question->id = 0 ;
|
||||||
$comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this->
|
$comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this->
|
||||||
if ($comment->outsidelimit) {
|
if ($comment->outsidelimit) {
|
||||||
$this->outsidelimit=$comment->outsidelimit ;
|
$this->outsidelimit=$comment->outsidelimit ;
|
||||||
}
|
}
|
||||||
$totalcomment='';
|
$totalcomment='';
|
||||||
// echo "<p> comment <pre>";print_r($comment);echo"</pre></p>";
|
// echo "<p> comment <pre>";print_r($comment);echo"</pre></p>";
|
||||||
|
|
||||||
foreach ($this->nonemptyanswer as $key => $answer) {
|
foreach ($this->nonemptyanswer as $key => $answer) {
|
||||||
$totalcomment .= $comment->stranswers[$key].'<br/>';
|
$totalcomment .= $comment->stranswers[$key].'<br/>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
|
$formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// $formdata['reload'] = '1';
|
||||||
// $formdata['reload'] = '1';
|
// $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
|
||||||
// $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
|
|
||||||
$formdata['selectdelete'] = '1';
|
$formdata['selectdelete'] = '1';
|
||||||
$formdata['selectadd'] = '1';
|
$formdata['selectadd'] = '1';
|
||||||
$j = $this->noofitems * count($this->datasetdefs)+1;
|
$j = $this->noofitems * count($this->datasetdefs)+1;
|
||||||
|
@ -644,10 +671,10 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
$idx++;
|
$idx++;
|
||||||
}
|
}
|
||||||
$formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
|
$formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
|
||||||
}*/
|
}*/
|
||||||
$question = (object)((array)$question + $default_values+$this->formdata );
|
$question = (object)((array)$question + $default_values+$this->formdata );
|
||||||
|
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
|
@ -659,8 +686,8 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
$errors = parent::validation($data, $files);
|
$errors = parent::validation($data, $files);
|
||||||
//verifying for errors in {=...} in question text;
|
//verifying for errors in {=...} in question text;
|
||||||
$qtext = "";
|
$qtext = "";
|
||||||
$qtextremaining = $data['questiontext'] ;
|
$qtextremaining = $data['questiontext']['text'];
|
||||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||||
foreach ($possibledatasets as $name => $value) {
|
foreach ($possibledatasets as $name => $value) {
|
||||||
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
||||||
}
|
}
|
||||||
|
@ -679,7 +706,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
$answers = $data['answer'];
|
$answers = $data['answer'];
|
||||||
$answercount = 0;
|
$answercount = 0;
|
||||||
$maxgrade = false;
|
$maxgrade = false;
|
||||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||||
$mandatorydatasets = array();
|
$mandatorydatasets = array();
|
||||||
foreach ($answers as $key => $answer){
|
foreach ($answers as $key => $answer){
|
||||||
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
||||||
|
@ -797,4 +824,3 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
question/type/calculatedsimple/lib.php
Normal file
31
question/type/calculatedsimple/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_calculatedsimple_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_calculatedsimple', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -1,30 +1,41 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
// CALCULATED ///
|
// CALCULATED ///
|
||||||
/////////////////
|
/////////////////
|
||||||
|
|
||||||
/// QUESTION TYPE CLASS //////////////////
|
/// QUESTION TYPE CLASS //////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class question_calculatedsimple_qtype extends question_calculated_qtype {
|
class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
|
|
||||||
// Used by the function custom_generator_tools:
|
// Used by the function custom_generator_tools:
|
||||||
var $calcgenerateidhasbeenadded = false;
|
public $calcgenerateidhasbeenadded = false;
|
||||||
public $virtualqtype = false;
|
public $virtualqtype = false;
|
||||||
|
|
||||||
function name() {
|
function name() {
|
||||||
return 'calculatedsimple';
|
return 'calculatedsimple';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function save_question_options($question) {
|
function save_question_options($question) {
|
||||||
|
global $CFG, $DB , $QTYPES;
|
||||||
|
$context = $question->context;
|
||||||
//$options = $question->subtypeoptions;
|
//$options = $question->subtypeoptions;
|
||||||
// Get old answers:
|
// Get old answers:
|
||||||
global $CFG, $DB , $QTYPES;
|
|
||||||
|
|
||||||
if (isset($question->answer) && !isset($question->answers)) {
|
if (isset($question->answer) && !isset($question->answers)) {
|
||||||
$question->answers = $question->answer;
|
$question->answers = $question->answer;
|
||||||
|
@ -52,18 +63,22 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
$question->answers=$question->answer;
|
$question->answers=$question->answer;
|
||||||
}
|
}
|
||||||
foreach ($question->answers as $key => $dataanswer) {
|
foreach ($question->answers as $key => $dataanswer) {
|
||||||
if ( trim($dataanswer) != '' ) {
|
if ( trim($dataanswer) != '' ) {
|
||||||
$answer = new stdClass;
|
$answer = new stdClass;
|
||||||
$answer->question = $question->id;
|
$answer->question = $question->id;
|
||||||
$answer->answer = trim($dataanswer);
|
$answer->answer = trim($dataanswer);
|
||||||
$answer->fraction = $question->fraction[$key];
|
$answer->fraction = $question->fraction[$key];
|
||||||
$answer->feedback = trim($question->feedback[$key]);
|
$answer->feedbackformat = $question->feedback[$key]['format'];
|
||||||
|
|
||||||
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||||
$answer->id = $oldanswer->id;
|
$answer->id = $oldanswer->id;
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback[$key]['text']));
|
||||||
$DB->update_record("question_answers", $answer);
|
$DB->update_record("question_answers", $answer);
|
||||||
} else { // This is a completely new answer
|
} else { // This is a completely new answer
|
||||||
|
$answer->feedback = '';
|
||||||
$answer->id = $DB->insert_record("question_answers", $answer);
|
$answer->id = $DB->insert_record("question_answers", $answer);
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback[$key]['text']));
|
||||||
|
$DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the options object
|
// Set up the options object
|
||||||
|
@ -99,82 +114,82 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isset($question->import_process)&&$question->import_process) {
|
||||||
if( isset($question->import_process)&&$question->import_process){
|
|
||||||
$this->import_datasets($question);
|
$this->import_datasets($question);
|
||||||
}else {
|
} else {
|
||||||
//save datasets and datatitems from form i.e in question
|
//save datasets and datatitems from form i.e in question
|
||||||
// $datasetdefs = $this->get_dataset_definitions($question->id, array());
|
// $datasetdefs = $this->get_dataset_definitions($question->id, array());
|
||||||
$question->dataset = $question->datasetdef ;
|
$question->dataset = $question->datasetdef ;
|
||||||
// $this->save_dataset_definitions($question);
|
// $this->save_dataset_definitions($question);
|
||||||
// Save datasets
|
// Save datasets
|
||||||
$datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
|
$datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
|
||||||
$tmpdatasets = array_flip($question->dataset);
|
$tmpdatasets = array_flip($question->dataset);
|
||||||
$defids = array_keys($datasetdefinitions);
|
$defids = array_keys($datasetdefinitions);
|
||||||
$datasetdefs = array();
|
$datasetdefs = array();
|
||||||
foreach ($defids as $defid) {
|
foreach ($defids as $defid) {
|
||||||
$datasetdef = &$datasetdefinitions[$defid];
|
$datasetdef = &$datasetdefinitions[$defid];
|
||||||
if (isset($datasetdef->id)) {
|
if (isset($datasetdef->id)) {
|
||||||
if (!isset($tmpdatasets[$defid])) {
|
if (!isset($tmpdatasets[$defid])) {
|
||||||
// This dataset is not used any more, delete it
|
// This dataset is not used any more, delete it
|
||||||
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $datasetdef->id));
|
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $datasetdef->id));
|
||||||
// if ($datasetdef->category == 0) { // Question local dataset
|
// if ($datasetdef->category == 0) { // Question local dataset
|
||||||
$DB->delete_records('question_dataset_definitions', array('id' => $datasetdef->id));
|
$DB->delete_records('question_dataset_definitions', array('id' => $datasetdef->id));
|
||||||
$DB->delete_records('question_dataset_items', array('definition' => $datasetdef->id));
|
$DB->delete_records('question_dataset_items', array('definition' => $datasetdef->id));
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
// This has already been saved or just got deleted
|
// This has already been saved or just got deleted
|
||||||
|
unset($datasetdefinitions[$defid]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$datasetdef->id = $DB->insert_record('question_dataset_definitions', $datasetdef);
|
||||||
|
$datasetdefs[]= clone($datasetdef);
|
||||||
|
$questiondataset = new stdClass;
|
||||||
|
$questiondataset->question = $question->id;
|
||||||
|
$questiondataset->datasetdefinition = $datasetdef->id;
|
||||||
|
$DB->insert_record('question_datasets', $questiondataset);
|
||||||
unset($datasetdefinitions[$defid]);
|
unset($datasetdefinitions[$defid]);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
$datasetdef->id = $DB->insert_record('question_dataset_definitions', $datasetdef);
|
// Remove local obsolete datasets as well as relations
|
||||||
$datasetdefs[]= clone($datasetdef);
|
// to datasets in other categories:
|
||||||
$questiondataset = new stdClass;
|
if (!empty($datasetdefinitions)) {
|
||||||
$questiondataset->question = $question->id;
|
foreach ($datasetdefinitions as $def) {
|
||||||
$questiondataset->datasetdefinition = $datasetdef->id;
|
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $def->id));
|
||||||
$DB->insert_record('question_datasets', $questiondataset);
|
if ($def->category == 0) { // Question local dataset
|
||||||
unset($datasetdefinitions[$defid]);
|
$DB->delete_records('question_dataset_definitions', array('id' => $def->id));
|
||||||
}
|
$DB->delete_records('question_dataset_items', array('definition' => $def->id));
|
||||||
// Remove local obsolete datasets as well as relations
|
}
|
||||||
// to datasets in other categories:
|
}
|
||||||
if (!empty($datasetdefinitions)) {
|
}
|
||||||
foreach ($datasetdefinitions as $def) {
|
$datasetdefs = $this->get_dataset_definitions($question->id, $question->dataset);
|
||||||
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $def->id));
|
// Handle adding and removing of dataset items
|
||||||
if ($def->category == 0) { // Question local dataset
|
$i = 1;
|
||||||
$DB->delete_records('question_dataset_definitions', array('id' => $def->id));
|
ksort($question->definition);
|
||||||
$DB->delete_records('question_dataset_items', array('definition' => $def->id));
|
foreach ($question->definition as $key => $defid) {
|
||||||
|
$addeditem = new stdClass();
|
||||||
|
$addeditem->definition = $datasetdefs[$defid]->id;
|
||||||
|
$addeditem->value = $question->number[$i];
|
||||||
|
$addeditem->itemnumber = ceil($i / count($datasetdefs));
|
||||||
|
if (empty($question->makecopy) && $question->itemid[$i]) {
|
||||||
|
// Reuse any previously used record
|
||||||
|
$addeditem->id = $question->itemid[$i];
|
||||||
|
$DB->update_record('question_dataset_items', $addeditem);
|
||||||
|
} else {
|
||||||
|
$DB->insert_record('question_dataset_items', $addeditem);
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
$maxnumber = -1;
|
||||||
|
if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber){
|
||||||
|
$maxnumber = $addeditem->itemnumber;
|
||||||
|
foreach ($datasetdefs as $key => $newdef) {
|
||||||
|
if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) {
|
||||||
|
$newdef->itemcount = $maxnumber;
|
||||||
|
// Save the new value for options
|
||||||
|
$DB->update_record('question_dataset_definitions', $newdef);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$datasetdefs = $this->get_dataset_definitions($question->id, $question->dataset);
|
|
||||||
// Handle adding and removing of dataset items
|
|
||||||
$i = 1;
|
|
||||||
ksort($question->definition);
|
|
||||||
foreach ($question->definition as $key => $defid) {
|
|
||||||
$addeditem = new stdClass();
|
|
||||||
$addeditem->definition = $datasetdefs[$defid]->id;
|
|
||||||
$addeditem->value = $question->number[$i];
|
|
||||||
$addeditem->itemnumber = ceil($i / count($datasetdefs));
|
|
||||||
if (empty($question->makecopy) && $question->itemid[$i]) {
|
|
||||||
// Reuse any previously used record
|
|
||||||
$addeditem->id = $question->itemid[$i];
|
|
||||||
$DB->update_record('question_dataset_items', $addeditem);
|
|
||||||
} else {
|
|
||||||
$DB->insert_record('question_dataset_items', $addeditem);
|
|
||||||
}
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber){
|
|
||||||
$maxnumber = $addeditem->itemnumber;
|
|
||||||
foreach ($datasetdefs as $key => $newdef) {
|
|
||||||
if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) {
|
|
||||||
$newdef->itemcount = $maxnumber;
|
|
||||||
// Save the new value for options
|
|
||||||
$DB->update_record('question_dataset_definitions', $newdef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Report any problems.
|
// Report any problems.
|
||||||
//convert to calculated
|
//convert to calculated
|
||||||
if(!empty($question->makecopy) && !empty($question->convert)) {
|
if(!empty($question->makecopy) && !empty($question->convert)) {
|
||||||
|
@ -190,39 +205,34 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function finished_edit_wizard(&$form) {
|
function finished_edit_wizard(&$form) {
|
||||||
return true ; //isset($form->backtoquiz);
|
return true ; //isset($form->backtoquiz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this version save the available data at the different steps of the question editing process
|
* this version save the available data at the different steps of the question editing process
|
||||||
* without using global $SESSION as storage between steps
|
* without using global $SESSION as storage between steps
|
||||||
* at the first step $wizardnow = 'question'
|
* at the first step $wizardnow = 'question'
|
||||||
* when creating a new question
|
* when creating a new question
|
||||||
* when modifying a question
|
* when modifying a question
|
||||||
* when copying as a new question
|
* when copying as a new question
|
||||||
* the general parameters and answers are saved using parent::save_question
|
* the general parameters and answers are saved using parent::save_question
|
||||||
* then the datasets are prepared and saved
|
* then the datasets are prepared and saved
|
||||||
* at the second step $wizardnow = 'datasetdefinitions'
|
* at the second step $wizardnow = 'datasetdefinitions'
|
||||||
* the datadefs final type are defined as private, category or not a datadef
|
* the datadefs final type are defined as private, category or not a datadef
|
||||||
* at the third step $wizardnow = 'datasetitems'
|
* at the third step $wizardnow = 'datasetitems'
|
||||||
* the datadefs parameters and the data items are created or defined
|
* the datadefs parameters and the data items are created or defined
|
||||||
*
|
*
|
||||||
* @param object question
|
* @param object question
|
||||||
* @param object $form
|
* @param object $form
|
||||||
* @param int $course
|
* @param int $course
|
||||||
* @param PARAM_ALPHA $wizardnow should be added as we are coming from question2.php
|
* @param PARAM_ALPHA $wizardnow should be added as we are coming from question2.php
|
||||||
*/
|
*/
|
||||||
function save_question($question, $form, $course) {
|
function save_question($question, $form, $course) {
|
||||||
$question = default_questiontype::save_question($question, $form, $course);
|
$question = default_questiontype::save_question($question, $form, $course);
|
||||||
return $question;
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function custom_generator_tools_part(&$mform, $idx, $j){
|
function custom_generator_tools_part(&$mform, $idx, $j){
|
||||||
|
|
||||||
$minmaxgrp = array();
|
$minmaxgrp = array();
|
||||||
|
@ -247,14 +257,14 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
$strheader = "";
|
$strheader = "";
|
||||||
$delimiter = '';
|
$delimiter = '';
|
||||||
|
|
||||||
// $answers = $question->options->answers;
|
// $answers = $question->options->answers;
|
||||||
|
|
||||||
foreach ($answers as $key => $answer) {
|
foreach ($answers as $key => $answer) {
|
||||||
/* if (is_string($answer)) {
|
/* if (is_string($answer)) {
|
||||||
$strheader .= $delimiter.$answer;
|
$strheader .= $delimiter.$answer;
|
||||||
} else {*/
|
} else {*/
|
||||||
$strheader .= $delimiter.$answer->answer;
|
$strheader .= $delimiter.$answer->answer;
|
||||||
// }
|
// }
|
||||||
$delimiter = '<br/><br/><br/>';
|
$delimiter = '<br/><br/><br/>';
|
||||||
}
|
}
|
||||||
return $strheader;
|
return $strheader;
|
||||||
|
@ -262,18 +272,18 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
|
|
||||||
function tolerance_types() {
|
function tolerance_types() {
|
||||||
return array('1' => get_string('relative', 'quiz'),
|
return array('1' => get_string('relative', 'quiz'),
|
||||||
'2' => get_string('nominal', 'quiz'),
|
'2' => get_string('nominal', 'quiz'),
|
||||||
// '3' => get_string('geometric', 'quiz')
|
// '3' => get_string('geometric', 'quiz')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataset_options($form, $name, $mandatory=true,$renameabledatasets=false) {
|
function dataset_options($form, $name, $mandatory=true,$renameabledatasets=false) {
|
||||||
// Takes datasets from the parent implementation but
|
// Takes datasets from the parent implementation but
|
||||||
// filters options that are currently not accepted by calculated
|
// filters options that are currently not accepted by calculated
|
||||||
// It also determines a default selection...
|
// It also determines a default selection...
|
||||||
//$renameabledatasets not implemented anmywhere
|
//$renameabledatasets not implemented anmywhere
|
||||||
list($options, $selected) = $this->dataset_options_from_database($form, $name,'','qtype_calculated');
|
list($options, $selected) = $this->dataset_options_from_database($form, $name,'','qtype_calculated');
|
||||||
// list($options, $selected) = $this->dataset_optionsa($form, $name);
|
// list($options, $selected) = $this->dataset_optionsa($form, $name);
|
||||||
|
|
||||||
foreach ($options as $key => $whatever) {
|
foreach ($options as $key => $whatever) {
|
||||||
if (!preg_match('~^1-~', $key) && $key != '0') {
|
if (!preg_match('~^1-~', $key) && $key != '0') {
|
||||||
|
@ -282,7 +292,7 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
}
|
}
|
||||||
if (!$selected) {
|
if (!$selected) {
|
||||||
if ($mandatory){
|
if ($mandatory){
|
||||||
$selected = "1-0-$name"; // Default
|
$selected = "1-0-$name"; // Default
|
||||||
}else {
|
}else {
|
||||||
$selected = "0"; // Default
|
$selected = "0"; // Default
|
||||||
}
|
}
|
||||||
|
@ -291,53 +301,123 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs all the code required to set up and save an essay question for testing purposes.
|
* Runs all the code required to set up and save an essay question for testing purposes.
|
||||||
* Alternate DB table prefix may be used to facilitate data deletion.
|
* Alternate DB table prefix may be used to facilitate data deletion.
|
||||||
*/
|
*/
|
||||||
function generate_test($name, $courseid = null) {
|
function generate_test($name, $courseid = null) {
|
||||||
global $DB;
|
global $DB;
|
||||||
list($form, $question) = parent::generate_test($name, $courseid);
|
list($form, $question) = parent::generate_test($name, $courseid);
|
||||||
$form->feedback = 1;
|
$form->feedback = 1;
|
||||||
$form->multiplier = array(1, 1);
|
$form->multiplier = array(1, 1);
|
||||||
$form->shuffleanswers = 1;
|
$form->shuffleanswers = 1;
|
||||||
$form->noanswers = 1;
|
$form->noanswers = 1;
|
||||||
$form->qtype ='calculatedsimple';
|
$form->qtype ='calculatedsimple';
|
||||||
$question->qtype ='calculatedsimple';
|
$question->qtype ='calculatedsimple';
|
||||||
$form->answers = array('{a} + {b}');
|
$form->answers = array('{a} + {b}');
|
||||||
$form->fraction = array(1);
|
$form->fraction = array(1);
|
||||||
$form->tolerance = array(0.01);
|
$form->tolerance = array(0.01);
|
||||||
$form->tolerancetype = array(1);
|
$form->tolerancetype = array(1);
|
||||||
$form->correctanswerlength = array(2);
|
$form->correctanswerlength = array(2);
|
||||||
$form->correctanswerformat = array(1);
|
$form->correctanswerformat = array(1);
|
||||||
$form->questiontext = "What is {a} + {b}?";
|
$form->questiontext = "What is {a} + {b}?";
|
||||||
|
|
||||||
if ($courseid) {
|
if ($courseid) {
|
||||||
$course = $DB->get_record('course', array('id'=> $courseid));
|
$course = $DB->get_record('course', array('id'=> $courseid));
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_question = $this->save_question($question, $form, $course);
|
$new_question = $this->save_question($question, $form, $course);
|
||||||
|
|
||||||
$dataset_form = new stdClass();
|
$dataset_form = new stdClass();
|
||||||
$dataset_form->nextpageparam["forceregeneration"]= 1;
|
$dataset_form->nextpageparam["forceregeneration"]= 1;
|
||||||
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
||||||
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
||||||
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
||||||
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
||||||
$dataset_form->itemid = array(1 => '' , 2 => '');
|
$dataset_form->itemid = array(1 => '' , 2 => '');
|
||||||
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
||||||
$dataset_form->definition = array(1 => "1-0-a",
|
$dataset_form->definition = array(1 => "1-0-a",
|
||||||
2 => "1-0-b");
|
2 => "1-0-b");
|
||||||
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
||||||
$dataset_form->addbutton = 1;
|
$dataset_form->addbutton = 1;
|
||||||
$dataset_form->selectadd = 1;
|
$dataset_form->selectadd = 1;
|
||||||
$dataset_form->courseid = $courseid;
|
$dataset_form->courseid = $courseid;
|
||||||
$dataset_form->cmid = 0;
|
$dataset_form->cmid = 0;
|
||||||
$dataset_form->id = $new_question->id;
|
$dataset_form->id = $new_question->id;
|
||||||
$this->save_dataset_items($new_question, $dataset_form);
|
$this->save_dataset_items($new_question, $dataset_form);
|
||||||
|
|
||||||
return $new_question;
|
return $new_question;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
$component = 'question';
|
||||||
|
$filearea = 'feedback';
|
||||||
|
foreach ($oldanswers as $answer) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$component = 'qtype_calculatedsimple';
|
||||||
|
$filearea = 'feedback';
|
||||||
|
$filearea = 'instruction';
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
$itemid = reset($args);
|
||||||
|
if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||||
|
|
||||||
|
// check if answer id exists
|
||||||
|
$result = $options->feedback && array_key_exists($itemid, $question->options->answers);
|
||||||
|
if (!$result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// check response
|
||||||
|
if (!$this->check_response($question, $state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if ($filearea == 'instruction') {
|
||||||
|
// TODO: should it be display all the time like questiontext?
|
||||||
|
// check if question id exists
|
||||||
|
if ($itemid != $question->id) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//// END OF CLASS ////
|
//// END OF CLASS ////
|
||||||
|
|
||||||
|
@ -349,5 +429,3 @@ question_register_questiontype(new question_calculatedsimple_qtype());
|
||||||
if ( ! defined ("CALCULATEDSIMPLE")) {
|
if ( ! defined ("CALCULATEDSIMPLE")) {
|
||||||
define("CALCULATEDSIMPLE", "calculatedsimple");
|
define("CALCULATEDSIMPLE", "calculatedsimple");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the description question type.
|
* Defines the editing form for the description question type.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,10 +6,6 @@
|
||||||
<div class="qtext">
|
<div class="qtext">
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php if ($generalfeedback) { ?>
|
<?php if ($generalfeedback) { ?>
|
||||||
<div class="generalfeedback">
|
<div class="generalfeedback">
|
||||||
|
|
|
@ -68,7 +68,6 @@ class description_qtype extends default_questiontype {
|
||||||
$editlink = $this->get_question_edit_link($question, $cmoptions, $options);
|
$editlink = $this->get_question_edit_link($question, $cmoptions, $options);
|
||||||
|
|
||||||
$questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
|
$questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
|
||||||
$image = get_question_image($question);
|
|
||||||
|
|
||||||
$generalfeedback = '';
|
$generalfeedback = '';
|
||||||
if ($isfinished && $options->generalfeedback) {
|
if ($isfinished && $options->generalfeedback) {
|
||||||
|
@ -91,4 +90,3 @@ class description_qtype extends default_questiontype {
|
||||||
}
|
}
|
||||||
// Register this question type with questionlib.php.
|
// Register this question type with questionlib.php.
|
||||||
question_register_questiontype(new description_qtype());
|
question_register_questiontype(new description_qtype());
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class for question editing forms.
|
* A base class for question editing forms.
|
||||||
*
|
*
|
||||||
|
@ -7,7 +23,7 @@
|
||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||||
* @package questionbank
|
* @package questionbank
|
||||||
* @subpackage questiontypes
|
* @subpackage questiontypes
|
||||||
*//** */
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form definition base class. This defines the common fields that
|
* Form definition base class. This defines the common fields that
|
||||||
|
@ -27,24 +43,44 @@ class question_edit_form extends moodleform {
|
||||||
* @var object
|
* @var object
|
||||||
*/
|
*/
|
||||||
public $question;
|
public $question;
|
||||||
|
|
||||||
public $contexts;
|
public $contexts;
|
||||||
public $category;
|
public $category;
|
||||||
public $categorycontext;
|
public $categorycontext;
|
||||||
public $coursefilesid;
|
public $coursefilesid;
|
||||||
|
|
||||||
|
/** @var object current context */
|
||||||
|
public $context;
|
||||||
|
/** @var array html editor options */
|
||||||
|
public $editoroptions;
|
||||||
|
/** @var array options to preapre draft area */
|
||||||
|
public $fileoptions;
|
||||||
|
/** @var object instance of question type */
|
||||||
|
public $instance;
|
||||||
|
|
||||||
function question_edit_form($submiturl, $question, $category, $contexts, $formeditable = true){
|
function question_edit_form($submiturl, $question, $category, $contexts, $formeditable = true){
|
||||||
|
global $DB;
|
||||||
|
|
||||||
$this->question = $question;
|
$this->question = $question;
|
||||||
|
|
||||||
$this->contexts = $contexts;
|
$this->contexts = $contexts;
|
||||||
|
|
||||||
|
$record = $DB->get_record('question_categories', array('id'=>$question->category), 'contextid');
|
||||||
|
$this->context = get_context_instance_by_id($record->contextid);
|
||||||
|
|
||||||
|
$this->editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'context'=>$this->context);
|
||||||
|
$this->fileoptions = array('subdir'=>true, 'maxfiles'=>-1, 'maxbytes'=>-1);
|
||||||
|
|
||||||
$this->category = $category;
|
$this->category = $category;
|
||||||
$this->categorycontext = get_context_instance_by_id($category->contextid);
|
$this->categorycontext = get_context_instance_by_id($category->contextid);
|
||||||
|
//** *
|
||||||
//course id or site id depending on question cat context
|
//course id or site id depending on question cat context
|
||||||
$this->coursefilesid = get_filesdir_from_context(get_context_instance_by_id($category->contextid));
|
$this->coursefilesid = get_filesdir_from_context(get_context_instance_by_id($category->contextid));
|
||||||
|
|
||||||
|
if (!empty($question->id)) {
|
||||||
|
$question->id = (int)$question->id;
|
||||||
|
//$this->instance = new
|
||||||
|
}
|
||||||
|
|
||||||
parent::moodleform($submiturl, null, 'post', '', null, $formeditable);
|
parent::moodleform($submiturl, null, 'post', '', null, $formeditable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -106,26 +142,9 @@ class question_edit_form extends moodleform {
|
||||||
$mform->setType('name', PARAM_TEXT);
|
$mform->setType('name', PARAM_TEXT);
|
||||||
$mform->addRule('name', null, 'required', null, 'client');
|
$mform->addRule('name', null, 'required', null, 'client');
|
||||||
|
|
||||||
//TODO: MDL-16094 convert to new editor element
|
$mform->addElement('editor', 'questiontext', get_string('questiontext', 'quiz'),
|
||||||
$mform->addElement('htmleditor', 'questiontext', get_string('questiontext', 'quiz'),
|
array('rows' => 15, 'course' => $this->coursefilesid), $this->editoroptions);
|
||||||
array('rows' => 15, 'course' => $this->coursefilesid));
|
|
||||||
$mform->setType('questiontext', PARAM_RAW);
|
$mform->setType('questiontext', PARAM_RAW);
|
||||||
//$mform->addElement('format', 'questiontextformat', get_string('format'));
|
|
||||||
$mform->addElement('hidden', 'questiontextformat');
|
|
||||||
$mform->setType('questiontextformat', PARAM_INT);
|
|
||||||
|
|
||||||
make_upload_directory($this->coursefilesid); // Just in case
|
|
||||||
$coursefiles = get_directory_list("$CFG->dataroot/$this->coursefilesid", $CFG->moddata);
|
|
||||||
foreach ($coursefiles as $filename) {
|
|
||||||
if (mimeinfo("icon", $filename) == "image.gif") {
|
|
||||||
$images["$filename"] = $filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (empty($images)) {
|
|
||||||
$mform->addElement('static', 'image', get_string('imagedisplay', 'quiz'), get_string('noimagesyet'));
|
|
||||||
} else {
|
|
||||||
$mform->addElement('select', 'image', get_string('imagedisplay', 'quiz'), array_merge(array(''=>get_string('none')), $images));
|
|
||||||
}
|
|
||||||
|
|
||||||
$mform->addElement('text', 'defaultgrade', get_string('defaultgrade', 'quiz'),
|
$mform->addElement('text', 'defaultgrade', get_string('defaultgrade', 'quiz'),
|
||||||
array('size' => 3));
|
array('size' => 3));
|
||||||
|
@ -140,8 +159,8 @@ class question_edit_form extends moodleform {
|
||||||
$mform->addHelpButton('penalty', 'penaltyfactor', 'question');
|
$mform->addHelpButton('penalty', 'penaltyfactor', 'question');
|
||||||
$mform->setDefault('penalty', 0.1);
|
$mform->setDefault('penalty', 0.1);
|
||||||
|
|
||||||
$mform->addElement('htmleditor', 'generalfeedback', get_string('generalfeedback', 'quiz'),
|
$mform->addElement('editor', 'generalfeedback', get_string('generalfeedback', 'quiz'),
|
||||||
array('rows' => 10, 'course' => $this->coursefilesid));
|
array('rows' => 10, 'course' => $this->coursefilesid), $this->editoroptions);
|
||||||
$mform->setType('generalfeedback', PARAM_RAW);
|
$mform->setType('generalfeedback', PARAM_RAW);
|
||||||
$mform->addHelpButton('generalfeedback', 'generalfeedback', 'quiz');
|
$mform->addHelpButton('generalfeedback', 'generalfeedback', 'quiz');
|
||||||
|
|
||||||
|
@ -235,7 +254,7 @@ class question_edit_form extends moodleform {
|
||||||
$errors= parent::validation($fromform, $files);
|
$errors= parent::validation($fromform, $files);
|
||||||
if (empty($fromform->makecopy) && isset($this->question->id)
|
if (empty($fromform->makecopy) && isset($this->question->id)
|
||||||
&& ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew)
|
&& ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew)
|
||||||
&& empty($fromform->usecurrentcat) && !$this->question->formoptions->canmove){
|
&& empty($fromform->usecurrentcat) && !$this->question->formoptions->canmove) {
|
||||||
$errors['currentgrp'] = get_string('nopermissionmove', 'question');
|
$errors['currentgrp'] = get_string('nopermissionmove', 'question');
|
||||||
}
|
}
|
||||||
return $errors;
|
return $errors;
|
||||||
|
@ -264,8 +283,8 @@ class question_edit_form extends moodleform {
|
||||||
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
||||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
||||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
$repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'),
|
||||||
array('course' => $this->coursefilesid));
|
array('course' => $this->coursefilesid), $this->editoroptions);
|
||||||
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
||||||
$repeatedoptions['fraction']['default'] = 0;
|
$repeatedoptions['fraction']['default'] = 0;
|
||||||
$answersoption = 'answers';
|
$answersoption = 'answers';
|
||||||
|
@ -302,9 +321,33 @@ class question_edit_form extends moodleform {
|
||||||
|
|
||||||
function set_data($question) {
|
function set_data($question) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
if (empty($question->image)){
|
// prepare question text
|
||||||
unset($question->image);
|
$draftid = file_get_submitted_draft_itemid('questiontext');
|
||||||
|
|
||||||
|
if (!empty($question->questiontext)) {
|
||||||
|
$questiontext = $question->questiontext;
|
||||||
|
} else {
|
||||||
|
$questiontext = '';
|
||||||
}
|
}
|
||||||
|
$questiontext = file_prepare_draft_area($draftid, $this->context->id, 'question', 'questiontext', empty($question->id)?null:(int)$question->id, null, $questiontext);
|
||||||
|
|
||||||
|
$question->questiontext = array();
|
||||||
|
$question->questiontext['text'] = $questiontext;
|
||||||
|
$question->questiontext['format'] = empty($question->questiontextformat) ? editors_get_preferred_format() : $question->questiontextformat;
|
||||||
|
$question->questiontext['itemid'] = $draftid;
|
||||||
|
|
||||||
|
// prepare general feedback
|
||||||
|
$draftid = file_get_submitted_draft_itemid('generalfeedback');
|
||||||
|
|
||||||
|
if (empty($question->generalfeedback)) {
|
||||||
|
$question->generalfeedback = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$feedback = file_prepare_draft_area($draftid, $this->context->id, 'question', 'generalfeedback', empty($question->id)?null:(int)$question->id, null, $question->generalfeedback);
|
||||||
|
$question->generalfeedback = array();
|
||||||
|
$question->generalfeedback['text'] = $feedback;
|
||||||
|
$question->generalfeedback['format'] = empty($question->generalfeedbackformat) ? editors_get_preferred_format() : $question->generalfeedbackformat;
|
||||||
|
$question->generalfeedback['itemid'] = $draftid;
|
||||||
|
|
||||||
// Remove unnecessary trailing 0s form grade fields.
|
// Remove unnecessary trailing 0s form grade fields.
|
||||||
if (isset($question->defaultgrade)) {
|
if (isset($question->defaultgrade)) {
|
||||||
|
@ -324,10 +367,20 @@ class question_edit_form extends moodleform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// subclass adds data_preprocessing code here
|
||||||
|
$question = $this->data_preprocessing($question);
|
||||||
parent::set_data($question);
|
parent::set_data($question);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any preprocessing needed for the settings form for the question type
|
||||||
|
*
|
||||||
|
* @param array $question - array to fill in with the default values
|
||||||
|
*/
|
||||||
|
function data_preprocessing($question) {
|
||||||
|
return $question;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this in the subclass to question type name.
|
* Override this in the subclass to question type name.
|
||||||
* @return the question type name, should be the same as the name() method in the question type class.
|
* @return the question type name, should be the same as the name() method in the question type class.
|
||||||
|
@ -336,5 +389,3 @@ class question_edit_form extends moodleform {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
|
|
||||||
<div class="ablock clearfix">
|
<div class="ablock clearfix">
|
||||||
<div class="prompt">
|
<div class="prompt">
|
||||||
<?php echo $stranswer; ?>
|
<?php echo $stranswer; ?>
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the essay question type.
|
* Defines the editing form for the essay question type.
|
||||||
*
|
*
|
||||||
|
@ -19,8 +35,7 @@ class question_edit_essay_form extends question_edit_form {
|
||||||
* @param MoodleQuickForm $mform the form being built.
|
* @param MoodleQuickForm $mform the form being built.
|
||||||
*/
|
*/
|
||||||
function definition_inner(&$mform) {
|
function definition_inner(&$mform) {
|
||||||
$mform->addElement('htmleditor', 'feedback', get_string("feedback", "quiz"),
|
$mform->addElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
|
||||||
array('course' => $this->coursefilesid));
|
|
||||||
$mform->setType('feedback', PARAM_RAW);
|
$mform->setType('feedback', PARAM_RAW);
|
||||||
|
|
||||||
$mform->addElement('hidden', 'fraction', 0);
|
$mform->addElement('hidden', 'fraction', 0);
|
||||||
|
@ -32,17 +47,29 @@ class question_edit_essay_form extends question_edit_form {
|
||||||
$mform->setType('penalty', PARAM_RAW);
|
$mform->setType('penalty', PARAM_RAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
if (!empty($question->options) && !empty($question->options->answers)) {
|
if (!empty($question->options) && !empty($question->options->answers)) {
|
||||||
$answer = reset($question->options->answers);
|
$answer = reset($question->options->answers);
|
||||||
$question->feedback = $answer->feedback;
|
$question->feedback = array();
|
||||||
|
$draftid = file_get_submitted_draft_itemid('feedback');
|
||||||
|
$question->feedback['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'question', // component
|
||||||
|
'answerfeedback', // filarea
|
||||||
|
!empty($answer->id)?(int)$answer->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$answer->feedback // text
|
||||||
|
);
|
||||||
|
$question->feedback['text'] = $answer->feedback;
|
||||||
|
$question->feedback['format'] = $answer->feedbackformat;
|
||||||
|
$question->feedback['itemid'] = $draftid;
|
||||||
}
|
}
|
||||||
$question->penalty = 0;
|
$question->penalty = 0;
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
return 'essay';
|
return 'essay';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
question/type/essay/lib.php
Normal file
31
question/type/essay/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_essay_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_essay', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -1,5 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
/// ESSAY ///
|
/// ESSAY ///
|
||||||
/////////////////
|
/////////////////
|
||||||
|
@ -21,6 +36,7 @@ class question_essay_qtype extends default_questiontype {
|
||||||
|
|
||||||
function save_question_options($question) {
|
function save_question_options($question) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
$context = $question->context;
|
||||||
$result = true;
|
$result = true;
|
||||||
$update = true;
|
$update = true;
|
||||||
$answer = $DB->get_record("question_answers", array("question" => $question->id));
|
$answer = $DB->get_record("question_answers", array("question" => $question->id));
|
||||||
|
@ -29,13 +45,20 @@ class question_essay_qtype extends default_questiontype {
|
||||||
$answer->question = $question->id;
|
$answer->question = $question->id;
|
||||||
$update = false;
|
$update = false;
|
||||||
}
|
}
|
||||||
$answer->answer = $question->feedback;
|
$answer->feedbackformat = $question->feedback['format'];
|
||||||
$answer->feedback = $question->feedback;
|
$answer->answerformat = $question->feedback['format'];
|
||||||
$answer->fraction = $question->fraction;
|
$answer->fraction = $question->fraction;
|
||||||
if ($update) {
|
if ($update) {
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback['text']));
|
||||||
|
$answer->answer = $answer->feedback;
|
||||||
$DB->update_record("question_answers", $answer);
|
$DB->update_record("question_answers", $answer);
|
||||||
} else {
|
} else {
|
||||||
$answer->id = $DB->insert_record("question_answers", $answer);
|
$answer->feedback = $question->feedback['text'];
|
||||||
|
$answer->answer = $answer->feedback;
|
||||||
|
$answer->id = $DB->insert_record('question_answers', $answer);
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback['text']));
|
||||||
|
$answer->answer = $answer->feedback;
|
||||||
|
$DB->update_record('question_answers', $answer);
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@ -43,12 +66,14 @@ class question_essay_qtype extends default_questiontype {
|
||||||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
|
||||||
$answers = &$question->options->answers;
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
|
||||||
|
$answers = &$question->options->answers;
|
||||||
|
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
||||||
|
|
||||||
// Only use the rich text editor for the first essay question on a page.
|
// Only use the rich text editor for the first essay question on a page.
|
||||||
|
|
||||||
$formatoptions = new stdClass;
|
$formatoptions = new stdClass;
|
||||||
$formatoptions->noclean = true;
|
$formatoptions->noclean = true;
|
||||||
$formatoptions->para = false;
|
$formatoptions->para = false;
|
||||||
|
|
||||||
|
@ -60,13 +85,12 @@ class question_essay_qtype extends default_questiontype {
|
||||||
$question->questiontextformat,
|
$question->questiontextformat,
|
||||||
$formatoptions, $cmoptions->course);
|
$formatoptions, $cmoptions->course);
|
||||||
|
|
||||||
$image = get_question_image($question);
|
|
||||||
|
|
||||||
// feedback handling
|
// feedback handling
|
||||||
$feedback = '';
|
$feedback = '';
|
||||||
if ($options->feedback && !empty($answers)) {
|
if ($options->feedback && !empty($answers)) {
|
||||||
foreach ($answers as $answer) {
|
foreach ($answers as $answer) {
|
||||||
$feedback = format_text($answer->feedback, '', $formatoptions, $cmoptions->course);
|
$feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'qtype_essay', 'feedback', array($state->attempt, $state->question), $answer->id);
|
||||||
|
$feedback = format_text($feedback, $answer->feedbackformat, $formatoptions, $cmoptions->course);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +163,54 @@ class question_essay_qtype extends default_questiontype {
|
||||||
return $this->save_question($question, $form, $course);
|
return $this->save_question($question, $form, $course);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
$component = 'question';
|
||||||
|
$filearea = 'answerfeedback';
|
||||||
|
foreach ($oldanswers as $answer) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||||
|
|
||||||
|
$answerid = reset($args); // itemid is answer id.
|
||||||
|
$answers = &$question->options->answers;
|
||||||
|
if (isset($state->responses[''])) {
|
||||||
|
$response = $state->responses[''];
|
||||||
|
} else {
|
||||||
|
$response = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options->feedback && !empty($response);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Restore method not needed.
|
// Restore method not needed.
|
||||||
}
|
}
|
||||||
//// END OF CLASS ////
|
//// END OF CLASS ////
|
||||||
|
@ -147,4 +219,3 @@ class question_essay_qtype extends default_questiontype {
|
||||||
//// INITIATION - Without this line the question type is not in use... ///
|
//// INITIATION - Without this line the question type is not in use... ///
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
question_register_questiontype(new question_essay_qtype());
|
question_register_questiontype(new question_essay_qtype());
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<XMLDB PATH="question/type/match/db" VERSION="20060812" COMMENT="XMLDB file for Moodle question/type/match">
|
<XMLDB PATH="question/type/match/db" VERSION="20100721" COMMENT="XMLDB file for Moodle question/type/match"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
||||||
|
>
|
||||||
<TABLES>
|
<TABLES>
|
||||||
<TABLE NAME="question_match" COMMENT="Defines fixed matching questions" NEXT="question_match_sub">
|
<TABLE NAME="question_match" COMMENT="Defines fixed matching questions" NEXT="question_match_sub">
|
||||||
<FIELDS>
|
<FIELDS>
|
||||||
|
@ -18,8 +21,9 @@
|
||||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="code"/>
|
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="code"/>
|
||||||
<FIELD NAME="code" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Should this point to parent question_match-&gt;id ?" PREVIOUS="id" NEXT="question"/>
|
<FIELD NAME="code" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Should this point to parent question_match-&gt;id ?" PREVIOUS="id" NEXT="question"/>
|
||||||
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="code" NEXT="questiontext"/>
|
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="code" NEXT="questiontext"/>
|
||||||
<FIELD NAME="questiontext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="answertext"/>
|
<FIELD NAME="questiontext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="questiontextformat"/>
|
||||||
<FIELD NAME="answertext" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="questiontext"/>
|
<FIELD NAME="questiontextformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="questiontext" NEXT="answertext"/>
|
||||||
|
<FIELD NAME="answertext" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="questiontextformat"/>
|
||||||
</FIELDS>
|
</FIELDS>
|
||||||
<KEYS>
|
<KEYS>
|
||||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
||||||
|
@ -27,4 +31,4 @@
|
||||||
</KEYS>
|
</KEYS>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
</TABLES>
|
</TABLES>
|
||||||
</XMLDB>
|
</XMLDB>
|
58
question/type/match/db/upgrade.php
Normal file
58
question/type/match/db/upgrade.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file keeps track of upgrades to
|
||||||
|
// the match qtype plugin
|
||||||
|
//
|
||||||
|
// Sometimes, changes between versions involve
|
||||||
|
// alterations to database structures and other
|
||||||
|
// major things that may break installations.
|
||||||
|
//
|
||||||
|
// The upgrade function in this file will attempt
|
||||||
|
// to perform all the necessary actions to upgrade
|
||||||
|
// your older installation to the current version.
|
||||||
|
//
|
||||||
|
// If there's something it cannot do itself, it
|
||||||
|
// will tell you what you need to do.
|
||||||
|
//
|
||||||
|
// The commands in here will all be database-neutral,
|
||||||
|
// using the methods of database_manager class
|
||||||
|
//
|
||||||
|
// Please do not forget to use upgrade_set_timeout()
|
||||||
|
// before any action that may take longer time to finish.
|
||||||
|
|
||||||
|
function xmldb_qtype_match_upgrade($oldversion) {
|
||||||
|
global $CFG, $DB, $QTYPES;
|
||||||
|
|
||||||
|
$dbman = $DB->get_manager();
|
||||||
|
|
||||||
|
if ($oldversion < 2009072100) {
|
||||||
|
|
||||||
|
// Define field questiontextformat to be added to question_match_sub
|
||||||
|
$table = new xmldb_table('question_match_sub');
|
||||||
|
$field = new xmldb_field('questiontextformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'questiontext');
|
||||||
|
|
||||||
|
// Conditionally launch add field questiontextformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rs = $DB->get_recordset('question_match_sub');
|
||||||
|
foreach ($rs as $record) {
|
||||||
|
if ($CFG->texteditors !== 'textarea') {
|
||||||
|
if (!empty($record->questiontext)) {
|
||||||
|
$record->questiontext = text_to_html($record->questiontext);
|
||||||
|
}
|
||||||
|
$record->questiontextformat = FORMAT_HTML;
|
||||||
|
} else {
|
||||||
|
$record->questiontextformat = FORMAT_MOODLE;
|
||||||
|
}
|
||||||
|
$DB->update_record('question_match_sub', $record);
|
||||||
|
}
|
||||||
|
$rs->close();
|
||||||
|
|
||||||
|
// match savepoint reached
|
||||||
|
upgrade_plugin_savepoint(true, 2009072100, 'qtype', 'match');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -2,10 +2,6 @@
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
|
|
||||||
<div class="ablock clearfix">
|
<div class="ablock clearfix">
|
||||||
|
|
||||||
<table class="answer">
|
<table class="answer">
|
||||||
|
|
|
@ -17,7 +17,7 @@ class question_edit_match_form extends question_edit_form {
|
||||||
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
||||||
$repeated = array();
|
$repeated = array();
|
||||||
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
||||||
$repeated[] =& $mform->createElement('textarea', 'subquestions', get_string('question', 'quiz'), array('cols'=>40, 'rows'=>3));
|
$repeated[] =& $mform->createElement('editor', 'subquestions', get_string('question', 'quiz'), null, $this->editoroptions);
|
||||||
$repeated[] =& $mform->createElement('text', 'subanswers', get_string('answer', 'quiz'), array('size'=>50));
|
$repeated[] =& $mform->createElement('text', 'subanswers', get_string('answer', 'quiz'), array('size'=>50));
|
||||||
$repeatedoptions['subquestions']['type'] = PARAM_RAW;
|
$repeatedoptions['subquestions']['type'] = PARAM_RAW;
|
||||||
$repeatedoptions['subanswers']['type'] = PARAM_TEXT;
|
$repeatedoptions['subanswers']['type'] = PARAM_TEXT;
|
||||||
|
@ -41,21 +41,35 @@ class question_edit_match_form extends question_edit_form {
|
||||||
$this->add_per_answer_fields($mform, get_string('questionno', 'quiz', '{no}'), 0);
|
$this->add_per_answer_fields($mform, get_string('questionno', 'quiz', '{no}'), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
if (isset($question->options)){
|
if (isset($question->options)) {
|
||||||
$subquestions = $question->options->subquestions;
|
$subquestions = $question->options->subquestions;
|
||||||
if (count($subquestions)) {
|
if (count($subquestions)) {
|
||||||
$key = 0;
|
$key = 0;
|
||||||
foreach ($subquestions as $subquestion){
|
foreach ($subquestions as $subquestion){
|
||||||
$default_values['subanswers['.$key.']'] = $subquestion->answertext;
|
$default_values['subanswers['.$key.']'] = $subquestion->answertext;
|
||||||
$default_values['subquestions['.$key.']'] = $subquestion->questiontext;
|
|
||||||
|
$draftid = file_get_submitted_draft_itemid('subquestions['.$key.']');
|
||||||
|
$default_values['subquestions['.$key.']'] = array();
|
||||||
|
$default_values['subquestions['.$key.']']['format'] = $subquestion->questiontextformat;
|
||||||
|
$default_values['subquestions['.$key.']']['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'qtype_match', // component
|
||||||
|
'subquestion', // filarea
|
||||||
|
!empty($subquestion->id)?(int)$subquestion->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$subquestion->questiontext // text
|
||||||
|
);
|
||||||
|
$default_values['subquestions['.$key.']']['itemid'] = $draftid;
|
||||||
|
|
||||||
$key++;
|
$key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
||||||
$question = (object)((array)$question + $default_values);
|
$question = (object)((array)$question + $default_values);
|
||||||
}
|
}
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
|
@ -69,7 +83,7 @@ class question_edit_match_form extends question_edit_form {
|
||||||
$questioncount = 0;
|
$questioncount = 0;
|
||||||
$answercount = 0;
|
$answercount = 0;
|
||||||
foreach ($questions as $key => $question){
|
foreach ($questions as $key => $question){
|
||||||
$trimmedquestion = trim($question);
|
$trimmedquestion = trim($question['text']);
|
||||||
$trimmedanswer = trim($answers[$key]);
|
$trimmedanswer = trim($answers[$key]);
|
||||||
if ($trimmedquestion != ''){
|
if ($trimmedquestion != ''){
|
||||||
$questioncount++;
|
$questioncount++;
|
||||||
|
|
31
question/type/match/lib.php
Normal file
31
question/type/match/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_match_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $DB, $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_match', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -1,5 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
/// MATCH ///
|
/// MATCH ///
|
||||||
/////////////
|
/////////////
|
||||||
|
@ -24,6 +39,7 @@ class question_match_qtype extends default_questiontype {
|
||||||
|
|
||||||
function save_question_options($question) {
|
function save_question_options($question) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
$context = $question->context;
|
||||||
$result = new stdClass;
|
$result = new stdClass;
|
||||||
|
|
||||||
if (!$oldsubquestions = $DB->get_records("question_match_sub", array("question" => $question->id), "id ASC")) {
|
if (!$oldsubquestions = $DB->get_records("question_match_sub", array("question" => $question->id), "id ASC")) {
|
||||||
|
@ -35,24 +51,30 @@ class question_match_qtype extends default_questiontype {
|
||||||
|
|
||||||
// Insert all the new question+answer pairs
|
// Insert all the new question+answer pairs
|
||||||
foreach ($question->subquestions as $key => $questiontext) {
|
foreach ($question->subquestions as $key => $questiontext) {
|
||||||
$questiontext = trim($questiontext);
|
$itemid = $questiontext['itemid'];
|
||||||
|
$format = $questiontext['format'];
|
||||||
|
$questiontext = trim($questiontext['text']);
|
||||||
$answertext = trim($question->subanswers[$key]);
|
$answertext = trim($question->subanswers[$key]);
|
||||||
if ($questiontext != '' || $answertext != '') {
|
if ($questiontext != '' || $answertext != '') {
|
||||||
if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it
|
if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it
|
||||||
$subquestion->questiontext = $questiontext;
|
|
||||||
$subquestion->answertext = $answertext;
|
$subquestion->answertext = $answertext;
|
||||||
|
$subquestion->questiontext = file_save_draft_area_files($itemid, $context->id, 'qtype_match', 'subquestion', $subquestion->id, self::$fileoptions, $questiontext);
|
||||||
|
$subquestion->questiontextformat = $format;
|
||||||
$DB->update_record("question_match_sub", $subquestion);
|
$DB->update_record("question_match_sub", $subquestion);
|
||||||
} else {
|
} else {
|
||||||
$subquestion = new stdClass;
|
$subquestion = new stdClass;
|
||||||
// Determine a unique random code
|
// Determine a unique random code
|
||||||
$subquestion->code = rand(1,999999999);
|
$subquestion->code = rand(1, 999999999);
|
||||||
while ($DB->record_exists('question_match_sub', array('code' => $subquestion->code, 'question' => $question->id))) {
|
while ($DB->record_exists('question_match_sub', array('code' => $subquestion->code, 'question' => $question->id))) {
|
||||||
$subquestion->code = rand();
|
$subquestion->code = rand();
|
||||||
}
|
}
|
||||||
$subquestion->question = $question->id;
|
$subquestion->question = $question->id;
|
||||||
$subquestion->questiontext = $questiontext;
|
$subquestion->questiontext = $questiontext;
|
||||||
$subquestion->answertext = $answertext;
|
$subquestion->questiontextformat = $format;
|
||||||
|
$subquestion->answertext = $answertext;
|
||||||
$subquestion->id = $DB->insert_record("question_match_sub", $subquestion);
|
$subquestion->id = $DB->insert_record("question_match_sub", $subquestion);
|
||||||
|
$questiontext = file_save_draft_area_files($itemid, $context->id, 'qtype_match', 'subquestion', $subquestion->id, self::$fileoptions, $questiontext);
|
||||||
|
$DB->set_field('question_match_sub', 'questiontext', $questiontext, array('id'=>$subquestion->id));
|
||||||
}
|
}
|
||||||
$subquestions[] = $subquestion->id;
|
$subquestions[] = $subquestion->id;
|
||||||
}
|
}
|
||||||
|
@ -228,6 +250,7 @@ class question_match_qtype extends default_questiontype {
|
||||||
|
|
||||||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||||
global $CFG, $OUTPUT;
|
global $CFG, $OUTPUT;
|
||||||
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
$subquestions = $state->options->subquestions;
|
$subquestions = $state->options->subquestions;
|
||||||
$correctanswers = $this->get_correct_responses($question, $state);
|
$correctanswers = $this->get_correct_responses($question, $state);
|
||||||
$nameprefix = $question->name_prefix;
|
$nameprefix = $question->name_prefix;
|
||||||
|
@ -263,15 +286,14 @@ class question_match_qtype extends default_questiontype {
|
||||||
// Print formulation
|
// Print formulation
|
||||||
$questiontext = $this->format_text($question->questiontext,
|
$questiontext = $this->format_text($question->questiontext,
|
||||||
$question->questiontextformat, $cmoptions);
|
$question->questiontextformat, $cmoptions);
|
||||||
$image = get_question_image($question);
|
|
||||||
|
|
||||||
// Print the input controls
|
// Print the input controls
|
||||||
foreach ($subquestions as $key => $subquestion) {
|
foreach ($subquestions as $key => $subquestion) {
|
||||||
if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) {
|
if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) {
|
||||||
// Subquestion text:
|
// Subquestion text:
|
||||||
$a = new stdClass;
|
$a = new stdClass;
|
||||||
$a->text = $this->format_text($subquestion->questiontext,
|
$text = quiz_rewrite_question_urls($subquestion->questiontext, 'pluginfile.php', $context->id, 'qtype_match', 'subquestion', array($state->attempt, $state->question), $subquestion->id);
|
||||||
$question->questiontextformat, $cmoptions);
|
$a->text = $this->format_text($text, $subquestion->questiontextformat, $cmoptions);
|
||||||
|
|
||||||
// Drop-down list:
|
// Drop-down list:
|
||||||
$menuname = $nameprefix.$subquestion->id;
|
$menuname = $nameprefix.$subquestion->id;
|
||||||
|
@ -757,6 +779,53 @@ class question_match_qtype extends default_questiontype {
|
||||||
|
|
||||||
return $this->save_question($question, $form, $course);
|
return $this->save_question($question, $form, $course);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
// move files belonging to question component
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
// move files belonging to qtype_multichoice
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// process files in sub questions
|
||||||
|
if (!$subquestions = $DB->get_records('question_match_sub', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$subquestions = array();
|
||||||
|
}
|
||||||
|
$component = 'qtype_match';
|
||||||
|
$filearea = 'subquestion';
|
||||||
|
foreach ($subquestions as $sub) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $sub->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
|
||||||
|
$itemid = reset($args);
|
||||||
|
if ($filearea == 'subquestion') {
|
||||||
|
// always display quetion images
|
||||||
|
// itemid is sub question id
|
||||||
|
if ($itemid != $question->id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//// END OF CLASS ////
|
//// END OF CLASS ////
|
||||||
|
|
||||||
|
@ -764,4 +833,3 @@ class question_match_qtype extends default_questiontype {
|
||||||
//// INITIATION - Without this line the question type is not in use... ///
|
//// INITIATION - Without this line the question type is not in use... ///
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
question_register_questiontype(new question_match_qtype());
|
question_register_questiontype(new question_match_qtype());
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$plugin->version = 2006032200;
|
$plugin->version = 2009072100;
|
||||||
$plugin->requires = 2007101000;
|
$plugin->requires = 2007101000;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
|
|
||||||
<?php if ($anss) { ?>
|
<?php if ($anss) { ?>
|
||||||
<div class="ablock clearfix">
|
<div class="ablock clearfix">
|
||||||
<div class="prompt">
|
<div class="prompt">
|
||||||
|
@ -21,4 +17,4 @@
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
|
|
@ -42,7 +42,6 @@ class question_missingtype_qtype extends default_questiontype {
|
||||||
$questiontext = format_text($question->questiontext,
|
$questiontext = format_text($question->questiontext,
|
||||||
$question->questiontextformat,
|
$question->questiontextformat,
|
||||||
$formatoptions, $cmoptions->course);
|
$formatoptions, $cmoptions->course);
|
||||||
$image = get_question_image($question);
|
|
||||||
|
|
||||||
// Print each answer in a separate row if there are any
|
// Print each answer in a separate row if there are any
|
||||||
$anss = array();
|
$anss = array();
|
||||||
|
|
|
@ -15,15 +15,15 @@
|
||||||
class question_edit_multianswer_form extends question_edit_form {
|
class question_edit_multianswer_form extends question_edit_form {
|
||||||
|
|
||||||
// $questiondisplay will contain the qtype_multianswer_extract_question from the questiontext
|
// $questiondisplay will contain the qtype_multianswer_extract_question from the questiontext
|
||||||
var $questiondisplay ;
|
public $questiondisplay ;
|
||||||
// $savedquestiondisplay will contain the qtype_multianswer_extract_question from the questiontext in database
|
// $savedquestiondisplay will contain the qtype_multianswer_extract_question from the questiontext in database
|
||||||
var $savedquestion ;
|
public $savedquestion ;
|
||||||
var $savedquestiondisplay ;
|
public $savedquestiondisplay ;
|
||||||
var $used_in_quiz = false ;
|
public $used_in_quiz = false ;
|
||||||
var $qtype_change = false ;
|
public $qtype_change = false ;
|
||||||
var $negative_diff = 0 ;
|
public $negative_diff = 0 ;
|
||||||
var $nb_of_quiz = 0;
|
public $nb_of_quiz = 0;
|
||||||
var $nb_of_attempts = 0;
|
public $nb_of_attempts = 0;
|
||||||
public $confirm = 0 ;
|
public $confirm = 0 ;
|
||||||
public $reload = false ;
|
public $reload = false ;
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
}else {
|
}else {
|
||||||
$this->reload = false ;
|
$this->reload = false ;
|
||||||
}
|
}
|
||||||
// $this->question = $question;
|
// $this->question = $question;
|
||||||
$this->used_in_quiz =false;
|
$this->used_in_quiz =false;
|
||||||
// echo "<p> question <pre>";print_r($question);echo "</pre></p>";
|
// echo "<p> question <pre>";print_r($question);echo "</pre></p>";
|
||||||
if(isset($question->id) && $question->id != 0 ){
|
if(isset($question->id) && $question->id != 0 ){
|
||||||
$this->savedquestiondisplay =fullclone($question ) ;
|
$this->savedquestiondisplay =fullclone($question ) ;
|
||||||
if ($list = $DB->get_records('quiz_question_instances', array( 'question'=> $question->id))){
|
if ($list = $DB->get_records('quiz_question_instances', array( 'question'=> $question->id))){
|
||||||
|
@ -51,15 +51,9 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function definition_inner(&$mform) {
|
function definition_inner(&$mform) {
|
||||||
$mform->addElement('hidden', 'reload', 1);
|
$mform->addElement('hidden', 'reload', 1);
|
||||||
$mform->setType('reload', PARAM_INT);
|
$mform->setType('reload', PARAM_INT);
|
||||||
|
@ -69,7 +63,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
$mform->removeElement('defaultgrade');
|
$mform->removeElement('defaultgrade');
|
||||||
$this->confirm = optional_param('confirm','0', PARAM_RAW);
|
$this->confirm = optional_param('confirm','0', PARAM_RAW);
|
||||||
|
|
||||||
// display the questions from questiontext;
|
// display the questions from questiontext;
|
||||||
if ( "" != optional_param('questiontext','', PARAM_RAW)) {
|
if ( "" != optional_param('questiontext','', PARAM_RAW)) {
|
||||||
|
|
||||||
$this->questiondisplay = fullclone(qtype_multianswer_extract_question(optional_param('questiontext','', PARAM_RAW))) ;
|
$this->questiondisplay = fullclone(qtype_multianswer_extract_question(optional_param('questiontext','', PARAM_RAW))) ;
|
||||||
|
@ -80,14 +74,14 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
// question->id == 0 so no stored datasets
|
// question->id == 0 so no stored datasets
|
||||||
$this->questiondisplay = fullclone($this->savedquestiondisplay);
|
$this->questiondisplay = fullclone($this->savedquestiondisplay);
|
||||||
foreach($this->questiondisplay->options->questions as $subquestion){
|
foreach($this->questiondisplay->options->questions as $subquestion){
|
||||||
if (!empty($subquestion)){
|
if (!empty($subquestion)){
|
||||||
$subquestion->answer = array('');
|
$subquestion->answer = array('');
|
||||||
foreach($subquestion->options->answers as $ans){
|
foreach($subquestion->options->answers as $ans){
|
||||||
$subquestion->answer[]=$ans->answer ;
|
$subquestion->answer[]=$ans->answer ;
|
||||||
|
}
|
||||||
|
// $subquestion->answer = fullclone($subquestion->options->answers);
|
||||||
}
|
}
|
||||||
// $subquestion->answer = fullclone($subquestion->options->answers);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}else {
|
}else {
|
||||||
$this->questiondisplay = "";
|
$this->questiondisplay = "";
|
||||||
}
|
}
|
||||||
|
@ -97,7 +91,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
$countsavedsubquestions =0;
|
$countsavedsubquestions =0;
|
||||||
foreach($this->savedquestiondisplay->options->questions as $subquestion){
|
foreach($this->savedquestiondisplay->options->questions as $subquestion){
|
||||||
if (!empty($subquestion)){
|
if (!empty($subquestion)){
|
||||||
$countsavedsubquestions++;
|
$countsavedsubquestions++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -108,24 +102,24 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
$countsubquestions =0;
|
$countsubquestions =0;
|
||||||
foreach($this->questiondisplay->options->questions as $subquestion){
|
foreach($this->questiondisplay->options->questions as $subquestion){
|
||||||
if (!empty($subquestion)){
|
if (!empty($subquestion)){
|
||||||
$countsubquestions++;
|
$countsubquestions++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$countsubquestions =0;
|
$countsubquestions =0;
|
||||||
}
|
|
||||||
}else{
|
|
||||||
$countsubquestions =$countsavedsubquestions ;
|
|
||||||
}
|
}
|
||||||
// echo "<p> saved question $countsavedsubquestions <pre>";print_r($this->savedquestiondisplay);echo "</pre></p>";
|
}else{
|
||||||
// echo "<p> saved question $countsubquestions <pre>";print_r($this->questiondisplay);echo "</pre></p>";
|
$countsubquestions =$countsavedsubquestions ;
|
||||||
|
}
|
||||||
|
// echo "<p> saved question $countsavedsubquestions <pre>";print_r($this->savedquestiondisplay);echo "</pre></p>";
|
||||||
|
// echo "<p> saved question $countsubquestions <pre>";print_r($this->questiondisplay);echo "</pre></p>";
|
||||||
|
|
||||||
|
|
||||||
$mform->addElement('submit', 'analyzequestion', get_string('decodeverifyquestiontext','qtype_multianswer'));
|
$mform->addElement('submit', 'analyzequestion', get_string('decodeverifyquestiontext','qtype_multianswer'));
|
||||||
$mform->registerNoSubmitButton('analyzequestion');
|
$mform->registerNoSubmitButton('analyzequestion');
|
||||||
echo '<div class="ablock clearfix">';
|
echo '<div class="ablock clearfix">';
|
||||||
echo '<div class=" clearfix">';
|
echo '<div class=" clearfix">';
|
||||||
if ( $this->reload ){
|
if ( $this->reload ){
|
||||||
for ($sub =1;$sub <=$countsubquestions ;$sub++) {
|
for ($sub =1;$sub <=$countsubquestions ;$sub++) {
|
||||||
|
|
||||||
$this->editas[$sub] = 'unknown type';
|
$this->editas[$sub] = 'unknown type';
|
||||||
|
@ -135,14 +129,14 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
$this->editas[$sub] = optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW);
|
$this->editas[$sub] = optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW);
|
||||||
}
|
}
|
||||||
$storemess = '';
|
$storemess = '';
|
||||||
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
|
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
|
||||||
$this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
|
$this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
|
||||||
$this->qtype_change = true ;
|
$this->qtype_change = true ;
|
||||||
$storemess = "<font class=\"error\"> STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype]."</font >";
|
$storemess = "<font class=\"error\"> STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype]."</font >";
|
||||||
}
|
}
|
||||||
|
|
||||||
$mform->addElement('header', 'subhdr'.$sub, get_string('questionno', 'quiz',
|
$mform->addElement('header', 'subhdr'.$sub, get_string('questionno', 'quiz',
|
||||||
'{#'.$sub.'}').' '.$question_type_names[$this->questiondisplay->options->questions[$sub]->qtype].$storemess);
|
'{#'.$sub.'}').' '.$question_type_names[$this->questiondisplay->options->questions[$sub]->qtype].$storemess);
|
||||||
|
|
||||||
$mform->addElement('static', 'sub_'.$sub."_".'questiontext', get_string('questiondefinition','qtype_multianswer'),array('cols'=>60, 'rows'=>3));
|
$mform->addElement('static', 'sub_'.$sub."_".'questiontext', get_string('questiondefinition','qtype_multianswer'),array('cols'=>60, 'rows'=>3));
|
||||||
|
|
||||||
|
@ -153,16 +147,16 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
$mform->addElement('static', 'sub_'.$sub."_".'defaultgrade', get_string('defaultgrade', 'quiz'));
|
$mform->addElement('static', 'sub_'.$sub."_".'defaultgrade', get_string('defaultgrade', 'quiz'));
|
||||||
$mform->setDefault('sub_'.$sub."_".'defaultgrade',$this->questiondisplay->options->questions[$sub]->defaultgrade);
|
$mform->setDefault('sub_'.$sub."_".'defaultgrade',$this->questiondisplay->options->questions[$sub]->defaultgrade);
|
||||||
|
|
||||||
if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
|
if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
|
||||||
$mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'quiz'));
|
$mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'quiz'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->questiondisplay->options->questions[$sub]->qtype =='multichoice' ) {
|
if ($this->questiondisplay->options->questions[$sub]->qtype =='multichoice' ) {
|
||||||
$mform->addElement('static', 'sub_'.$sub."_".'layout', get_string('layout', 'qtype_multianswer'),array('cols'=>60, 'rows'=>1)) ;//, $gradeoptions);
|
$mform->addElement('static', 'sub_'.$sub."_".'layout', get_string('layout', 'qtype_multianswer'),array('cols'=>60, 'rows'=>1)) ;//, $gradeoptions);
|
||||||
}
|
}
|
||||||
foreach ($this->questiondisplay->options->questions[$sub]->answer as $key =>$ans) {
|
foreach ($this->questiondisplay->options->questions[$sub]->answer as $key =>$ans) {
|
||||||
|
|
||||||
$mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']', get_string('answer', 'quiz'), array('cols'=>60, 'rows'=>1));
|
$mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']', get_string('answer', 'quiz'), array('cols'=>60, 'rows'=>1));
|
||||||
|
|
||||||
if ($this->questiondisplay->options->questions[$sub]->qtype =='numerical' && $key == 0 ) {
|
if ($this->questiondisplay->options->questions[$sub]->qtype =='numerical' && $key == 0 ) {
|
||||||
$mform->addElement('static', 'sub_'.$sub."_".'tolerance['.$key.']', get_string('acceptederror', 'quiz')) ;//, $gradeoptions);
|
$mform->addElement('static', 'sub_'.$sub."_".'tolerance['.$key.']', get_string('acceptederror', 'quiz')) ;//, $gradeoptions);
|
||||||
|
@ -177,16 +171,14 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
$this->negative_diff =$countsavedsubquestions - $countsubquestions ;
|
$this->negative_diff =$countsavedsubquestions - $countsubquestions ;
|
||||||
if ( ($this->negative_diff > 0 ) ||$this->qtype_change || ($this->used_in_quiz && $this->negative_diff != 0)){
|
if ( ($this->negative_diff > 0 ) ||$this->qtype_change || ($this->used_in_quiz && $this->negative_diff != 0)){
|
||||||
$mform->addElement('header', 'additemhdr', get_string('warningquestionmodified','qtype_multianswer'));
|
$mform->addElement('header', 'additemhdr', get_string('warningquestionmodified','qtype_multianswer'));
|
||||||
}
|
}
|
||||||
if($this->negative_diff > 0) {
|
if($this->negative_diff > 0) {
|
||||||
//$this->used_in_quiz
|
//$this->used_in_quiz
|
||||||
|
$mform->addElement('static', 'alert1', "<strong>".get_string('questiondeleted','qtype_multianswer')."</strong>",get_string('questionsless','qtype_multianswer',$this->negative_diff));
|
||||||
$mform->addElement('static', 'alert1', "<strong>".get_string('questiondeleted','qtype_multianswer')."</strong>",get_string('questionsless','qtype_multianswer',$this->negative_diff));
|
|
||||||
}
|
}
|
||||||
if($this->qtype_change )
|
if($this->qtype_change ) {
|
||||||
{
|
$mform->addElement('static', 'alert1', "<strong>".get_string('questiontypechanged','qtype_multianswer')."</strong>",get_string('questiontypechangedcomment','qtype_multianswer'));
|
||||||
$mform->addElement('static', 'alert1', "<strong>".get_string('questiontypechanged','qtype_multianswer')."</strong>",get_string('questiontypechangedcomment','qtype_multianswer'));
|
|
||||||
}
|
}
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
}
|
}
|
||||||
|
@ -219,11 +211,11 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
|
|
||||||
foreach ($question->options->questions as $key => $wrapped) {
|
foreach ($question->options->questions as $key => $wrapped) {
|
||||||
if(!empty($wrapped)){
|
if(!empty($wrapped)){
|
||||||
// The old way of restoring the definitions is kept to gradually
|
// The old way of restoring the definitions is kept to gradually
|
||||||
// update all multianswer questions
|
// update all multianswer questions
|
||||||
if (empty($wrapped->questiontext)) {
|
if (empty($wrapped->questiontext)) {
|
||||||
$parsableanswerdef = '{' . $wrapped->defaultgrade . ':';
|
$parsableanswerdef = '{' . $wrapped->defaultgrade . ':';
|
||||||
switch ($wrapped->qtype) {
|
switch ($wrapped->qtype) {
|
||||||
case 'multichoice':
|
case 'multichoice':
|
||||||
$parsableanswerdef .= 'MULTICHOICE:';
|
$parsableanswerdef .= 'MULTICHOICE:';
|
||||||
break;
|
break;
|
||||||
|
@ -235,62 +227,62 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print_error('unknownquestiontype', 'question', '', $wrapped->qtype);
|
print_error('unknownquestiontype', 'question', '', $wrapped->qtype);
|
||||||
}
|
}
|
||||||
$separator= '';
|
$separator= '';
|
||||||
foreach ($wrapped->options->answers as $subanswer) {
|
foreach ($wrapped->options->answers as $subanswer) {
|
||||||
$parsableanswerdef .= $separator
|
$parsableanswerdef .= $separator
|
||||||
. '%' . round(100*$subanswer->fraction) . '%';
|
. '%' . round(100*$subanswer->fraction) . '%';
|
||||||
$parsableanswerdef .= $subanswer->answer;
|
$parsableanswerdef .= $subanswer->answer;
|
||||||
if (!empty($wrapped->options->tolerance)) {
|
if (!empty($wrapped->options->tolerance)) {
|
||||||
// Special for numerical answers:
|
// Special for numerical answers:
|
||||||
$parsableanswerdef .= ":{$wrapped->options->tolerance}";
|
$parsableanswerdef .= ":{$wrapped->options->tolerance}";
|
||||||
// We only want tolerance for the first alternative, it will
|
// We only want tolerance for the first alternative, it will
|
||||||
// be applied to all of the alternatives.
|
// be applied to all of the alternatives.
|
||||||
unset($wrapped->options->tolerance);
|
unset($wrapped->options->tolerance);
|
||||||
|
}
|
||||||
|
if ($subanswer->feedback) {
|
||||||
|
$parsableanswerdef .= "#$subanswer->feedback";
|
||||||
|
}
|
||||||
|
$separator = '~';
|
||||||
}
|
}
|
||||||
if ($subanswer->feedback) {
|
$parsableanswerdef .= '}';
|
||||||
$parsableanswerdef .= "#$subanswer->feedback";
|
// Fix the questiontext fields of old questions
|
||||||
}
|
$DB->set_field('question', 'questiontext', $parsableanswerdef, array('id' => $wrapped->id));
|
||||||
$separator = '~';
|
} else {
|
||||||
|
$parsableanswerdef = str_replace('&#', '&\#', $wrapped->questiontext);
|
||||||
}
|
}
|
||||||
$parsableanswerdef .= '}';
|
$question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
|
||||||
// Fix the questiontext fields of old questions
|
|
||||||
$DB->set_field('question', 'questiontext', $parsableanswerdef, array('id' => $wrapped->id));
|
|
||||||
} else {
|
|
||||||
$parsableanswerdef = str_replace('&#', '&\#', $wrapped->questiontext);
|
|
||||||
}
|
}
|
||||||
$question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// set default to $questiondisplay questions elements
|
// set default to $questiondisplay questions elements
|
||||||
if ( $this->reload ){
|
if ( $this->reload ){
|
||||||
if (isset($this->questiondisplay->options->questions)) {
|
if (isset($this->questiondisplay->options->questions)) {
|
||||||
$subquestions = fullclone($this->questiondisplay->options->questions) ;
|
$subquestions = fullclone($this->questiondisplay->options->questions) ;
|
||||||
if (count($subquestions)) {
|
if (count($subquestions)) {
|
||||||
$sub =1;
|
$sub =1;
|
||||||
foreach ($subquestions as $subquestion) {
|
foreach ($subquestions as $subquestion) {
|
||||||
$prefix = 'sub_'.$sub.'_' ;
|
$prefix = 'sub_'.$sub.'_' ;
|
||||||
|
|
||||||
// validate parameters
|
// validate parameters
|
||||||
$answercount = 0;
|
$answercount = 0;
|
||||||
$maxgrade = false;
|
$maxgrade = false;
|
||||||
$maxfraction = -1;
|
$maxfraction = -1;
|
||||||
if ($subquestion->qtype =='shortanswer' ) {
|
if ($subquestion->qtype =='shortanswer' ) {
|
||||||
switch ($subquestion->usecase) {
|
switch ($subquestion->usecase) {
|
||||||
case '1':
|
case '1':
|
||||||
$default_values[$prefix.'usecase']= get_string('caseyes', 'quiz');
|
$default_values[$prefix.'usecase']= get_string('caseyes', 'quiz');
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
default :
|
default :
|
||||||
$default_values[$prefix.'usecase']= get_string('caseno', 'quiz');
|
$default_values[$prefix.'usecase']= get_string('caseno', 'quiz');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($subquestion->qtype == 'multichoice' ) {
|
if ($subquestion->qtype == 'multichoice' ) {
|
||||||
$default_values[$prefix.'layout'] = $subquestion->layout ;
|
$default_values[$prefix.'layout'] = $subquestion->layout ;
|
||||||
switch ($subquestion->layout) {
|
switch ($subquestion->layout) {
|
||||||
case '0':
|
case '0':
|
||||||
$default_values[$prefix.'layout']= get_string('layoutselectinline', 'qtype_multianswer');
|
$default_values[$prefix.'layout']= get_string('layoutselectinline', 'qtype_multianswer');
|
||||||
break;
|
break;
|
||||||
|
@ -302,53 +294,53 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$default_values[$prefix.'layout']= get_string('layoutundefined', 'qtype_multianswer');
|
$default_values[$prefix.'layout']= get_string('layoutundefined', 'qtype_multianswer');
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($subquestion->answer as $key=>$answer) {
|
|
||||||
if ( $subquestion->qtype == 'numerical' && $key == 0 ) {
|
|
||||||
$default_values[$prefix.'tolerance['.$key.']'] = $subquestion->tolerance[0] ;
|
|
||||||
}
|
|
||||||
$trimmedanswer = trim($answer);
|
|
||||||
if ($trimmedanswer !== '') {
|
|
||||||
$answercount++;
|
|
||||||
if ($subquestion->qtype == 'numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
|
|
||||||
$this->_form->setElementError($prefix.'answer['.$key.']' , get_string('answermustbenumberorstar', 'qtype_numerical'));
|
|
||||||
}
|
|
||||||
if ($subquestion->fraction[$key] == 1) {
|
|
||||||
$maxgrade = true;
|
|
||||||
}
|
|
||||||
if ($subquestion->fraction[$key] > $maxfraction) {
|
|
||||||
$maxfraction = $subquestion->fraction[$key] ;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach ($subquestion->answer as $key=>$answer) {
|
||||||
|
if ( $subquestion->qtype == 'numerical' && $key == 0 ) {
|
||||||
|
$default_values[$prefix.'tolerance['.$key.']'] = $subquestion->tolerance[0] ;
|
||||||
|
}
|
||||||
|
$trimmedanswer = trim($answer);
|
||||||
|
if ($trimmedanswer !== '') {
|
||||||
|
$answercount++;
|
||||||
|
if ($subquestion->qtype == 'numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
|
||||||
|
$this->_form->setElementError($prefix.'answer['.$key.']' , get_string('answermustbenumberorstar', 'qtype_numerical'));
|
||||||
|
}
|
||||||
|
if ($subquestion->fraction[$key] == 1) {
|
||||||
|
$maxgrade = true;
|
||||||
|
}
|
||||||
|
if ($subquestion->fraction[$key] > $maxfraction) {
|
||||||
|
$maxfraction = $subquestion->fraction[$key] ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$default_values[$prefix.'answer['.$key.']'] = htmlspecialchars ($answer);
|
$default_values[$prefix.'answer['.$key.']'] = htmlspecialchars ($answer);
|
||||||
}
|
|
||||||
if ($answercount == 0) {
|
|
||||||
if ($subquestion->qtype == 'multichoice' ) {
|
|
||||||
$this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'qtype_multichoice', 2));
|
|
||||||
} else {
|
|
||||||
$this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'quiz', 1));
|
|
||||||
}
|
}
|
||||||
}
|
if ($answercount == 0) {
|
||||||
if ($maxgrade == false) {
|
if ($subquestion->qtype == 'multichoice' ) {
|
||||||
$this->_form->setElementError($prefix.'fraction[0]' ,get_string('fractionsnomax', 'question'));
|
$this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'qtype_multichoice', 2));
|
||||||
}
|
} else {
|
||||||
foreach ($subquestion->feedback as $key=>$answer) {
|
$this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'quiz', 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($maxgrade == false) {
|
||||||
|
$this->_form->setElementError($prefix.'fraction[0]' ,get_string('fractionsnomax', 'question'));
|
||||||
|
}
|
||||||
|
foreach ($subquestion->feedback as $key=>$answer) {
|
||||||
|
|
||||||
$default_values[$prefix.'feedback['.$key.']'] = htmlspecialchars ($answer);
|
$default_values[$prefix.'feedback['.$key.']'] = htmlspecialchars ($answer);
|
||||||
}
|
}
|
||||||
foreach ( $subquestion->fraction as $key=>$answer) {
|
foreach ( $subquestion->fraction as $key=>$answer) {
|
||||||
$default_values[$prefix.'fraction['.$key.']'] = $answer;
|
$default_values[$prefix.'fraction['.$key.']'] = $answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$sub++;
|
$sub++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
$default_values['alertas']= "<strong>".get_string('questioninquiz','qtype_multianswer')."</strong>";
|
||||||
$default_values['alertas']= "<strong>".get_string('questioninquiz','qtype_multianswer')."</strong>";
|
|
||||||
|
|
||||||
if( $default_values != "") {
|
if( $default_values != "") {
|
||||||
$question = (object)((array)$question + $default_values);
|
$question = (object)((array)$question + $default_values);
|
||||||
|
@ -358,14 +350,11 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
|
|
||||||
function validation($data, $files) {
|
function validation($data, $files) {
|
||||||
$errors = parent::validation($data, $files);
|
$errors = parent::validation($data, $files);
|
||||||
|
|
||||||
$questiondisplay = qtype_multianswer_extract_question($data['questiontext']) ;
|
|
||||||
|
|
||||||
|
|
||||||
|
$questiondisplay = qtype_multianswer_extract_question($data['questiontext']['text']);
|
||||||
|
|
||||||
if (isset($questiondisplay->options->questions)) {
|
if (isset($questiondisplay->options->questions)) {
|
||||||
|
$subquestions = fullclone($questiondisplay->options->questions) ;
|
||||||
$subquestions = fullclone($questiondisplay->options->questions) ;
|
|
||||||
if (count($subquestions)) {
|
if (count($subquestions)) {
|
||||||
$sub =1;
|
$sub =1;
|
||||||
foreach ($subquestions as $subquestion) {
|
foreach ($subquestions as $subquestion) {
|
||||||
|
@ -373,17 +362,17 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
$answercount = 0;
|
$answercount = 0;
|
||||||
$maxgrade = false;
|
$maxgrade = false;
|
||||||
$maxfraction = -1;
|
$maxfraction = -1;
|
||||||
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
|
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
|
||||||
$this->savedquestiondisplay->options->questions[$sub]->qtype != $questiondisplay->options->questions[$sub]->qtype ){
|
$this->savedquestiondisplay->options->questions[$sub]->qtype != $questiondisplay->options->questions[$sub]->qtype ){
|
||||||
$storemess = " STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype];
|
$storemess = " STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype];
|
||||||
}
|
}
|
||||||
foreach ( $subquestion->answer as $key=>$answer) {
|
foreach ( $subquestion->answer as $key=>$answer) {
|
||||||
$trimmedanswer = trim($answer);
|
$trimmedanswer = trim($answer);
|
||||||
if ($trimmedanswer !== '') {
|
if ($trimmedanswer !== '') {
|
||||||
$answercount++;
|
$answercount++;
|
||||||
if ($subquestion->qtype =='numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
|
if ($subquestion->qtype =='numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
|
||||||
$errors[$prefix.'answer['.$key.']']= get_string('answermustbenumberorstar', 'qtype_numerical');
|
$errors[$prefix.'answer['.$key.']']= get_string('answermustbenumberorstar', 'qtype_numerical');
|
||||||
}
|
}
|
||||||
if ($subquestion->fraction[$key] == 1) {
|
if ($subquestion->fraction[$key] == 1) {
|
||||||
$maxgrade = true;
|
$maxgrade = true;
|
||||||
}
|
}
|
||||||
|
@ -408,18 +397,17 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||||
$errors['questiontext']=get_string('questionsmissing', 'qtype_multianswer');
|
$errors['questiontext']=get_string('questionsmissing', 'qtype_multianswer');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// $question = qtype_multianswer_extract_question($data['questiontext']);
|
// $question = qtype_multianswer_extract_question($data['questiontext']);
|
||||||
// if (isset $question->options->questions
|
// if (isset $question->options->questions
|
||||||
if (( $this->negative_diff > 0 || $this->used_in_quiz && ($this->negative_diff > 0 ||$this->negative_diff < 0 || $this->qtype_change ))&& $this->confirm == 0 ){
|
if (( $this->negative_diff > 0 || $this->used_in_quiz && ($this->negative_diff > 0 ||$this->negative_diff < 0 || $this->qtype_change ))&& $this->confirm == 0 ){
|
||||||
$errors['confirm']=get_string('confirmsave', 'qtype_multianswer',$this->negative_diff);
|
$errors['confirm']=get_string('confirmsave', 'qtype_multianswer',$this->negative_diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
return 'multianswer';
|
return 'multianswer';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -307,10 +307,6 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '<div class="ablock clearfix">';
|
echo '<div class="ablock clearfix">';
|
||||||
// For this question type, we better print the image on top:
|
|
||||||
if ($image = get_question_image($question)) {
|
|
||||||
echo('<img class="qimage" src="' . $image . '" alt="" /><br />');
|
|
||||||
}
|
|
||||||
|
|
||||||
$qtextremaining = format_text($question->questiontext,
|
$qtextremaining = format_text($question->questiontext,
|
||||||
$question->questiontextformat, $formatoptions, $cmoptions->course);
|
$question->questiontextformat, $formatoptions, $cmoptions->course);
|
||||||
|
@ -986,9 +982,7 @@ function qtype_multianswer_extract_question($text) {
|
||||||
$question->options->questions = array();
|
$question->options->questions = array();
|
||||||
$question->defaultgrade = 0; // Will be increased for each answer norm
|
$question->defaultgrade = 0; // Will be increased for each answer norm
|
||||||
|
|
||||||
for ($positionkey=1
|
for ($positionkey=1; preg_match('/'.ANSWER_REGEX.'/', $question->questiontext['text'], $answerregs); ++$positionkey ) {
|
||||||
; preg_match('/'.ANSWER_REGEX.'/', $question->questiontext, $answerregs)
|
|
||||||
; ++$positionkey ) {
|
|
||||||
$wrapped = new stdClass;
|
$wrapped = new stdClass;
|
||||||
if (isset($answerregs[ANSWER_REGEX_NORM])&& $answerregs[ANSWER_REGEX_NORM]!== ''){
|
if (isset($answerregs[ANSWER_REGEX_NORM])&& $answerregs[ANSWER_REGEX_NORM]!== ''){
|
||||||
$wrapped->defaultgrade = $answerregs[ANSWER_REGEX_NORM];
|
$wrapped->defaultgrade = $answerregs[ANSWER_REGEX_NORM];
|
||||||
|
@ -1087,4 +1081,3 @@ function qtype_multianswer_extract_question($text) {
|
||||||
$question->questiontext = $question->questiontext;
|
$question->questiontext = $question->questiontext;
|
||||||
return $question;
|
return $question;
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<XMLDB PATH="question/type/multichoice/db" VERSION="20070413" COMMENT="XMLDB file for Moodle question/type/multichoice"
|
<XMLDB PATH="question/type/multichoice/db" VERSION="20100716" COMMENT="XMLDB file for Moodle question/type/multichoice"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
||||||
>
|
>
|
||||||
|
@ -12,10 +12,13 @@
|
||||||
<FIELD NAME="answers" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Redundant. Comma-separated list of question_answer ids. SELECT id FROM question_answers WHERE question = ? ORDER BY id." PREVIOUS="layout" NEXT="single"/>
|
<FIELD NAME="answers" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Redundant. Comma-separated list of question_answer ids. SELECT id FROM question_answers WHERE question = ? ORDER BY id." PREVIOUS="layout" NEXT="single"/>
|
||||||
<FIELD NAME="single" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="If 0 it multiple response (checkboxes). Otherwise it is radio buttons." PREVIOUS="answers" NEXT="shuffleanswers"/>
|
<FIELD NAME="single" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="If 0 it multiple response (checkboxes). Otherwise it is radio buttons." PREVIOUS="answers" NEXT="shuffleanswers"/>
|
||||||
<FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" COMMENT="Whether the choices can be randomly shuffled." PREVIOUS="single" NEXT="correctfeedback"/>
|
<FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" COMMENT="Whether the choices can be randomly shuffled." PREVIOUS="single" NEXT="correctfeedback"/>
|
||||||
<FIELD NAME="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="partiallycorrectfeedback"/>
|
<FIELD NAME="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="correctfeedbackformat"/>
|
||||||
<FIELD NAME="partiallycorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any partially correct response." PREVIOUS="correctfeedback" NEXT="incorrectfeedback"/>
|
<FIELD NAME="correctfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="correctfeedback" NEXT="partiallycorrectfeedback"/>
|
||||||
<FIELD NAME="incorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="partiallycorrectfeedback" NEXT="answernumbering"/>
|
<FIELD NAME="partiallycorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any partially correct response." PREVIOUS="correctfeedbackformat" NEXT="partiallycorrectfeedbackformat"/>
|
||||||
<FIELD NAME="answernumbering" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="abc" SEQUENCE="false" COMMENT="Indicates how and whether the choices should be numbered." PREVIOUS="incorrectfeedback"/>
|
<FIELD NAME="partiallycorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="partiallycorrectfeedback" NEXT="incorrectfeedback"/>
|
||||||
|
<FIELD NAME="incorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="partiallycorrectfeedbackformat" NEXT="incorrectfeedbackformat"/>
|
||||||
|
<FIELD NAME="incorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="incorrectfeedback" NEXT="answernumbering"/>
|
||||||
|
<FIELD NAME="answernumbering" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="abc" SEQUENCE="false" COMMENT="Indicates how and whether the choices should be numbered." PREVIOUS="incorrectfeedbackformat"/>
|
||||||
</FIELDS>
|
</FIELDS>
|
||||||
<KEYS>
|
<KEYS>
|
||||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
||||||
|
@ -23,4 +26,4 @@
|
||||||
</KEYS>
|
</KEYS>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
</TABLES>
|
</TABLES>
|
||||||
</XMLDB>
|
</XMLDB>
|
|
@ -52,6 +52,61 @@ function xmldb_qtype_multichoice_upgrade($oldversion) {
|
||||||
upgrade_plugin_savepoint(true, 2008021800, 'qtype', 'multichoice');
|
upgrade_plugin_savepoint(true, 2008021800, 'qtype', 'multichoice');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($oldversion < 2009021801) {
|
||||||
|
|
||||||
|
/// Define field correctfeedbackformat to be added to question_multichoice
|
||||||
|
$table = new xmldb_table('question_multichoice');
|
||||||
|
$field = new xmldb_field('correctfeedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'correctfeedback');
|
||||||
|
|
||||||
|
/// Conditionally launch add field correctfeedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define field partiallycorrectfeedbackformat to be added to question_multichoice
|
||||||
|
$field = new xmldb_field('partiallycorrectfeedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'partiallycorrectfeedback');
|
||||||
|
|
||||||
|
/// Conditionally launch add field partiallycorrectfeedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define field incorrectfeedbackformat to be added to question_multichoice
|
||||||
|
$field = new xmldb_field('incorrectfeedbackformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'incorrectfeedback');
|
||||||
|
|
||||||
|
/// Conditionally launch add field incorrectfeedbackformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rs = $DB->get_recordset('question_multichoice');
|
||||||
|
foreach ($rs as $record) {
|
||||||
|
if ($CFG->texteditors !== 'textarea') {
|
||||||
|
if (!empty($record->correctfeedback)) {
|
||||||
|
$record->correctfeedback = text_to_html($record->correctfeedback);
|
||||||
|
}
|
||||||
|
$record->correctfeedbackformat = FORMAT_HTML;
|
||||||
|
if (!empty($record->partiallycorrectfeedback)) {
|
||||||
|
$record->partiallycorrectfeedback = text_to_html($record->partiallycorrectfeedback);
|
||||||
|
}
|
||||||
|
$record->partiallycorrectfeedbackformat = FORMAT_HTML;
|
||||||
|
if (!empty($record->incorrectfeedback)) {
|
||||||
|
$record->incorrectfeedback = text_to_html($record->incorrectfeedback);
|
||||||
|
}
|
||||||
|
$record->incorrectfeedbackformat = FORMAT_HTML;
|
||||||
|
} else {
|
||||||
|
$record->correctfeedbackformat = FORMAT_MOODLE;
|
||||||
|
$record->partiallycorrectfeedbackformat = FORMAT_MOODLE;
|
||||||
|
$record->incorrectfeedbackformat = FORMAT_MOODLE;
|
||||||
|
}
|
||||||
|
$DB->update_record('question_multichoice', $record);
|
||||||
|
}
|
||||||
|
$rs->close();
|
||||||
|
|
||||||
|
/// multichoice savepoint reached
|
||||||
|
upgrade_plugin_savepoint(true, 2009021801, 'qtype', 'multichoice');
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
|
|
||||||
<div class="ablock clearfix">
|
<div class="ablock clearfix">
|
||||||
<div class="prompt">
|
<div class="prompt">
|
||||||
<?php echo $answerprompt; ?>
|
<?php echo $answerprompt; ?>
|
||||||
|
|
|
@ -1,4 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the multichoice question type.
|
* Defines the editing form for the multichoice question type.
|
||||||
*
|
*
|
||||||
|
@ -47,14 +65,14 @@ class question_edit_multichoice_form extends question_edit_form {
|
||||||
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
||||||
|
|
||||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||||
$mform->addElement('htmleditor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'),
|
$mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'),
|
||||||
array('course' => $this->coursefilesid));
|
array('course' => $this->coursefilesid), $this->editoroptions);
|
||||||
$mform->setType($feedbackname, PARAM_RAW);
|
$mform->setType($feedbackname, PARAM_RAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
if (isset($question->options)){
|
if (isset($question->options)){
|
||||||
$answers = $question->options->answers;
|
$answers = $question->options->answers;
|
||||||
if (count($answers)) {
|
if (count($answers)) {
|
||||||
|
@ -62,19 +80,44 @@ class question_edit_multichoice_form extends question_edit_form {
|
||||||
foreach ($answers as $answer){
|
foreach ($answers as $answer){
|
||||||
$default_values['answer['.$key.']'] = $answer->answer;
|
$default_values['answer['.$key.']'] = $answer->answer;
|
||||||
$default_values['fraction['.$key.']'] = $answer->fraction;
|
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||||
$default_values['feedback['.$key.']'] = $answer->feedback;
|
|
||||||
|
// prepare question text
|
||||||
|
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||||
|
$default_values['feedback['.$key.']'] = array();
|
||||||
|
$default_values['feedback['.$key.']']['text'] = file_prepare_draft_area($draftid, $this->context->id, 'question', 'answerfeedback', empty($answer->id)?null:(int)$answer->id, null, $answer->feedback);
|
||||||
|
$default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
|
||||||
|
$default_values['feedback['.$key.']']['itemid'] = $draftid;
|
||||||
$key++;
|
$key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$default_values['single'] = $question->options->single;
|
$default_values['single'] = $question->options->single;
|
||||||
$default_values['answernumbering'] = $question->options->answernumbering;
|
$default_values['answernumbering'] = $question->options->answernumbering;
|
||||||
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
||||||
$default_values['correctfeedback'] = $question->options->correctfeedback;
|
|
||||||
$default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback;
|
// prepare feedback editor to display files in draft area
|
||||||
$default_values['incorrectfeedback'] = $question->options->incorrectfeedback;
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||||
|
$draftid = file_get_submitted_draft_itemid($feedbackname);
|
||||||
|
$text = $question->options->$feedbackname;
|
||||||
|
$feedbackformat = $feedbackname . 'format';
|
||||||
|
$format = $question->options->$feedbackformat;
|
||||||
|
$default_values[$feedbackname] = array();
|
||||||
|
$default_values[$feedbackname]['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'qtype_multichoice', // component
|
||||||
|
$feedbackname, // filarea
|
||||||
|
!empty($question->id)?(int)$question->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$text // text
|
||||||
|
);
|
||||||
|
$default_values[$feedbackname]['format'] = $format;
|
||||||
|
$default_values[$feedbackname]['itemid'] = $draftid;
|
||||||
|
}
|
||||||
|
// prepare files code block ends
|
||||||
|
|
||||||
$question = (object)((array)$question + $default_values);
|
$question = (object)((array)$question + $default_values);
|
||||||
}
|
}
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
|
|
31
question/type/multichoice/lib.php
Normal file
31
question/type/multichoice/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_multichoice_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_multichoice', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -29,8 +29,8 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
|
|
||||||
list ($usql, $params) = $DB->get_in_or_equal(explode(',', $question->options->answers));
|
list ($usql, $params) = $DB->get_in_or_equal(explode(',', $question->options->answers));
|
||||||
if (!$question->options->answers = $DB->get_records_select('question_answers', "id $usql", $params, 'id')) {
|
if (!$question->options->answers = $DB->get_records_select('question_answers', "id $usql", $params, 'id')) {
|
||||||
echo $OUTPUT->notification('Error: Missing question answers for multichoice question'.$question->id.'!');
|
echo $OUTPUT->notification('Error: Missing question answers for multichoice question'.$question->id.'!');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -38,6 +38,7 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
|
|
||||||
function save_question_options($question) {
|
function save_question_options($question) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
$context = $question->context;
|
||||||
$result = new stdClass;
|
$result = new stdClass;
|
||||||
if (!$oldanswers = $DB->get_records("question_answers", array("question" => $question->id), "id ASC")) {
|
if (!$oldanswers = $DB->get_records("question_answers", array("question" => $question->id), "id ASC")) {
|
||||||
$oldanswers = array();
|
$oldanswers = array();
|
||||||
|
@ -65,18 +66,23 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
|
|
||||||
foreach ($question->answer as $key => $dataanswer) {
|
foreach ($question->answer as $key => $dataanswer) {
|
||||||
if ($dataanswer != "") {
|
if ($dataanswer != "") {
|
||||||
|
$feedbackformat = $question->feedback[$key]['format'];
|
||||||
if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||||
$answer->answer = $dataanswer;
|
$answer->answer = $dataanswer;
|
||||||
$answer->fraction = $question->fraction[$key];
|
$answer->fraction = $question->fraction[$key];
|
||||||
$answer->feedback = $question->feedback[$key];
|
$answer->feedbackformat = $feedbackformat;
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']);
|
||||||
$DB->update_record("question_answers", $answer);
|
$DB->update_record("question_answers", $answer);
|
||||||
} else {
|
} else {
|
||||||
unset($answer);
|
unset($answer);
|
||||||
$answer->answer = $dataanswer;
|
$answer->answer = $dataanswer;
|
||||||
$answer->question = $question->id;
|
$answer->question = $question->id;
|
||||||
$answer->fraction = $question->fraction[$key];
|
$answer->fraction = $question->fraction[$key];
|
||||||
$answer->feedback = $question->feedback[$key];
|
$answer->feedback = '';
|
||||||
|
$answer->feedbackformat = $feedbackformat;
|
||||||
$answer->id = $DB->insert_record("question_answers", $answer);
|
$answer->id = $DB->insert_record("question_answers", $answer);
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']);
|
||||||
|
$DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id));
|
||||||
}
|
}
|
||||||
$answers[] = $answer->id;
|
$answers[] = $answer->id;
|
||||||
|
|
||||||
|
@ -100,13 +106,19 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
$options->answers = implode(",",$answers);
|
$options->answers = implode(",",$answers);
|
||||||
$options->single = $question->single;
|
$options->single = $question->single;
|
||||||
if(isset($question->layout)){
|
if(isset($question->layout)){
|
||||||
$options->layout = $question->layout;
|
$options->layout = $question->layout;
|
||||||
}
|
}
|
||||||
$options->answernumbering = $question->answernumbering;
|
$options->answernumbering = $question->answernumbering;
|
||||||
$options->shuffleanswers = $question->shuffleanswers;
|
$options->shuffleanswers = $question->shuffleanswers;
|
||||||
$options->correctfeedback = trim($question->correctfeedback);
|
|
||||||
$options->partiallycorrectfeedback = trim($question->partiallycorrectfeedback);
|
foreach (array('correct', 'partiallycorrect', 'incorrect') as $feedbacktype) {
|
||||||
$options->incorrectfeedback = trim($question->incorrectfeedback);
|
$feedbackname = $feedbacktype . 'feedback';
|
||||||
|
$feedbackformat = $feedbackname . 'format';
|
||||||
|
$feedback = $question->$feedbackname;
|
||||||
|
$options->$feedbackformat = trim($feedback['format']);
|
||||||
|
$options->$feedbackname = file_save_draft_area_files($feedback['itemid'], $context->id, 'qtype_multichoice', $feedbackname, $question->id, self::$fileoptions, trim($feedback['text']));
|
||||||
|
}
|
||||||
|
|
||||||
if ($update) {
|
if ($update) {
|
||||||
$DB->update_record("question_multichoice", $options);
|
$DB->update_record("question_multichoice", $options);
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,11 +151,11 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes question from the question-type specific tables
|
* Deletes question from the question-type specific tables
|
||||||
*
|
*
|
||||||
* @return boolean Success/Failure
|
* @return boolean Success/Failure
|
||||||
* @param object $question The question being deleted
|
* @param object $question The question being deleted
|
||||||
*/
|
*/
|
||||||
function delete_question($questionid) {
|
function delete_question($questionid) {
|
||||||
global $DB;
|
global $DB;
|
||||||
$DB->delete_records("question_multichoice", array("question" => $questionid));
|
$DB->delete_records("question_multichoice", array("question" => $questionid));
|
||||||
|
@ -153,10 +165,10 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
|
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
|
||||||
// create an array of answerids ??? why so complicated ???
|
// create an array of answerids ??? why so complicated ???
|
||||||
$answerids = array_values(array_map(create_function('$val',
|
$answerids = array_values(array_map(create_function('$val',
|
||||||
'return $val->id;'), $question->options->answers));
|
'return $val->id;'), $question->options->answers));
|
||||||
// Shuffle the answers if required
|
// Shuffle the answers if required
|
||||||
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
|
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
|
||||||
$answerids = swapshuffle($answerids);
|
$answerids = swapshuffle($answerids);
|
||||||
}
|
}
|
||||||
$state->options->order = $answerids;
|
$state->options->order = $answerids;
|
||||||
// Create empty responses
|
// Create empty responses
|
||||||
|
@ -203,7 +215,7 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
$state->responses = array_flip($state->responses);
|
$state->responses = array_flip($state->responses);
|
||||||
// Set the value of each element to be equal to the index
|
// Set the value of each element to be equal to the index
|
||||||
array_walk($state->responses, create_function('&$a, $b',
|
array_walk($state->responses, create_function('&$a, $b',
|
||||||
'$a = $b;'));
|
'$a = $b;'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -252,6 +264,10 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
|
||||||
|
// required by file api
|
||||||
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
|
$component = 'qtype_' . $question->qtype;
|
||||||
|
|
||||||
$answers = &$question->options->answers;
|
$answers = &$question->options->answers;
|
||||||
$correctanswers = $this->get_correct_responses($question, $state);
|
$correctanswers = $this->get_correct_responses($question, $state);
|
||||||
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
||||||
|
@ -261,10 +277,8 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
$formatoptions->para = false;
|
$formatoptions->para = false;
|
||||||
|
|
||||||
// Print formulation
|
// Print formulation
|
||||||
$questiontext = format_text($question->questiontext,
|
$questiontext = format_text($question->questiontext, $question->questiontextformat,
|
||||||
$question->questiontextformat,
|
$formatoptions, $cmoptions->course);
|
||||||
$formatoptions, $cmoptions->course);
|
|
||||||
$image = get_question_image($question);
|
|
||||||
$answerprompt = ($question->options->single) ? get_string('singleanswer', 'quiz') :
|
$answerprompt = ($question->options->single) ? get_string('singleanswer', 'quiz') :
|
||||||
get_string('multipleanswers', 'quiz');
|
get_string('multipleanswers', 'quiz');
|
||||||
|
|
||||||
|
@ -311,11 +325,13 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
|
|
||||||
// Print the answer text
|
// Print the answer text
|
||||||
$a->text = $this->number_in_style($key, $question->options->answernumbering) .
|
$a->text = $this->number_in_style($key, $question->options->answernumbering) .
|
||||||
format_text($answer->answer, FORMAT_MOODLE, $formatoptions, $cmoptions->course);
|
format_text($answer->answer, $answer->answerformat, $formatoptions, $cmoptions->course);
|
||||||
|
|
||||||
// Print feedback if feedback is on
|
// Print feedback if feedback is on
|
||||||
if (($options->feedback || $options->correct_responses) && $checked) {
|
if (($options->feedback || $options->correct_responses) && $checked) {
|
||||||
$a->feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
// feedback for each answer
|
||||||
|
$a->feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'question', 'answerfeedback', array($state->attempt, $state->question), $answer->id);
|
||||||
|
$a->feedback = format_text($a->feedback, $answer->feedbackformat, $formatoptions, $cmoptions->course);
|
||||||
} else {
|
} else {
|
||||||
$a->feedback = '';
|
$a->feedback = '';
|
||||||
}
|
}
|
||||||
|
@ -327,14 +343,18 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
if ($options->feedback) {
|
if ($options->feedback) {
|
||||||
if ($state->raw_grade >= $question->maxgrade/1.01) {
|
if ($state->raw_grade >= $question->maxgrade/1.01) {
|
||||||
$feedback = $question->options->correctfeedback;
|
$feedback = $question->options->correctfeedback;
|
||||||
|
$feedbacktype = 'correctfeedback';
|
||||||
} else if ($state->raw_grade > 0) {
|
} else if ($state->raw_grade > 0) {
|
||||||
$feedback = $question->options->partiallycorrectfeedback;
|
$feedback = $question->options->partiallycorrectfeedback;
|
||||||
|
$feedbacktype = 'partiallycorrectfeedback';
|
||||||
} else {
|
} else {
|
||||||
$feedback = $question->options->incorrectfeedback;
|
$feedback = $question->options->incorrectfeedback;
|
||||||
|
$feedbacktype = 'incorrectfeedback';
|
||||||
}
|
}
|
||||||
$feedback = format_text($feedback,
|
|
||||||
$question->questiontextformat,
|
$feedback = quiz_rewrite_question_urls($feedback, 'pluginfile.php', $context->id, $component, $feedbacktype, array($state->attempt, $state->question), $question->id);
|
||||||
$formatoptions, $cmoptions->course);
|
$feedbackformat = $feedbacktype . 'format';
|
||||||
|
$feedback = format_text($feedback, $question->options->$feedbackformat, $formatoptions, $cmoptions->course);
|
||||||
}
|
}
|
||||||
|
|
||||||
include("$CFG->dirroot/question/type/multichoice/display.html");
|
include("$CFG->dirroot/question/type/multichoice/display.html");
|
||||||
|
@ -357,7 +377,7 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
|
|
||||||
// Make sure we don't assign negative or too high marks
|
// Make sure we don't assign negative or too high marks
|
||||||
$state->raw_grade = min(max((float) $state->raw_grade,
|
$state->raw_grade = min(max((float) $state->raw_grade,
|
||||||
0.0), 1.0) * $question->maxgrade;
|
0.0), 1.0) * $question->maxgrade;
|
||||||
|
|
||||||
// Apply the penalty for this attempt
|
// Apply the penalty for this attempt
|
||||||
$state->penalty = $question->penalty * $question->maxgrade;
|
$state->penalty = $question->penalty * $question->maxgrade;
|
||||||
|
@ -401,7 +421,7 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
}
|
}
|
||||||
return $totalfraction / count($question->options->answers);
|
return $totalfraction / count($question->options->answers);
|
||||||
}
|
}
|
||||||
/// BACKUP FUNCTIONS ////////////////////////////
|
/// BACKUP FUNCTIONS ////////////////////////////
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Backup the data in the question
|
* Backup the data in the question
|
||||||
|
@ -436,7 +456,7 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RESTORE FUNCTIONS /////////////////
|
/// RESTORE FUNCTIONS /////////////////
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restores the data in the question
|
* Restores the data in the question
|
||||||
|
@ -575,31 +595,31 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
|
|
||||||
// Decode links in the question_multichoice table.
|
// Decode links in the question_multichoice table.
|
||||||
if ($multichoices = $DB->get_records_list('question_multichoice', 'question',
|
if ($multichoices = $DB->get_records_list('question_multichoice', 'question',
|
||||||
$questionids, '', 'id, correctfeedback, partiallycorrectfeedback, incorrectfeedback')) {
|
$questionids, '', 'id, correctfeedback, partiallycorrectfeedback, incorrectfeedback')) {
|
||||||
|
|
||||||
foreach ($multichoices as $multichoice) {
|
foreach ($multichoices as $multichoice) {
|
||||||
$correctfeedback = restore_decode_content_links_worker($multichoice->correctfeedback, $restore);
|
$correctfeedback = restore_decode_content_links_worker($multichoice->correctfeedback, $restore);
|
||||||
$partiallycorrectfeedback = restore_decode_content_links_worker($multichoice->partiallycorrectfeedback, $restore);
|
$partiallycorrectfeedback = restore_decode_content_links_worker($multichoice->partiallycorrectfeedback, $restore);
|
||||||
$incorrectfeedback = restore_decode_content_links_worker($multichoice->incorrectfeedback, $restore);
|
$incorrectfeedback = restore_decode_content_links_worker($multichoice->incorrectfeedback, $restore);
|
||||||
if ($correctfeedback != $multichoice->correctfeedback ||
|
if ($correctfeedback != $multichoice->correctfeedback ||
|
||||||
$partiallycorrectfeedback != $multichoice->partiallycorrectfeedback ||
|
$partiallycorrectfeedback != $multichoice->partiallycorrectfeedback ||
|
||||||
$incorrectfeedback != $multichoice->incorrectfeedback) {
|
$incorrectfeedback != $multichoice->incorrectfeedback) {
|
||||||
$subquestion->correctfeedback = $correctfeedback;
|
$subquestion->correctfeedback = $correctfeedback;
|
||||||
$subquestion->partiallycorrectfeedback = $partiallycorrectfeedback;
|
$subquestion->partiallycorrectfeedback = $partiallycorrectfeedback;
|
||||||
$subquestion->incorrectfeedback = $incorrectfeedback;
|
$subquestion->incorrectfeedback = $incorrectfeedback;
|
||||||
$DB->update_record('question_multichoice', $multichoice);
|
$DB->update_record('question_multichoice', $multichoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do some output.
|
// Do some output.
|
||||||
if (++$i % 5 == 0 && !defined('RESTORE_SILENTLY')) {
|
if (++$i % 5 == 0 && !defined('RESTORE_SILENTLY')) {
|
||||||
echo ".";
|
echo ".";
|
||||||
if ($i % 100 == 0) {
|
if ($i % 100 == 0) {
|
||||||
echo "<br />";
|
echo "<br />";
|
||||||
|
}
|
||||||
|
backup_flush(300);
|
||||||
}
|
}
|
||||||
backup_flush(300);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
|
@ -625,16 +645,16 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
*/
|
*/
|
||||||
function number_in_style($num, $style) {
|
function number_in_style($num, $style) {
|
||||||
switch($style) {
|
switch($style) {
|
||||||
case 'abc':
|
case 'abc':
|
||||||
return $this->number_html(chr(ord('a') + $num));
|
return $this->number_html(chr(ord('a') + $num));
|
||||||
case 'ABCD':
|
case 'ABCD':
|
||||||
return $this->number_html(chr(ord('A') + $num));
|
return $this->number_html(chr(ord('A') + $num));
|
||||||
case '123':
|
case '123':
|
||||||
return $this->number_html(($num + 1));
|
return $this->number_html(($num + 1));
|
||||||
case 'none':
|
case 'none':
|
||||||
return '';
|
return '';
|
||||||
default:
|
default:
|
||||||
return 'ERR';
|
return 'ERR';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,8 +728,82 @@ class question_multichoice_qtype extends default_questiontype {
|
||||||
|
|
||||||
return $this->save_question($question, $form, $course);
|
return $this->save_question($question, $form, $course);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
// move files belonging to question component
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
// move files belonging to qtype_multichoice
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
$component = 'question';
|
||||||
|
$filearea = 'answerfeedback';
|
||||||
|
foreach ($oldanswers as $answer) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$component = 'qtype_multichoice';
|
||||||
|
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $filearea) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
$itemid = reset($args);
|
||||||
|
|
||||||
|
if (empty($question->maxgrade)) {
|
||||||
|
$question->maxgrade = $question->defaultgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($filearea, array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'))) {
|
||||||
|
$result = $options->feedback && ($itemid == $question->id);
|
||||||
|
if (!$result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($state->raw_grade >= $question->maxgrade/1.01) {
|
||||||
|
$feedbacktype = 'correctfeedback';
|
||||||
|
} else if ($state->raw_grade > 0) {
|
||||||
|
$feedbacktype = 'partiallycorrectfeedback';
|
||||||
|
} else {
|
||||||
|
$feedbacktype = 'incorrectfeedback';
|
||||||
|
}
|
||||||
|
if ($feedbacktype != $filearea) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||||
|
return $options->feedback && (array_key_exists($itemid, $question->options->answers));
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register this question type with the question bank.
|
// Register this question type with the question bank.
|
||||||
question_register_questiontype(new question_multichoice_qtype());
|
question_register_questiontype(new question_multichoice_qtype());
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$plugin->version = 2009021800;
|
$plugin->version = 2009021801;
|
||||||
$plugin->requires = 2007101000;
|
$plugin->requires = 2007101000;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<XMLDB PATH="question/type/numerical/db" VERSION="20091001" COMMENT="XMLDB file for Moodle question/type/numerical"
|
<XMLDB PATH="question/type/numerical/db" VERSION="20100720" COMMENT="XMLDB file for Moodle question/type/numerical"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
||||||
>
|
>
|
||||||
|
@ -23,8 +23,9 @@
|
||||||
<FIELDS>
|
<FIELDS>
|
||||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="question"/>
|
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="question"/>
|
||||||
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="instructions"/>
|
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="instructions"/>
|
||||||
<FIELD NAME="instructions" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="question" NEXT="showunits"/>
|
<FIELD NAME="instructions" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="question" NEXT="instructionsformat"/>
|
||||||
<FIELD NAME="showunits" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="display units as multichoice" PREVIOUS="instructions" NEXT="unitsleft"/>
|
<FIELD NAME="instructionsformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="instructions" NEXT="showunits"/>
|
||||||
|
<FIELD NAME="showunits" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="display units as multichoice" PREVIOUS="instructionsformat" NEXT="unitsleft"/>
|
||||||
<FIELD NAME="unitsleft" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="display the unit at left as in $1.00" PREVIOUS="showunits" NEXT="unitgradingtype"/>
|
<FIELD NAME="unitsleft" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="display the unit at left as in $1.00" PREVIOUS="showunits" NEXT="unitgradingtype"/>
|
||||||
<FIELD NAME="unitgradingtype" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="0 no penalty, 1 total grade, 2 response grade" PREVIOUS="unitsleft" NEXT="unitpenalty"/>
|
<FIELD NAME="unitgradingtype" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="0 no penalty, 1 total grade, 2 response grade" PREVIOUS="unitsleft" NEXT="unitpenalty"/>
|
||||||
<FIELD NAME="unitpenalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="true" DEFAULT="0.1" SEQUENCE="false" DECIMALS="7" PREVIOUS="unitgradingtype"/>
|
<FIELD NAME="unitpenalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="true" DEFAULT="0.1" SEQUENCE="false" DECIMALS="7" PREVIOUS="unitgradingtype"/>
|
||||||
|
@ -50,4 +51,4 @@
|
||||||
</INDEXES>
|
</INDEXES>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
</TABLES>
|
</TABLES>
|
||||||
</XMLDB>
|
</XMLDB>
|
|
@ -51,6 +51,35 @@ function xmldb_qtype_numerical_upgrade($oldversion) {
|
||||||
upgrade_plugin_savepoint(true, 2009100100, 'qtype', 'numerical');
|
upgrade_plugin_savepoint(true, 2009100100, 'qtype', 'numerical');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($oldversion < 2009100101) {
|
||||||
|
|
||||||
|
// Define field instructionsformat to be added to question_numerical_options
|
||||||
|
$table = new xmldb_table('question_numerical_options');
|
||||||
|
$field = new xmldb_field('instructionsformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'instructions');
|
||||||
|
|
||||||
|
// Conditionally launch add field instructionsformat
|
||||||
|
if (!$dbman->field_exists($table, $field)) {
|
||||||
|
$dbman->add_field($table, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rs = $DB->get_recordset('question_numerical_options');
|
||||||
|
foreach ($rs as $record) {
|
||||||
|
if ($CFG->texteditors !== 'textarea') {
|
||||||
|
if (!empty($record->instructions)) {
|
||||||
|
$record->instructions = text_to_html($record->instructions);
|
||||||
|
}
|
||||||
|
$record->instructionsformat = FORMAT_HTML;
|
||||||
|
} else {
|
||||||
|
$record->instructionsformat = FORMAT_MOODLE;
|
||||||
|
}
|
||||||
|
$DB->update_record('question_numerical_options', $record);
|
||||||
|
}
|
||||||
|
$rs->close();
|
||||||
|
|
||||||
|
// numerical savepoint reached
|
||||||
|
upgrade_plugin_savepoint(true, 2009100101, 'qtype', 'numerical');
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
|
|
||||||
<div class="ablock clearfix">
|
<div class="ablock clearfix">
|
||||||
<div class="prompt">
|
<div class="prompt">
|
||||||
<?php echo get_string("answer", "quiz").': '; ?>
|
<?php echo get_string("answer", "quiz").': '; ?>
|
||||||
|
@ -237,7 +233,7 @@
|
||||||
</div>
|
</div>
|
||||||
<?php if (!empty($question->options->instructions)){?>
|
<?php if (!empty($question->options->instructions)){?>
|
||||||
<div>
|
<div>
|
||||||
<?php echo format_text($question->options->instructions, true, $formatoptions, $cmoptions->course);?>
|
<?php echo format_text($question->options->instructions, $question->options->instructionsformat, $formatoptions, $cmoptions->course);?>
|
||||||
</div>
|
</div>
|
||||||
<?php }?>
|
<?php }?>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -250,5 +246,3 @@
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php $this->print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
|
<?php $this->print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the numerical question type.
|
* Defines the editing form for the numerical question type.
|
||||||
*
|
*
|
||||||
|
@ -39,30 +55,36 @@ class question_edit_numerical_form extends question_edit_form {
|
||||||
$creategrades->gradeoptions);
|
$creategrades->gradeoptions);
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
$QTYPES['numerical']->add_units_options($mform,$this);
|
$QTYPES['numerical']->add_units_options($mform,$this);
|
||||||
$QTYPES['numerical']->add_units_elements($mform,$this);
|
$QTYPES['numerical']->add_units_elements($mform,$this);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
global $QTYPES ;
|
global $QTYPES ;
|
||||||
if (isset($question->options)){
|
if (isset($question->options)){
|
||||||
/* $default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
|
||||||
$default_values['unitpenalty'] = $question->options->unitpenalty ;
|
|
||||||
$default_values['showunits'] = $question->options->showunits ;
|
|
||||||
$default_values['unitsleft'] = $question->options->unitsleft ;
|
|
||||||
$default_values['instructions'] = $question->options->instructions ;
|
|
||||||
*/
|
|
||||||
$answers = $question->options->answers;
|
$answers = $question->options->answers;
|
||||||
if (count($answers)) {
|
if (count($answers)) {
|
||||||
$key = 0;
|
$key = 0;
|
||||||
foreach ($answers as $answer){
|
foreach ($answers as $answer){
|
||||||
|
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||||
$default_values['answer['.$key.']'] = $answer->answer;
|
$default_values['answer['.$key.']'] = $answer->answer;
|
||||||
$default_values['fraction['.$key.']'] = $answer->fraction;
|
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||||
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
$default_values['tolerance['.$key.']'] = $answer->tolerance;
|
||||||
$default_values['feedback['.$key.']'] = $answer->feedback;
|
$default_values['feedback['.$key.']'] = array();
|
||||||
|
$default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
|
||||||
|
$default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'question', // component
|
||||||
|
'answerfeedback', // filarea
|
||||||
|
!empty($answer->id)?(int)$answer->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$answer->feedback // text
|
||||||
|
);
|
||||||
|
$default_values['feedback['.$key.']']['itemid'] = $draftid;
|
||||||
$key++;
|
$key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$QTYPES['numerical']->set_numerical_unit_data($question,$default_values);
|
$QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
|
||||||
|
|
||||||
/* if (isset($question->options->units)){
|
/* if (isset($question->options->units)){
|
||||||
$units = array_values($question->options->units);
|
$units = array_values($question->options->units);
|
||||||
|
@ -75,8 +97,9 @@ class question_edit_numerical_form extends question_edit_form {
|
||||||
}*/
|
}*/
|
||||||
$question = (object)((array)$question + $default_values);
|
$question = (object)((array)$question + $default_values);
|
||||||
}
|
}
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validation($data, $files) {
|
function validation($data, $files) {
|
||||||
global $QTYPES;
|
global $QTYPES;
|
||||||
$errors = parent::validation($data, $files);
|
$errors = parent::validation($data, $files);
|
||||||
|
@ -95,7 +118,7 @@ class question_edit_numerical_form extends question_edit_form {
|
||||||
if ($data['fraction'][$key] == 1) {
|
if ($data['fraction'][$key] == 1) {
|
||||||
$maxgrade = true;
|
$maxgrade = true;
|
||||||
}
|
}
|
||||||
} else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key])) {
|
} else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key]['text'])) {
|
||||||
$errors["answer[$key]"] = get_string('answermustbenumberorstar', 'qtype_numerical');
|
$errors["answer[$key]"] = get_string('answermustbenumberorstar', 'qtype_numerical');
|
||||||
$answercount++;
|
$answercount++;
|
||||||
}
|
}
|
||||||
|
@ -110,6 +133,7 @@ class question_edit_numerical_form extends question_edit_form {
|
||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
return 'numerical';
|
return 'numerical';
|
||||||
}
|
}
|
||||||
|
|
31
question/type/numerical/lib.php
Normal file
31
question/type/numerical/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_numerical_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_numerical', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -1,10 +1,26 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Martin Dougiamas and many others. Tim Hunt.
|
* @author Martin Dougiamas and many others. Tim Hunt.
|
||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||||
* @package questionbank
|
* @package questionbank
|
||||||
* @subpackage questiontypes
|
* @subpackage questiontypes
|
||||||
*//** */
|
*/
|
||||||
|
|
||||||
require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
|
require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
|
||||||
|
|
||||||
|
@ -19,6 +35,7 @@ require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
|
||||||
* @package questionbank
|
* @package questionbank
|
||||||
* @subpackage questiontypes
|
* @subpackage questiontypes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class question_numerical_qtype extends question_shortanswer_qtype {
|
class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
|
|
||||||
public $virtualqtype = false;
|
public $virtualqtype = false;
|
||||||
|
@ -52,7 +69,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
$this->get_numerical_units($question);
|
$this->get_numerical_units($question);
|
||||||
//get_numerical_options() need to know if there are units
|
//get_numerical_options() need to know if there are units
|
||||||
// to set correctly default values
|
// to set correctly default values
|
||||||
$this->get_numerical_options($question);
|
$this->get_numerical_options($question);
|
||||||
|
|
||||||
// If units are defined we strip off the default unit from the answer, if
|
// If units are defined we strip off the default unit from the answer, if
|
||||||
|
@ -75,7 +92,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
if (!$options = $DB->get_record('question_numerical_options', array('question' => $question->id))) {
|
if (!$options = $DB->get_record('question_numerical_options', array('question' => $question->id))) {
|
||||||
$question->options->unitgradingtype = 0; // total grade
|
$question->options->unitgradingtype = 0; // total grade
|
||||||
$question->options->unitpenalty = 0;
|
$question->options->unitpenalty = 0;
|
||||||
// the default
|
// the default
|
||||||
if ($defaultunit = $this->get_default_numerical_unit($question)) {
|
if ($defaultunit = $this->get_default_numerical_unit($question)) {
|
||||||
// so units can be graded
|
// so units can be graded
|
||||||
$question->options->showunits = NUMERICALQUESTIONUNITTEXTINPUTDISPLAY ;
|
$question->options->showunits = NUMERICALQUESTIONUNITTEXTINPUTDISPLAY ;
|
||||||
|
@ -85,18 +102,20 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
$question->options->showunits = NUMERICALQUESTIONUNITNODISPLAY ;
|
$question->options->showunits = NUMERICALQUESTIONUNITNODISPLAY ;
|
||||||
}
|
}
|
||||||
$question->options->unitsleft = 0 ;
|
$question->options->unitsleft = 0 ;
|
||||||
$question->options->instructions = '' ;
|
$question->options->instructions = '';
|
||||||
|
$question->options->instructionsformat = editors_get_preferred_format();
|
||||||
} else {
|
} else {
|
||||||
$question->options->unitgradingtype = $options->unitgradingtype;
|
$question->options->unitgradingtype = $options->unitgradingtype;
|
||||||
$question->options->unitpenalty = $options->unitpenalty;
|
$question->options->unitpenalty = $options->unitpenalty;
|
||||||
$question->options->showunits = $options->showunits ;
|
$question->options->showunits = $options->showunits;
|
||||||
$question->options->unitsleft = $options->unitsleft ;
|
$question->options->unitsleft = $options->unitsleft;
|
||||||
$question->options->instructions = $options->instructions ;
|
$question->options->instructions = $options->instructions;
|
||||||
|
$question->options->instructionsformat = $options->instructionsformat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_numerical_units(&$question) {
|
function get_numerical_units(&$question) {
|
||||||
global $DB;
|
global $DB;
|
||||||
if ($units = $DB->get_records('question_numerical_units', array('question' => $question->id), 'id ASC')) {
|
if ($units = $DB->get_records('question_numerical_units', array('question' => $question->id), 'id ASC')) {
|
||||||
|
@ -127,6 +146,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
*/
|
*/
|
||||||
function save_question_options($question) {
|
function save_question_options($question) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
$context = $question->context;
|
||||||
|
|
||||||
// Get old versions of the objects
|
// Get old versions of the objects
|
||||||
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
$oldanswers = array();
|
$oldanswers = array();
|
||||||
|
@ -148,7 +169,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
foreach ($question->answer as $key => $dataanswer) {
|
foreach ($question->answer as $key => $dataanswer) {
|
||||||
// Check for, and ingore, completely blank answer from the form.
|
// Check for, and ingore, completely blank answer from the form.
|
||||||
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
|
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
|
||||||
html_is_blank($question->feedback[$key])) {
|
html_is_blank($question->feedback[$key]['text'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,13 +184,23 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$answer->fraction = $question->fraction[$key];
|
$answer->fraction = $question->fraction[$key];
|
||||||
$answer->feedback = trim($question->feedback[$key]);
|
|
||||||
|
$feedbacktext = trim($question->feedback[$key]['text']);
|
||||||
|
$draftid = $question->feedback[$key]['itemid'];
|
||||||
|
|
||||||
|
|
||||||
|
$answer->feedbackformat = $question->feedback[$key]['format'];
|
||||||
|
|
||||||
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||||
|
$feedbacktext = file_save_draft_area_files($draftid, $context->id, 'question', 'answerfeedback', $oldanswer->id, self::$fileoptions, $feedbacktext);
|
||||||
|
$answer->feedback = $feedbacktext;
|
||||||
$answer->id = $oldanswer->id;
|
$answer->id = $oldanswer->id;
|
||||||
$DB->update_record("question_answers", $answer);
|
$DB->update_record("question_answers", $answer);
|
||||||
} else { // This is a completely new answer
|
} else { // This is a completely new answer
|
||||||
|
$answer->feedback = $feedbacktext;
|
||||||
$answer->id = $DB->insert_record("question_answers", $answer);
|
$answer->id = $DB->insert_record("question_answers", $answer);
|
||||||
|
$feedbacktext = file_save_draft_area_files($draftid, $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $feedbacktext);
|
||||||
|
$DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$answer->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the options object
|
// Set up the options object
|
||||||
|
@ -220,10 +251,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
|
|
||||||
function save_numerical_options(&$question) {
|
function save_numerical_options(&$question) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
|
||||||
$result = new stdClass;
|
$result = new stdClass;
|
||||||
// numerical options
|
// numerical options
|
||||||
$update = true ;
|
$update = true ;
|
||||||
$options = $DB->get_record("question_numerical_options", array("question" => $question->id));
|
$options = $DB->get_record('question_numerical_options', array('question' => $question->id));
|
||||||
if (!$options) {
|
if (!$options) {
|
||||||
$update = false;
|
$update = false;
|
||||||
$options = new stdClass;
|
$options = new stdClass;
|
||||||
|
@ -246,7 +278,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}else {
|
}else {
|
||||||
$options->showunits = $question->showunits1;
|
$options->showunits = $question->showunits1;
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
if(isset($question->showunits)){
|
if(isset($question->showunits)){
|
||||||
$options->showunits = $question->showunits;
|
$options->showunits = $question->showunits;
|
||||||
}else {
|
}else {
|
||||||
|
@ -264,22 +296,27 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}else {
|
}else {
|
||||||
$options->unitsleft = 0 ;
|
$options->unitsleft = 0 ;
|
||||||
}
|
}
|
||||||
|
$options->instructionsformat = $question->instructions['format'];
|
||||||
if(isset($question->instructions)){
|
if(isset($question->instructions)){
|
||||||
$options->instructions = trim($question->instructions);
|
$options->instructions = trim($question->instructions['text']);
|
||||||
}else {
|
}else {
|
||||||
$options->instructions = '' ;
|
$options->instructions = '' ;
|
||||||
}
|
}
|
||||||
|
$component = 'qtype_' . $question->qtype;
|
||||||
|
$options->instructions = file_save_draft_area_files($question->instructions['itemid'],
|
||||||
|
$question->context->id, // context
|
||||||
|
$component, // component
|
||||||
|
'instruction', // filearea
|
||||||
|
$question->id, // itemid
|
||||||
|
self::$fileoptions, // options
|
||||||
|
$question->instructions['text'] // text
|
||||||
|
);
|
||||||
if ($update) {
|
if ($update) {
|
||||||
if (!$DB->update_record("question_numerical_options", $options)) {
|
$DB->update_record("question_numerical_options", $options);
|
||||||
$result->error = "Could not update numerical question options! (id=$options->id)";
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!$DB->insert_record("question_numerical_options", $options)) {
|
$id = $DB->insert_record("question_numerical_options", $options);
|
||||||
$result->error = "Could not insert numerical question options!";
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +357,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
$state->responses = array();
|
$state->responses = array();
|
||||||
$state->responses['answer'] = '';
|
$state->responses['answer'] = '';
|
||||||
$state->responses['unit'] = '';
|
$state->responses['unit'] = '';
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function restore_session_and_responses(&$question, &$state) {
|
function restore_session_and_responses(&$question, &$state) {
|
||||||
|
@ -356,10 +393,10 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
$rawresponse = str_replace($search, $replace, trim($rawresponse));
|
$rawresponse = str_replace($search, $replace, trim($rawresponse));
|
||||||
if (preg_match('~^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$~',
|
if (preg_match('~^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$~',
|
||||||
$rawresponse, $responseparts)) {
|
$rawresponse, $responseparts)) {
|
||||||
if(isset($responseparts[5]) ){
|
if(isset($responseparts[5]) ){
|
||||||
$unit = $responseparts[5] ;
|
$unit = $responseparts[5] ;
|
||||||
}
|
}
|
||||||
if(isset($responseparts[1]) ){
|
if(isset($responseparts[1]) ){
|
||||||
$answer = $responseparts[1] ;
|
$answer = $responseparts[1] ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,30 +441,33 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
*/
|
*/
|
||||||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
|
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
|
||||||
$formatoptions = new stdClass;
|
$formatoptions = new stdClass;
|
||||||
$formatoptions->noclean = true;
|
$formatoptions->noclean = true;
|
||||||
$formatoptions->para = false;
|
$formatoptions->para = false;
|
||||||
$nameprefix = $question->name_prefix;
|
$nameprefix = $question->name_prefix;
|
||||||
|
$component = 'qtype_' . $question->qtype;
|
||||||
|
// rewrite instructions text
|
||||||
|
$question->options->instructions = quiz_rewrite_question_urls($question->options->instructions, 'pluginfile.php', $context->id, $component, 'instruction', array($state->attempt, $state->question), $question->id);
|
||||||
|
|
||||||
/// Print question text and media
|
/// Print question text and media
|
||||||
|
|
||||||
$questiontext = format_text($question->questiontext,
|
$questiontext = format_text($question->questiontext,
|
||||||
$question->questiontextformat,
|
$question->questiontextformat,
|
||||||
$formatoptions, $cmoptions->course);
|
$formatoptions, $cmoptions->course);
|
||||||
$image = get_question_image($question);
|
|
||||||
|
|
||||||
/// Print input controls
|
/// Print input controls
|
||||||
// as the entry is controlled the question type here is numerical
|
// as the entry is controlled the question type here is numerical
|
||||||
// In all cases there is a text input for the number
|
// In all cases there is a text input for the number
|
||||||
// If $question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY
|
// If $question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY
|
||||||
// there is an additional text input for the unit
|
// there is an additional text input for the unit
|
||||||
// If $question->options->showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY"
|
// If $question->options->showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY"
|
||||||
// radio elements display the defined unit
|
// radio elements display the defined unit
|
||||||
// The code allows the input number elememt to be displayed
|
// The code allows the input number elememt to be displayed
|
||||||
// before i.e. at left or after at rigth of the unit variants.
|
// before i.e. at left or after at rigth of the unit variants.
|
||||||
|
$nameanswer = "name=\"".$question->name_prefix."answer\"";
|
||||||
$nameunit = "name=\"".$question->name_prefix."unit\"";
|
$nameunit = "name=\"".$question->name_prefix."unit\"";
|
||||||
$nameanswer = "name=\"".$question->name_prefix."answer\"";
|
|
||||||
if (isset($state->responses['']) && $state->responses[''] != '' && !isset($state->responses['answer'])){
|
if (isset($state->responses['']) && $state->responses[''] != '' && !isset($state->responses['answer'])){
|
||||||
$this->split_old_answer($state->responses[''], $question->options->units, $state->responses['answer'] ,$state->responses['unit'] );
|
$this->split_old_answer($state->responses[''], $question->options->units, $state->responses['answer'] ,$state->responses['unit'] );
|
||||||
}
|
}
|
||||||
|
@ -438,7 +478,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
if (isset($state->responses['unit']) && $state->responses['unit']!='') {
|
if (isset($state->responses['unit']) && $state->responses['unit']!='') {
|
||||||
$valueunit = ' value="'.s($state->responses['unit']).'" ';
|
$valueunit = ' value="'.s($state->responses['unit']).'" ';
|
||||||
} else {
|
} else {
|
||||||
$valueunit = ' value="" ';
|
$valueunit = ' value="" ';
|
||||||
if ($question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ){
|
if ($question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ){
|
||||||
$valueunit = ' value="'.s($question->options->units[0]->unit).'" ';
|
$valueunit = ' value="'.s($question->options->units[0]->unit).'" ';
|
||||||
|
@ -464,72 +504,75 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
//this is OK for the first answer with a good response
|
//this is OK for the first answer with a good response
|
||||||
// having to test for * so response as long as not empty
|
// having to test for * so response as long as not empty
|
||||||
$response = $this->extract_numerical_response($state->responses['answer']);
|
$response = $this->extract_numerical_response($state->responses['answer']);
|
||||||
$break = 0 ;
|
$break = 0 ;
|
||||||
foreach($question->options->answers as $answer) {
|
foreach($question->options->answers as $answer) {
|
||||||
// if * then everything has the $answer->fraction value
|
// if * then everything has the $answer->fraction value
|
||||||
if ($answer->answer !== '*' ) {
|
if ($answer->answer !== '*' ) {
|
||||||
$this->get_tolerance_interval($answer);
|
$this->get_tolerance_interval($answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$answer->feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'question', 'answerfeedback', array($state->attempt, $state->question), $answer->id);
|
||||||
if ($answer->answer === '*') {
|
if ($answer->answer === '*') {
|
||||||
$answerasterisk = true ;
|
$answerasterisk = true ;
|
||||||
$rawgrade = $answer->fraction ;
|
$rawgrade = $answer->fraction ;
|
||||||
$class = question_get_feedback_class($answer->fraction);
|
$class = question_get_feedback_class($answer->fraction);
|
||||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||||
$classunitvalue = $class ;
|
$classunitvalue = $class ;
|
||||||
$classunit = question_get_feedback_class($answer->fraction);
|
$classunit = question_get_feedback_class($answer->fraction);
|
||||||
$feedbackimgunit = question_get_feedback_image($answer->fraction, $options->feedback);
|
$feedbackimgunit = question_get_feedback_image($answer->fraction, $options->feedback);
|
||||||
if ($answer->feedback) {
|
if ($answer->feedback) {
|
||||||
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
||||||
}
|
}
|
||||||
if ( isset($question->options->units))
|
if ( isset($question->options->units))
|
||||||
{
|
{
|
||||||
$valid_numerical_unit = true ;
|
$valid_numerical_unit = true ;
|
||||||
}
|
}
|
||||||
$break = 1 ;
|
$break = 1 ;
|
||||||
} else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
|
} else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
|
||||||
$hasunits = 1 ;
|
$hasunits = 1 ;
|
||||||
foreach($question->options->units as $key => $unit){
|
foreach($question->options->units as $key => $unit){
|
||||||
// The student did type a number, so check it with tolerances.
|
// The student did type a number, so check it with tolerances.
|
||||||
$testresponse = $response /$unit->multiplier ;
|
$testresponse = $response /$unit->multiplier ;
|
||||||
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
|
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
|
||||||
$unittested = $unit->unit ;
|
$unittested = $unit->unit ;
|
||||||
$rawgrade = $answer->fraction ;
|
$rawgrade = $answer->fraction ;
|
||||||
$class = question_get_feedback_class($answer->fraction);
|
$class = question_get_feedback_class($answer->fraction);
|
||||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||||
if ($answer->feedback) {
|
if ($answer->feedback) {
|
||||||
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
||||||
}
|
}
|
||||||
if($state->responses['unit'] == $unit->unit){
|
if($state->responses['unit'] == $unit->unit){
|
||||||
$classunitvalue = $answer->fraction ;
|
$classunitvalue = $answer->fraction ;
|
||||||
}else {
|
}else {
|
||||||
$classunitvalue == 0 ;
|
$classunitvalue == 0 ;
|
||||||
}
|
}
|
||||||
$classunit = question_get_feedback_class($classunitvalue);
|
$classunit = question_get_feedback_class($classunitvalue);
|
||||||
$feedbackimgunit = question_get_feedback_image($classunitvalue, $options->feedback);
|
$feedbackimgunit = question_get_feedback_image($classunitvalue, $options->feedback);
|
||||||
$break = 1 ;
|
$break = 1 ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if($response !== false && ($answer->min <= $response && $response <= $answer->max) ) {
|
} else if($response !== false && ($answer->min <= $response && $response <= $answer->max) ) {
|
||||||
$rawgrade = $answer->fraction ;
|
$rawgrade = $answer->fraction ;
|
||||||
$class = question_get_feedback_class($answer->fraction);
|
$class = question_get_feedback_class($answer->fraction);
|
||||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||||
if ($answer->feedback) {
|
if ($answer->feedback) {
|
||||||
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
$feedback = format_text($answer->feedback, $answer->feedbackformat, $formatoptions, $cmoptions->course);
|
||||||
}
|
}
|
||||||
$break = 1 ;
|
$break = 1 ;
|
||||||
}
|
}
|
||||||
if ($break) break;
|
if ($break) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$state->options->raw_unitpenalty = 0 ;
|
$state->options->raw_unitpenalty = 0 ;
|
||||||
$raw_unitpenalty = 0 ;
|
$raw_unitpenalty = 0 ;
|
||||||
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
||||||
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
|
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
|
||||||
$classunitvalue = 1 ;
|
$classunitvalue = 1 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if($classunitvalue == 0){
|
if($classunitvalue == 0){
|
||||||
if($question->options->unitgradingtype == 1){
|
if($question->options->unitgradingtype == 1){
|
||||||
|
@ -537,10 +580,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}else {
|
}else {
|
||||||
$raw_unitpenalty = $question->options->unitpenalty * $question->maxgrade;
|
$raw_unitpenalty = $question->options->unitpenalty * $question->maxgrade;
|
||||||
}
|
}
|
||||||
$state->options->raw_unitpenalty = $raw_unitpenalty ;
|
$state->options->raw_unitpenalty = $raw_unitpenalty ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Removed correct answer, to be displayed later MDL-7496
|
/// Removed correct answer, to be displayed later MDL-7496
|
||||||
include("$CFG->dirroot/question/type/numerical/display.html");
|
include("$CFG->dirroot/question/type/numerical/display.html");
|
||||||
}
|
}
|
||||||
|
@ -580,7 +622,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
* and but NOT the unit into account. Returns a true for if a response matches the
|
* and but NOT the unit into account. Returns a true for if a response matches the
|
||||||
* answer or in one of the unit , false if it doesn't.
|
* answer or in one of the unit , false if it doesn't.
|
||||||
* the total grading will see if the unit match.
|
* the total grading will see if the unit match.
|
||||||
* if unit != -1 then the test is done only on this unit
|
* if unit != -1 then the test is done only on this unit
|
||||||
*/
|
*/
|
||||||
function test_response(&$question, &$state, $answer ) {
|
function test_response(&$question, &$state, $answer ) {
|
||||||
// Deal with the match anything answer.
|
// Deal with the match anything answer.
|
||||||
|
@ -589,17 +631,17 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
/* To be able to test (old) questions that do not have an unit
|
/* To be able to test (old) questions that do not have an unit
|
||||||
* input element the test is done using the $state->responses['']
|
* input element the test is done using the $state->responses['']
|
||||||
* which contains the response which is analyzed by extract_numerical_response()
|
* which contains the response which is analyzed by extract_numerical_response()
|
||||||
* If the data comes from the numerical or calculated display
|
* If the data comes from the numerical or calculated display
|
||||||
* the $state->responses['unit'] comes from either
|
* the $state->responses['unit'] comes from either
|
||||||
* a multichoice radio element NUMERICALQUESTIONUNITMULTICHOICEDISPLAY
|
* a multichoice radio element NUMERICALQUESTIONUNITMULTICHOICEDISPLAY
|
||||||
* where the $state->responses['unit'] value is the key => unit object
|
* where the $state->responses['unit'] value is the key => unit object
|
||||||
* in the the $question->options->units array
|
* in the the $question->options->units array
|
||||||
* or an input text element NUMERICALUNITTEXTINPUTDISPLAY
|
* or an input text element NUMERICALUNITTEXTINPUTDISPLAY
|
||||||
* which contains the student response
|
* which contains the student response
|
||||||
* for NUMERICALQUESTIONUNITTEXTDISPLAY and NUMERICALQUESTIONUNITNODISPLAY
|
* for NUMERICALQUESTIONUNITTEXTDISPLAY and NUMERICALQUESTIONUNITNODISPLAY
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!isset($state->responses['answer']) && isset($state->responses[''])){
|
if (!isset($state->responses['answer']) && isset($state->responses[''])){
|
||||||
$state->responses['answer'] = $state->responses[''];
|
$state->responses['answer'] = $state->responses[''];
|
||||||
|
@ -611,14 +653,14 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
// The student did type a number, so check it with tolerances.
|
// The student did type a number, so check it with tolerances.
|
||||||
$this->get_tolerance_interval($answer);
|
$this->get_tolerance_interval($answer);
|
||||||
if ($answer->min <= $response && $response <= $answer->max){
|
if ($answer->min <= $response && $response <= $answer->max){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// testing for other units
|
// testing for other units
|
||||||
if ( isset($question->options->units) && count($question->options->units) > 0) {
|
if ( isset($question->options->units) && count($question->options->units) > 0) {
|
||||||
foreach($question->options->units as $key =>$unit){
|
foreach($question->options->units as $key =>$unit){
|
||||||
$testresponse = $response /$unit->multiplier ;
|
$testresponse = $response /$unit->multiplier ;
|
||||||
if($answer->min <= $testresponse && $testresponse<= $answer->max) {
|
if($answer->min <= $testresponse && $testresponse<= $answer->max) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -626,11 +668,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs response processing and grading
|
* Performs response processing and grading
|
||||||
* The function was redefined for handling correctly the two parts
|
* The function was redefined for handling correctly the two parts
|
||||||
* number and unit of numerical or calculated questions
|
* number and unit of numerical or calculated questions
|
||||||
* The code handles also the case when there no unit defined by the user or
|
* The code handles also the case when there no unit defined by the user or
|
||||||
* when used in a multianswer (Cloze) question.
|
* when used in a multianswer (Cloze) question.
|
||||||
* This function performs response processing and grading and updates
|
* This function performs response processing and grading and updates
|
||||||
* the state accordingly.
|
* the state accordingly.
|
||||||
* @return boolean Indicates success or failure.
|
* @return boolean Indicates success or failure.
|
||||||
|
@ -652,7 +694,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
if (!isset($state->responses['answer']) && isset($state->responses[''])){
|
if (!isset($state->responses['answer']) && isset($state->responses[''])){
|
||||||
$state->responses['answer'] = $state->responses[''];
|
$state->responses['answer'] = $state->responses[''];
|
||||||
}
|
}
|
||||||
|
|
||||||
//to apply the unit penalty we need to analyse the response in a more complex way
|
//to apply the unit penalty we need to analyse the response in a more complex way
|
||||||
//the apply_unit() function analysis could be used to obtain the infos
|
//the apply_unit() function analysis could be used to obtain the infos
|
||||||
// however it is used to detect good or bad numbers but also
|
// however it is used to detect good or bad numbers but also
|
||||||
|
@ -664,33 +706,33 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
$hasunits = 0 ;
|
$hasunits = 0 ;
|
||||||
$response = $this->extract_numerical_response($state->responses['answer']);
|
$response = $this->extract_numerical_response($state->responses['answer']);
|
||||||
$answerasterisk = false ;
|
$answerasterisk = false ;
|
||||||
|
|
||||||
$break = 0 ;
|
$break = 0 ;
|
||||||
foreach($question->options->answers as $answer) {
|
foreach($question->options->answers as $answer) {
|
||||||
if ($answer->answer !== '*' ) {
|
if ($answer->answer !== '*' ) {
|
||||||
// The student did type a number, so check it with tolerances.
|
// The student did type a number, so check it with tolerances.
|
||||||
$this->get_tolerance_interval($answer);
|
$this->get_tolerance_interval($answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if * then everything is OK even unit
|
// if * then everything is OK even unit
|
||||||
if ($answer->answer === '*') {
|
if ($answer->answer === '*') {
|
||||||
$state->raw_grade = $answer->fraction;
|
$state->raw_grade = $answer->fraction;
|
||||||
if ( isset($question->options->units)){
|
if ( isset($question->options->units)){
|
||||||
$valid_numerical_unit = true ;
|
$valid_numerical_unit = true ;
|
||||||
}
|
}
|
||||||
$answerasterisk = true ;
|
$answerasterisk = true ;
|
||||||
$break = 1 ;
|
$break = 1 ;
|
||||||
}else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
|
}else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
|
||||||
$hasunits = 1 ;
|
$hasunits = 1 ;
|
||||||
foreach($question->options->units as $key => $unit){
|
foreach($question->options->units as $key => $unit){
|
||||||
$testresponse = $response /$unit->multiplier ;
|
$testresponse = $response /$unit->multiplier ;
|
||||||
|
|
||||||
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
|
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
|
||||||
$state->raw_grade = $answer->fraction;
|
$state->raw_grade = $answer->fraction;
|
||||||
$unittested = $unit->unit ;
|
$unittested = $unit->unit ;
|
||||||
$break = 1 ;
|
$break = 1 ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if ($response !== false) {
|
}else if ($response !== false) {
|
||||||
if($this->test_response($question, $state, $answer)) {
|
if($this->test_response($question, $state, $answer)) {
|
||||||
|
@ -700,9 +742,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
if ($break) break;
|
if ($break) break;
|
||||||
} //foreach($question->options
|
} //foreach($question->options
|
||||||
|
|
||||||
// in all cases the unit should be tested
|
// in all cases the unit should be tested
|
||||||
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
||||||
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
|
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
|
||||||
$valid_numerical_unit = true ;
|
$valid_numerical_unit = true ;
|
||||||
}else {
|
}else {
|
||||||
|
@ -714,7 +756,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
$valid_numerical_unit = true ;
|
$valid_numerical_unit = true ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply unit penalty
|
// apply unit penalty
|
||||||
$raw_unitpenalty = 0 ;
|
$raw_unitpenalty = 0 ;
|
||||||
if(!empty($question->options->unitpenalty)&& $valid_numerical_unit != true ){
|
if(!empty($question->options->unitpenalty)&& $valid_numerical_unit != true ){
|
||||||
|
@ -725,7 +767,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
$state->raw_grade -= $raw_unitpenalty ;
|
$state->raw_grade -= $raw_unitpenalty ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we don't assign negative or too high marks.
|
// Make sure we don't assign negative or too high marks.
|
||||||
$state->raw_grade = min(max((float) $state->raw_grade,
|
$state->raw_grade = min(max((float) $state->raw_grade,
|
||||||
0.0), 1.0) * $question->maxgrade;
|
0.0), 1.0) * $question->maxgrade;
|
||||||
|
@ -857,7 +899,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
// test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don't need spaces and ,
|
// test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don't need spaces and ,
|
||||||
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
|
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
|
||||||
$replace = array('', '');
|
$replace = array('', '');
|
||||||
}else { // remove spaces and normalise , to a . .
|
}else { // remove spaces and normalise , to a . .
|
||||||
$replace = array('', '.');
|
$replace = array('', '.');
|
||||||
}
|
}
|
||||||
$rawresponse = str_replace($search, $replace, $rawresponse);
|
$rawresponse = str_replace($search, $replace, $rawresponse);
|
||||||
|
@ -890,7 +932,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
// test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don't need spaces and ,
|
// test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don't need spaces and ,
|
||||||
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
|
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
|
||||||
$replace = array('', '');
|
$replace = array('', '');
|
||||||
}else { // remove spaces and normalise , to a . .
|
}else { // remove spaces and normalise , to a . .
|
||||||
$replace = array('', '.');
|
$replace = array('', '.');
|
||||||
}
|
}
|
||||||
$rawresponse = str_replace($search, $replace, $rawresponse);
|
$rawresponse = str_replace($search, $replace, $rawresponse);
|
||||||
|
@ -920,10 +962,10 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* function used in function definition_inner()
|
* function used in function definition_inner()
|
||||||
* of edit_..._form.php for
|
* of edit_..._form.php for
|
||||||
* numerical, calculated, calculatedsimple
|
* numerical, calculated, calculatedsimple
|
||||||
*/
|
*/
|
||||||
function add_units_options(&$mform, &$that){
|
function add_units_options(&$mform, &$that){
|
||||||
$mform->addElement('header', 'unithandling', get_string('unitshandling', 'qtype_numerical'));
|
$mform->addElement('header', 'unithandling', get_string('unitshandling', 'qtype_numerical'));
|
||||||
// Units are graded
|
// Units are graded
|
||||||
|
@ -938,8 +980,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
$showunits0grp[] =& $mform->createElement('radio', 'showunits0', get_string('unitedit', 'qtype_numerical'), get_string('editableunittext', 'qtype_numerical'),0);
|
$showunits0grp[] =& $mform->createElement('radio', 'showunits0', get_string('unitedit', 'qtype_numerical'), get_string('editableunittext', 'qtype_numerical'),0);
|
||||||
$showunits0grp[] =& $mform->createElement('radio', 'showunits0', get_string('selectunits', 'qtype_numerical') , get_string('unitchoice', 'qtype_numerical'),1);
|
$showunits0grp[] =& $mform->createElement('radio', 'showunits0', get_string('selectunits', 'qtype_numerical') , get_string('unitchoice', 'qtype_numerical'),1);
|
||||||
$mform->addGroup($showunits0grp, 'showunits0grp', get_string('studentunitanswer', 'qtype_numerical'),' OR ' , false);
|
$mform->addGroup($showunits0grp, 'showunits0grp', get_string('studentunitanswer', 'qtype_numerical'),' OR ' , false);
|
||||||
$mform->addElement('htmleditor', 'instructions', get_string('instructions', 'qtype_numerical'),
|
$mform->addElement('editor', 'instructions', get_string('instructions', 'qtype_numerical'), null, $that->editoroptions);
|
||||||
array('rows' => 10, 'course' => $that->coursefilesid));
|
|
||||||
$mform->addElement('static', 'separator1', '<HR/>', '<HR/>');
|
$mform->addElement('static', 'separator1', '<HR/>', '<HR/>');
|
||||||
// Units are not graded
|
// Units are not graded
|
||||||
$mform->addElement('radio', 'unitrole', get_string('unitnotgraded', 'qtype_numerical'), get_string('onlynumerical', 'qtype_numerical'),1);
|
$mform->addElement('radio', 'unitrole', get_string('unitnotgraded', 'qtype_numerical'), get_string('onlynumerical', 'qtype_numerical'),1);
|
||||||
|
@ -967,6 +1008,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
$mform->disabledIf('unitsleft', 'showunits1','eq','3');
|
$mform->disabledIf('unitsleft', 'showunits1','eq','3');
|
||||||
$mform->disabledIf('showunits1','unitrole','eq','0');
|
$mform->disabledIf('showunits1','unitrole','eq','0');
|
||||||
$mform->disabledIf('showunits0','unitrole','eq','1');
|
$mform->disabledIf('showunits0','unitrole','eq','1');
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -974,7 +1017,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
* of edit_..._form.php for
|
* of edit_..._form.php for
|
||||||
* numerical, calculated, calculatedsimple
|
* numerical, calculated, calculatedsimple
|
||||||
*/
|
*/
|
||||||
function add_units_elements(& $mform,& $that) {
|
function add_units_elements(& $mform,& $that) {
|
||||||
$repeated = array();
|
$repeated = array();
|
||||||
$repeated[] =& $mform->createElement('header', 'unithdr', get_string('unithdr', 'qtype_numerical', '{no}'));
|
$repeated[] =& $mform->createElement('header', 'unithdr', get_string('unithdr', 'qtype_numerical', '{no}'));
|
||||||
|
|
||||||
|
@ -1006,31 +1049,48 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* function used in in function setdata ()
|
* function used in in function data_preprocessing() of edit_numerical_form.php for
|
||||||
* of edit_..._form.php for
|
* numerical, calculated, calculatedsimple
|
||||||
* numerical, calculated, calculatedsimple
|
*/
|
||||||
*/
|
function set_numerical_unit_data($mform, &$question, &$default_values){
|
||||||
function set_numerical_unit_data(&$question,&$default_values){
|
|
||||||
|
list($categoryid) = explode(',', $question->category);
|
||||||
|
$context = $this->get_context_by_category_id($categoryid);
|
||||||
|
|
||||||
if (isset($question->options)){
|
if (isset($question->options)){
|
||||||
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
||||||
$default_values['unitpenalty'] = $question->options->unitpenalty ;
|
$default_values['unitpenalty'] = $question->options->unitpenalty ;
|
||||||
switch ($question->options->showunits){
|
switch ($question->options->showunits){
|
||||||
case 'O' :
|
case 'O' :
|
||||||
case '1' :
|
case '1' :
|
||||||
$default_values['showunits0'] = $question->options->showunits ;
|
$default_values['showunits0'] = $question->options->showunits ;
|
||||||
$default_values['unitrole'] = 0 ;
|
$default_values['unitrole'] = 0 ;
|
||||||
break;
|
break;
|
||||||
case '2' :
|
case '2' :
|
||||||
case '3' :
|
case '3' :
|
||||||
$default_values['showunits1'] = $question->options->showunits ;
|
$default_values['showunits1'] = $question->options->showunits ;
|
||||||
$default_values['unitrole'] = 1 ;
|
$default_values['unitrole'] = 1 ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$default_values['unitsleft'] = $question->options->unitsleft ;
|
$default_values['unitsleft'] = $question->options->unitsleft ;
|
||||||
$default_values['instructions'] = $question->options->instructions ;
|
|
||||||
|
// processing files
|
||||||
if (isset($question->options->units)){
|
$component = 'qtype_' . $question->qtype;
|
||||||
|
$draftid = file_get_submitted_draft_itemid('instructions');
|
||||||
|
$default_values['instructions'] = array();
|
||||||
|
$default_values['instructions']['format'] = $question->options->instructionsformat;
|
||||||
|
$default_values['instructions']['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$context->id, // context
|
||||||
|
$component, // component
|
||||||
|
'instruction', // filarea
|
||||||
|
!empty($question->id)?(int)$question->id:null, // itemid
|
||||||
|
$mform->fileoptions, // options
|
||||||
|
$question->options->instructions // text
|
||||||
|
);
|
||||||
|
$default_values['instructions']['itemid'] = $draftid;
|
||||||
|
|
||||||
|
if (isset($question->options->units)) {
|
||||||
$units = array_values($question->options->units);
|
$units = array_values($question->options->units);
|
||||||
if (!empty($units)) {
|
if (!empty($units)) {
|
||||||
foreach ($units as $key => $unit){
|
foreach ($units as $key => $unit){
|
||||||
|
@ -1042,11 +1102,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* function use in in function validation()
|
* function use in in function validation()
|
||||||
* of edit_..._form.php for
|
* of edit_..._form.php for
|
||||||
* numerical, calculated, calculatedsimple
|
* numerical, calculated, calculatedsimple
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function validate_numerical_options(& $data, & $errors){
|
function validate_numerical_options(& $data, & $errors){
|
||||||
$units = $data['unit'];
|
$units = $data['unit'];
|
||||||
|
@ -1055,9 +1115,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}else {
|
}else {
|
||||||
$showunits = $data['showunits1'];
|
$showunits = $data['showunits1'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($showunits == NUMERICALQUESTIONUNITTEXTINPUTDISPLAY) ||
|
if (($showunits == NUMERICALQUESTIONUNITTEXTINPUTDISPLAY) ||
|
||||||
($showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY ) ||
|
($showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY ) ||
|
||||||
($showunits == NUMERICALQUESTIONUNITTEXTDISPLAY )){
|
($showunits == NUMERICALQUESTIONUNITTEXTDISPLAY )){
|
||||||
if (trim($units[0]) == ''){
|
if (trim($units[0]) == ''){
|
||||||
$errors['unit[0]'] = 'You must set a valid unit name' ;
|
$errors['unit[0]'] = 'You must set a valid unit name' ;
|
||||||
|
@ -1072,8 +1132,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check double units.
|
// Check double units.
|
||||||
$alreadyseenunits = array();
|
$alreadyseenunits = array();
|
||||||
if (isset($data['unit'])) {
|
if (isset($data['unit'])) {
|
||||||
|
@ -1106,7 +1166,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1284,6 +1344,71 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
||||||
|
|
||||||
return $this->save_question($question, $form, $course);
|
return $this->save_question($question, $form, $course);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
$component = 'question';
|
||||||
|
$filearea = 'answerfeedback';
|
||||||
|
foreach ($oldanswers as $answer) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$component = 'qtype_numerical';
|
||||||
|
$filearea = 'instruction';
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
$itemid = reset($args);
|
||||||
|
if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||||
|
$result = $options->feedback && array_key_exists($itemid, $question->options->answers);
|
||||||
|
if (!$result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach($question->options->answers as $answer) {
|
||||||
|
if ($this->test_response($question, $state, $answer)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if ($filearea == 'instruction') {
|
||||||
|
if ($itemid != $question->id) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// INITIATION - Without this line the question type is not in use.
|
// INITIATION - Without this line the question type is not in use.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$plugin->version = 2009100100;
|
$plugin->version = 2009100101;
|
||||||
$plugin->requires = 2007101000;
|
$plugin->requires = 2007101000;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default questiontype class.
|
* The default questiontype class.
|
||||||
*
|
*
|
||||||
|
@ -30,6 +46,7 @@ require_once($CFG->libdir . '/questionlib.php');
|
||||||
* @subpackage questiontypes
|
* @subpackage questiontypes
|
||||||
*/
|
*/
|
||||||
class default_questiontype {
|
class default_questiontype {
|
||||||
|
public static $fileoptions = array('subdirs'=>false, 'maxfiles'=>-1, 'maxbytes'=>0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the question type
|
* Name of the question type
|
||||||
|
@ -294,31 +311,35 @@ class default_questiontype {
|
||||||
*/
|
*/
|
||||||
function save_question($question, $form, $course) {
|
function save_question($question, $form, $course) {
|
||||||
global $USER, $DB, $OUTPUT;
|
global $USER, $DB, $OUTPUT;
|
||||||
|
|
||||||
|
list($question->category) = explode(',', $form->category);
|
||||||
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
|
|
||||||
// This default implementation is suitable for most
|
// This default implementation is suitable for most
|
||||||
// question types.
|
// question types.
|
||||||
|
|
||||||
// First, save the basic question itself
|
// First, save the basic question itself
|
||||||
$question->name = trim($form->name);
|
$question->name = trim($form->name);
|
||||||
$question->questiontext = trim($form->questiontext);
|
|
||||||
$question->questiontextformat = $form->questiontextformat;
|
|
||||||
$question->parent = isset($form->parent) ? $form->parent : 0;
|
$question->parent = isset($form->parent) ? $form->parent : 0;
|
||||||
$question->length = $this->actual_number_of_questions($question);
|
$question->length = $this->actual_number_of_questions($question);
|
||||||
$question->penalty = isset($form->penalty) ? $form->penalty : 0;
|
$question->penalty = isset($form->penalty) ? $form->penalty : 0;
|
||||||
|
|
||||||
if (empty($form->image)) {
|
if (empty($form->questiontext['text'])) {
|
||||||
$question->image = '';
|
$question->questiontext = '';
|
||||||
} else {
|
} else {
|
||||||
$question->image = $form->image;
|
$question->questiontext = trim($form->questiontext['text']);;
|
||||||
}
|
}
|
||||||
|
$question->questiontextformat = !empty($form->questiontext['format'])?$form->questiontext['format']:0;
|
||||||
|
|
||||||
if (empty($form->generalfeedback)) {
|
if (empty($form->generalfeedback['text'])) {
|
||||||
$question->generalfeedback = '';
|
$question->generalfeedback = '';
|
||||||
} else {
|
} else {
|
||||||
$question->generalfeedback = trim($form->generalfeedback);
|
$question->generalfeedback = trim($form->generalfeedback['text']);
|
||||||
}
|
}
|
||||||
|
$question->generalfeedbackformat = !empty($form->generalfeedback['format'])?$form->generalfeedback['format']:0;
|
||||||
|
|
||||||
if (empty($question->name)) {
|
if (empty($question->name)) {
|
||||||
$question->name = shorten_text(strip_tags($question->questiontext), 15);
|
$question->name = shorten_text(strip_tags($form->questiontext['text']), 15);
|
||||||
if (empty($question->name)) {
|
if (empty($question->name)) {
|
||||||
$question->name = '-';
|
$question->name = '-';
|
||||||
}
|
}
|
||||||
|
@ -332,14 +353,16 @@ class default_questiontype {
|
||||||
$question->defaultgrade = $form->defaultgrade;
|
$question->defaultgrade = $form->defaultgrade;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($question->category) = explode(',', $form->category);
|
|
||||||
|
|
||||||
if (!empty($question->id)) {
|
if (!empty($question->id)) {
|
||||||
/// Question already exists, update.
|
/// Question already exists, update.
|
||||||
$question->modifiedby = $USER->id;
|
$question->modifiedby = $USER->id;
|
||||||
$question->timemodified = time();
|
$question->timemodified = time();
|
||||||
$DB->update_record('question', $question);
|
|
||||||
|
|
||||||
|
// process queston text
|
||||||
|
$question->questiontext = file_save_draft_area_files($form->questiontext['itemid'], $context->id, 'question', 'questiontext', (int)$question->id, self::$fileoptions, $question->questiontext);
|
||||||
|
// process feedback text
|
||||||
|
$question->generalfeedback = file_save_draft_area_files($form->generalfeedback['itemid'], $context->id, 'question', 'generalfeedback', (int)$question->id, self::$fileoptions, $question->generalfeedback);
|
||||||
|
$DB->update_record('question', $question);
|
||||||
} else {
|
} else {
|
||||||
/// New question.
|
/// New question.
|
||||||
// Set the unique code
|
// Set the unique code
|
||||||
|
@ -349,6 +372,12 @@ class default_questiontype {
|
||||||
$question->timecreated = time();
|
$question->timecreated = time();
|
||||||
$question->timemodified = time();
|
$question->timemodified = time();
|
||||||
$question->id = $DB->insert_record('question', $question);
|
$question->id = $DB->insert_record('question', $question);
|
||||||
|
// process queston text
|
||||||
|
$question->questiontext = file_save_draft_area_files($form->questiontext['itemid'], $context->id, 'question', 'questiontext', (int)$question->id, self::$fileoptions, $question->questiontext);
|
||||||
|
// process feedback text
|
||||||
|
$question->generalfeedback = file_save_draft_area_files($form->generalfeedback['itemid'], $context->id, 'question', 'generalfeedback', (int)$question->id, self::$fileoptions, $question->generalfeedback);
|
||||||
|
|
||||||
|
$DB->update_record('question', $question);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now to save all the answers and type-specific options
|
// Now to save all the answers and type-specific options
|
||||||
|
@ -356,11 +385,14 @@ class default_questiontype {
|
||||||
$form->qtype = $question->qtype;
|
$form->qtype = $question->qtype;
|
||||||
$form->category = $question->category;
|
$form->category = $question->category;
|
||||||
$form->questiontext = $question->questiontext;
|
$form->questiontext = $question->questiontext;
|
||||||
|
$form->questiontextformat = $question->questiontextformat;
|
||||||
|
// current context
|
||||||
|
$form->context = $context;
|
||||||
|
|
||||||
$result = $this->save_question_options($form);
|
$result = $this->save_question_options($form);
|
||||||
|
|
||||||
if (!empty($result->error)) {
|
if (!empty($result->error)) {
|
||||||
print_error('questionsaveerror', 'question', '', $result->error);
|
print_error($result->error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($result->notice)) {
|
if (!empty($result->notice)) {
|
||||||
|
@ -888,12 +920,18 @@ class default_questiontype {
|
||||||
* @param object $cmoptions
|
* @param object $cmoptions
|
||||||
* @param object $options An object describing the rendering options.
|
* @param object $options An object describing the rendering options.
|
||||||
*/
|
*/
|
||||||
function print_question(&$question, &$state, $number, $cmoptions, $options) {
|
function print_question(&$question, &$state, $number, $cmoptions, $options, $context=null) {
|
||||||
/* The default implementation should work for most question types
|
/* The default implementation should work for most question types
|
||||||
provided the member functions it calls are overridden where required.
|
provided the member functions it calls are overridden where required.
|
||||||
The layout is determined by the template question.html */
|
The layout is determined by the template question.html */
|
||||||
|
|
||||||
global $CFG, $OUTPUT;
|
global $CFG, $OUTPUT;
|
||||||
|
|
||||||
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
|
$question->questiontext = quiz_rewrite_question_urls($question->questiontext, 'pluginfile.php', $context->id, 'question', 'questiontext', array($state->attempt, $state->question), $question->id);
|
||||||
|
|
||||||
|
$question->generalfeedback = quiz_rewrite_question_urls($question->generalfeedback, 'pluginfile.php', $context->id, 'question', 'generalfeedback', array($state->attempt, $state->question), $question->id);
|
||||||
|
|
||||||
$isgraded = question_state_is_graded($state->last_graded);
|
$isgraded = question_state_is_graded($state->last_graded);
|
||||||
|
|
||||||
if (isset($question->randomquestionid)) {
|
if (isset($question->randomquestionid)) {
|
||||||
|
@ -908,7 +946,7 @@ class default_questiontype {
|
||||||
$generalfeedback = '';
|
$generalfeedback = '';
|
||||||
if ($isgraded && $options->generalfeedback) {
|
if ($isgraded && $options->generalfeedback) {
|
||||||
$generalfeedback = $this->format_text($question->generalfeedback,
|
$generalfeedback = $this->format_text($question->generalfeedback,
|
||||||
$question->questiontextformat, $cmoptions);
|
$question->generalfeedbackformat, $cmoptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
$grade = '';
|
$grade = '';
|
||||||
|
@ -1246,6 +1284,22 @@ class default_questiontype {
|
||||||
.' been implemented for question type '.$this->name());
|
.' been implemented for question type '.$this->name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
|
||||||
|
if ($component == 'question' && $filearea == 'questiontext') {
|
||||||
|
// Question text always visible.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if ($component == 'question' && $filearea = 'generalfeedback') {
|
||||||
|
return $options->generalfeedback && question_state_is_graded($state->last_graded);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Unrecognised component or filearea.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the submit button(s) for the question in the given state
|
* Prints the submit button(s) for the question in the given state
|
||||||
*
|
*
|
||||||
|
@ -1494,29 +1548,6 @@ class default_questiontype {
|
||||||
*/
|
*/
|
||||||
function find_file_links($question, $courseid){
|
function find_file_links($question, $courseid){
|
||||||
$urls = array();
|
$urls = array();
|
||||||
|
|
||||||
/// Question image
|
|
||||||
if ($question->image != ''){
|
|
||||||
if (substr(strtolower($question->image), 0, 7) == 'http://') {
|
|
||||||
$matches = array();
|
|
||||||
|
|
||||||
//support for older questions where we have a complete url in image field
|
|
||||||
if (preg_match('!^'.question_file_links_base_url($courseid).'(.*)!i', $question->image, $matches)){
|
|
||||||
if ($cleanedurl = question_url_check($urls[$matches[2]])){
|
|
||||||
$urls[$cleanedurl] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($question->image != ''){
|
|
||||||
if ($cleanedurl = question_url_check($question->image)){
|
|
||||||
$urls[$cleanedurl] = null;//will be set later
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Questiontext and general feedback.
|
/// Questiontext and general feedback.
|
||||||
$urls += question_find_file_links_from_html($question->questiontext, $courseid);
|
$urls += question_find_file_links_from_html($question->questiontext, $courseid);
|
||||||
$urls += question_find_file_links_from_html($question->generalfeedback, $courseid);
|
$urls += question_find_file_links_from_html($question->generalfeedback, $courseid);
|
||||||
|
@ -1557,21 +1588,6 @@ class default_questiontype {
|
||||||
function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){
|
function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){
|
||||||
global $CFG, $DB;
|
global $CFG, $DB;
|
||||||
$updateqrec = false;
|
$updateqrec = false;
|
||||||
|
|
||||||
/// Question image
|
|
||||||
if (!empty($question->image)){
|
|
||||||
//support for older questions where we have a complete url in image field
|
|
||||||
if (substr(strtolower($question->image), 0, 7) == 'http://') {
|
|
||||||
$questionimage = preg_replace('!^'.question_file_links_base_url($fromcourseid).preg_quote($url, '!').'$!i', $destination, $question->image, 1);
|
|
||||||
} else {
|
|
||||||
$questionimage = preg_replace('!^'.preg_quote($url, '!').'$!i', $destination, $question->image, 1);
|
|
||||||
}
|
|
||||||
if ($questionimage != $question->image){
|
|
||||||
$question->image = $questionimage;
|
|
||||||
$updateqrec = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Questiontext and general feedback.
|
/// Questiontext and general feedback.
|
||||||
$question->questiontext = question_replace_file_links_in_html($question->questiontext, $fromcourseid, $tocourseid, $url, $destination, $updateqrec);
|
$question->questiontext = question_replace_file_links_in_html($question->questiontext, $fromcourseid, $tocourseid, $url, $destination, $updateqrec);
|
||||||
$question->generalfeedback = question_replace_file_links_in_html($question->generalfeedback, $fromcourseid, $tocourseid, $url, $destination, $updateqrec);
|
$question->generalfeedback = question_replace_file_links_in_html($question->generalfeedback, $fromcourseid, $tocourseid, $url, $destination, $updateqrec);
|
||||||
|
@ -1802,5 +1818,45 @@ class default_questiontype {
|
||||||
$question->qtype = $this->qtype;
|
$question->qtype = $this->qtype;
|
||||||
return array($form, $question);
|
return array($form, $question);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get question context by category id
|
||||||
|
* @param int $category
|
||||||
|
* @return object $context
|
||||||
|
*/
|
||||||
|
function get_context_by_category_id($category) {
|
||||||
|
global $DB;
|
||||||
|
$contextid = $DB->get_field('question_categories', 'contextid', array('id'=>$category));
|
||||||
|
$context = get_context_instance_by_id($contextid);
|
||||||
|
return $context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
$fs = get_file_storage();
|
||||||
|
$component = 'question';
|
||||||
|
// process general question files
|
||||||
|
// Currently we have questiontext and generalfeedback areas
|
||||||
|
foreach (array('questiontext', 'generalfeedback') as $filearea) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
if ($newcategory->contextid == $question->contextid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$newfile = new object();
|
||||||
|
// only contextid changed
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
// delete old files
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -79,11 +79,13 @@ class question_edit_random_form extends question_edit_form {
|
||||||
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
|
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
|
||||||
$mform->closeHeaderBefore('buttonar');
|
$mform->closeHeaderBefore('buttonar');
|
||||||
}
|
}
|
||||||
|
|
||||||
function validation($fromform, $files) {
|
function validation($fromform, $files) {
|
||||||
//validation of category
|
//validation of category
|
||||||
//is not relevant for this question type
|
//is not relevant for this question type
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
return 'random';
|
return 'random';
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ class random_qtype extends default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
function display_question_editing_page(&$mform, $question, $wizardnow){
|
function display_question_editing_page(&$mform, $question, $wizardnow){
|
||||||
|
global $OUTPUT;
|
||||||
$heading = $this->get_heading(empty($question->id));
|
$heading = $this->get_heading(empty($question->id));
|
||||||
echo $OUTPUT->heading_with_help($heading, $this->name(), $this->plugin_name());
|
echo $OUTPUT->heading_with_help($heading, $this->name(), $this->plugin_name());
|
||||||
$mform->display();
|
$mform->display();
|
||||||
|
@ -424,5 +425,3 @@ class random_qtype extends default_questiontype {
|
||||||
//// INITIATION - Without this line the question type is not in use... ///
|
//// INITIATION - Without this line the question type is not in use... ///
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
question_register_questiontype(new random_qtype());
|
question_register_questiontype(new random_qtype());
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,6 @@ class question_edit_randomsamatch_form extends question_edit_form {
|
||||||
* @param MoodleQuickForm $mform the form being built.
|
* @param MoodleQuickForm $mform the form being built.
|
||||||
*/
|
*/
|
||||||
function definition_inner(&$mform) {
|
function definition_inner(&$mform) {
|
||||||
$mform->removeElement('image');
|
|
||||||
|
|
||||||
$questionstoselect = array();
|
$questionstoselect = array();
|
||||||
for ($i=2; $i<=QUESTION_NUMANS; $i++){
|
for ($i=2; $i<=QUESTION_NUMANS; $i++){
|
||||||
$questionstoselect[$i] = $i;
|
$questionstoselect[$i] = $i;
|
||||||
|
@ -33,15 +31,15 @@ class question_edit_randomsamatch_form extends question_edit_form {
|
||||||
$mform->setType('fraction', PARAM_RAW);
|
$mform->setType('fraction', PARAM_RAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
if (empty($question->name)) {
|
if (empty($question->name)) {
|
||||||
$question->name = get_string("randomsamatch", "quiz");
|
$question->name = get_string("randomsamatch", "quiz");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($question->questiontext)) {
|
if (empty($question->questiontext)) {
|
||||||
$question->questiontext = get_string("randomsamatchintro", "quiz");
|
$question->questiontext = get_string("randomsamatchintro", "quiz");
|
||||||
}
|
}
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
function qtype() {
|
function qtype() {
|
||||||
|
@ -70,7 +68,5 @@ class question_edit_randomsamatch_form extends question_edit_form {
|
||||||
$errors['choose'] = get_string('notenoughsaincategory', 'qtype_randomsamatch', $a);
|
$errors['choose'] = get_string('notenoughsaincategory', 'qtype_randomsamatch', $a);
|
||||||
}
|
}
|
||||||
return $errors;
|
return $errors;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
|
|
||||||
<div class="ablock clearfix">
|
<div class="ablock clearfix">
|
||||||
<div class="prompt">
|
<div class="prompt">
|
||||||
<?php echo get_string("answer", "quiz").': '; ?>
|
<?php echo get_string("answer", "quiz").': '; ?>
|
||||||
|
|
|
@ -1,4 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the shortanswer question type.
|
* Defines the editing form for the shortanswer question type.
|
||||||
*
|
*
|
||||||
|
@ -30,22 +48,40 @@ class question_edit_shortanswer_form extends question_edit_form {
|
||||||
$creategrades->gradeoptions);
|
$creategrades->gradeoptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_data($question) {
|
function data_preprocessing($question) {
|
||||||
if (isset($question->options)){
|
if (isset($question->options)){
|
||||||
$answers = $question->options->answers;
|
$answers = $question->options->answers;
|
||||||
|
$answers_ids = array();
|
||||||
if (count($answers)) {
|
if (count($answers)) {
|
||||||
$key = 0;
|
$key = 0;
|
||||||
foreach ($answers as $answer){
|
foreach ($answers as $answer){
|
||||||
|
$answers_ids[] = $answer->id;
|
||||||
$default_values['answer['.$key.']'] = $answer->answer;
|
$default_values['answer['.$key.']'] = $answer->answer;
|
||||||
$default_values['fraction['.$key.']'] = $answer->fraction;
|
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||||
$default_values['feedback['.$key.']'] = $answer->feedback;
|
$default_values['feedback['.$key.']'] = array();
|
||||||
|
|
||||||
|
// prepare feedback editor to display files in draft area
|
||||||
|
$draftid_editor = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||||
|
$default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
|
||||||
|
$draftid_editor, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'question', // component
|
||||||
|
'answerfeedback', // filarea
|
||||||
|
!empty($answer->id)?(int)$answer->id:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$answer->feedback // text
|
||||||
|
);
|
||||||
|
$default_values['feedback['.$key.']']['itemid'] = $draftid_editor;
|
||||||
|
// prepare files code block ends
|
||||||
|
|
||||||
|
$default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
|
||||||
$key++;
|
$key++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$default_values['usecase'] = $question->options->usecase;
|
$default_values['usecase'] = $question->options->usecase;
|
||||||
$question = (object)((array)$question + $default_values);
|
$question = (object)((array)$question + $default_values);
|
||||||
}
|
}
|
||||||
parent::set_data($question);
|
return $question;
|
||||||
}
|
}
|
||||||
function validation($data, $files) {
|
function validation($data, $files) {
|
||||||
$errors = parent::validation($data, $files);
|
$errors = parent::validation($data, $files);
|
||||||
|
@ -59,7 +95,7 @@ class question_edit_shortanswer_form extends question_edit_form {
|
||||||
if ($data['fraction'][$key] == 1) {
|
if ($data['fraction'][$key] == 1) {
|
||||||
$maxgrade = true;
|
$maxgrade = true;
|
||||||
}
|
}
|
||||||
} else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key])) {
|
} else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key]['text'])) {
|
||||||
$errors["answer[$key]"] = get_string('answermustbegiven', 'qtype_shortanswer');
|
$errors["answer[$key]"] = get_string('answermustbegiven', 'qtype_shortanswer');
|
||||||
$answercount++;
|
$answercount++;
|
||||||
}
|
}
|
||||||
|
|
31
question/type/shortanswer/lib.php
Normal file
31
question/type/shortanswer/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package questionbank
|
||||||
|
* @subpackage questiontypes
|
||||||
|
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_shortanswer_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $DB, $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_shortanswer', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -1,5 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
/// SHORTANSWER ///
|
/// SHORTANSWER ///
|
||||||
///////////////////
|
///////////////////
|
||||||
|
@ -27,17 +42,48 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
function extra_question_fields() {
|
function extra_question_fields() {
|
||||||
return array('question_shortanswer','answers','usecase');
|
return array('question_shortanswer', 'answers', 'usecase');
|
||||||
}
|
}
|
||||||
|
|
||||||
function questionid_column_name() {
|
function questionid_column_name() {
|
||||||
return 'question';
|
return 'question';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
$component = 'question';
|
||||||
|
$filearea = 'answerfeedback';
|
||||||
|
foreach ($oldanswers as $answer) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function save_question_options($question) {
|
function save_question_options($question) {
|
||||||
global $DB;
|
global $DB;
|
||||||
$result = new stdClass;
|
$result = new stdClass;
|
||||||
|
|
||||||
|
$context = $question->context;
|
||||||
|
|
||||||
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
$oldanswers = array();
|
$oldanswers = array();
|
||||||
}
|
}
|
||||||
|
@ -49,23 +95,36 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
foreach ($question->answer as $key => $dataanswer) {
|
foreach ($question->answer as $key => $dataanswer) {
|
||||||
// Check for, and ingore, completely blank answer from the form.
|
// Check for, and ingore, completely blank answer from the form.
|
||||||
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
|
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
|
||||||
html_is_blank($question->feedback[$key])) {
|
html_is_blank($question->feedback[$key]['text'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$feedbackformat = $question->feedback[$key]['format'];
|
||||||
|
|
||||||
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||||
$answer = $oldanswer;
|
$answer = $oldanswer;
|
||||||
$answer->answer = trim($dataanswer);
|
$answer->answer = trim($dataanswer);
|
||||||
$answer->fraction = $question->fraction[$key];
|
$answer->fraction = $question->fraction[$key];
|
||||||
$answer->feedback = $question->feedback[$key];
|
|
||||||
|
// save draft file and rewrite text in feedback
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $oldanswer->id, self::$fileoptions, $question->feedback[$key]['text']);
|
||||||
|
$answer->feedbackformat = $feedbackformat;
|
||||||
|
|
||||||
$DB->update_record("question_answers", $answer);
|
$DB->update_record("question_answers", $answer);
|
||||||
} else { // This is a completely new answer
|
} else { // This is a completely new answer
|
||||||
$answer = new stdClass;
|
$answer = new stdClass;
|
||||||
$answer->answer = trim($dataanswer);
|
$answer->answer = trim($dataanswer);
|
||||||
$answer->question = $question->id;
|
$answer->question = $question->id;
|
||||||
$answer->fraction = $question->fraction[$key];
|
$answer->fraction = $question->fraction[$key];
|
||||||
$answer->feedback = $question->feedback[$key];
|
// feedback content needs to be rewriten
|
||||||
|
$answer->feedback = '';
|
||||||
|
$answer->feedbackformat = $feedbackformat;
|
||||||
$answer->id = $DB->insert_record("question_answers", $answer);
|
$answer->id = $DB->insert_record("question_answers", $answer);
|
||||||
|
|
||||||
|
// save draft file and rewrite text in feedback
|
||||||
|
$answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']);
|
||||||
|
// update feedback content
|
||||||
|
$DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id));
|
||||||
}
|
}
|
||||||
$answers[] = $answer->id;
|
$answers[] = $answer->id;
|
||||||
if ($question->fraction[$key] > $maxfraction) {
|
if ($question->fraction[$key] > $maxfraction) {
|
||||||
|
@ -97,6 +156,8 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||||
|
global $CFG;
|
||||||
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
/// This implementation is also used by question type 'numerical'
|
/// This implementation is also used by question type 'numerical'
|
||||||
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
|
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
|
||||||
$formatoptions = new stdClass;
|
$formatoptions = new stdClass;
|
||||||
|
@ -109,7 +170,6 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
$questiontext = format_text($question->questiontext,
|
$questiontext = format_text($question->questiontext,
|
||||||
$question->questiontextformat,
|
$question->questiontextformat,
|
||||||
$formatoptions, $cmoptions->course);
|
$formatoptions, $cmoptions->course);
|
||||||
$image = get_question_image($question);
|
|
||||||
|
|
||||||
/// Print input controls
|
/// Print input controls
|
||||||
|
|
||||||
|
@ -135,6 +195,7 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
$class = question_get_feedback_class($answer->fraction);
|
$class = question_get_feedback_class($answer->fraction);
|
||||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||||
if ($answer->feedback) {
|
if ($answer->feedback) {
|
||||||
|
$answer->feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'question', 'answerfeedback', array($state->attempt, $state->question), $answer->id);
|
||||||
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -145,7 +206,7 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
/// Removed correct answer, to be displayed later MDL-7496
|
/// Removed correct answer, to be displayed later MDL-7496
|
||||||
include($this->get_display_html_path());
|
include($this->get_display_html_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_display_html_path() {
|
function get_display_html_path() {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
return $CFG->dirroot.'/question/type/shortanswer/display.html';
|
return $CFG->dirroot.'/question/type/shortanswer/display.html';
|
||||||
|
@ -330,12 +391,12 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
// print grade for this submission
|
// print grade for this submission
|
||||||
print_string('gradingdetails', 'quiz', $grade) ;
|
print_string('gradingdetails', 'quiz', $grade) ;
|
||||||
// A unit penalty for numerical was applied so display it
|
// A unit penalty for numerical was applied so display it
|
||||||
// a temporary solution for unit rendering in numerical
|
// a temporary solution for unit rendering in numerical
|
||||||
// waiting for the new question engine code for a permanent one
|
// waiting for the new question engine code for a permanent one
|
||||||
if(isset($state->options->raw_unitpenalty) && $state->options->raw_unitpenalty > 0.0 ){
|
if(isset($state->options->raw_unitpenalty) && $state->options->raw_unitpenalty > 0.0 ){
|
||||||
echo ' ';
|
echo ' ';
|
||||||
print_string('unitappliedpenalty','qtype_numerical',question_format_grade($cmoptions, $state->options->raw_unitpenalty ));
|
print_string('unitappliedpenalty','qtype_numerical',question_format_grade($cmoptions, $state->options->raw_unitpenalty ));
|
||||||
}
|
}
|
||||||
if ($cmoptions->penaltyscheme) {
|
if ($cmoptions->penaltyscheme) {
|
||||||
// print details of grade adjustment due to penalties
|
// print details of grade adjustment due to penalties
|
||||||
if ($state->last_graded->raw_grade > $state->last_graded->grade){
|
if ($state->last_graded->raw_grade > $state->last_graded->grade){
|
||||||
|
@ -390,6 +451,33 @@ class question_shortanswer_qtype extends default_questiontype {
|
||||||
|
|
||||||
return $this->save_question($question, $form, $course);
|
return $this->save_question($question, $form, $course);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||||
|
$answers = &$question->options->answers;
|
||||||
|
if (isset($state->responses[''])) {
|
||||||
|
$response = $state->responses[''];
|
||||||
|
} else {
|
||||||
|
$response = '';
|
||||||
|
}
|
||||||
|
$answerid = reset($args); // itemid is answer id.
|
||||||
|
if (empty($options->feedback)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach($answers as $answer) {
|
||||||
|
if ($this->test_response($question, $state, $answer)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//// END OF CLASS ////
|
//// END OF CLASS ////
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
<?php echo $questiontext; ?>
|
<?php echo $questiontext; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($image) { ?>
|
|
||||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
|
||||||
<?php } ?>
|
|
||||||
|
|
||||||
<div class="ablock clearfix">
|
<div class="ablock clearfix">
|
||||||
<div class="prompt">
|
<div class="prompt">
|
||||||
<?php print_string('answer', 'quiz') ?>:
|
<?php print_string('answer', 'quiz') ?>:
|
||||||
|
@ -27,4 +23,4 @@
|
||||||
</div>
|
</div>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php $this->print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
|
<?php $this->print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
if (!defined('MOODLE_INTERNAL')) {
|
if (!defined('MOODLE_INTERNAL')) {
|
||||||
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
|
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once($CFG->dirroot.'/question/type/edit_question_form.php');
|
require_once($CFG->dirroot.'/question/type/edit_question_form.php');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the editing form for the thruefalse question type.
|
* Defines the editing form for the thruefalse question type.
|
||||||
*
|
*
|
||||||
|
@ -12,7 +29,7 @@ require_once($CFG->dirroot.'/question/type/edit_question_form.php');
|
||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||||
* @package questionbank
|
* @package questionbank
|
||||||
* @subpackage questiontypes
|
* @subpackage questiontypes
|
||||||
*//** */
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* truefalse editing form definition.
|
* truefalse editing form definition.
|
||||||
|
@ -27,12 +44,10 @@ class question_edit_truefalse_form extends question_edit_form {
|
||||||
$mform->addElement('select', 'correctanswer', get_string('correctanswer', 'qtype_truefalse'),
|
$mform->addElement('select', 'correctanswer', get_string('correctanswer', 'qtype_truefalse'),
|
||||||
array(0 => get_string('false', 'qtype_truefalse'), 1 => get_string('true', 'qtype_truefalse')));
|
array(0 => get_string('false', 'qtype_truefalse'), 1 => get_string('true', 'qtype_truefalse')));
|
||||||
|
|
||||||
$mform->addElement('htmleditor', 'feedbacktrue', get_string('feedbacktrue', 'qtype_truefalse'),
|
$mform->addElement('editor', 'feedbacktrue', get_string('feedbacktrue', 'qtype_truefalse'), null, $this->editoroptions);;
|
||||||
array('course' => $this->coursefilesid));;
|
|
||||||
$mform->setType('feedbacktrue', PARAM_RAW);
|
$mform->setType('feedbacktrue', PARAM_RAW);
|
||||||
|
|
||||||
$mform->addElement('htmleditor', 'feedbackfalse', get_string('feedbackfalse', 'qtype_truefalse'),
|
$mform->addElement('editor', 'feedbackfalse', get_string('feedbackfalse', 'qtype_truefalse'), null, $this->editoroptions);
|
||||||
array('course' => $this->coursefilesid));
|
|
||||||
$mform->setType('feedbackfalse', PARAM_RAW);
|
$mform->setType('feedbackfalse', PARAM_RAW);
|
||||||
|
|
||||||
// Fix penalty factor at 1.
|
// Fix penalty factor at 1.
|
||||||
|
@ -43,9 +58,45 @@ class question_edit_truefalse_form extends question_edit_form {
|
||||||
function set_data($question) {
|
function set_data($question) {
|
||||||
if (!empty($question->options->trueanswer)) {
|
if (!empty($question->options->trueanswer)) {
|
||||||
$trueanswer = $question->options->answers[$question->options->trueanswer];
|
$trueanswer = $question->options->answers[$question->options->trueanswer];
|
||||||
|
$draftid = file_get_submitted_draft_itemid('trueanswer');
|
||||||
|
$answerid = $question->options->trueanswer;
|
||||||
|
$text = $trueanswer->feedback;
|
||||||
|
|
||||||
$question->correctanswer = ($trueanswer->fraction != 0);
|
$question->correctanswer = ($trueanswer->fraction != 0);
|
||||||
$question->feedbacktrue = $trueanswer->feedback;
|
$question->feedbacktrue = array();
|
||||||
$question->feedbackfalse = $question->options->answers[$question->options->falseanswer]->feedback;
|
$question->feedbacktrue['text'] = $trueanswer->feedback;
|
||||||
|
$question->feedbacktrue['format'] = $trueanswer->feedbackformat;
|
||||||
|
$question->feedbacktrue['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'question', // component
|
||||||
|
'answerfeedback', // filarea
|
||||||
|
!empty($answerid)?(int)$answerid:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$text // text
|
||||||
|
);
|
||||||
|
$question->feedbacktrue['itemid'] = $draftid;
|
||||||
|
}
|
||||||
|
if (!empty($question->options->falseanswer)) {
|
||||||
|
$falseanswer = $question->options->answers[$question->options->falseanswer];
|
||||||
|
$draftid = file_get_submitted_draft_itemid('falseanswer');
|
||||||
|
$answerid = $question->options->falseanswer;
|
||||||
|
$text = $falseanswer->feedback;
|
||||||
|
|
||||||
|
$question->correctanswer = ($falseanswer->fraction != 0);
|
||||||
|
$question->feedbackfalse = array();
|
||||||
|
$question->feedbackfalse['text'] = $falseanswer->feedback;
|
||||||
|
$question->feedbackfalse['format'] = $falseanswer->feedbackformat;
|
||||||
|
$question->feedbackfalse['text'] = file_prepare_draft_area(
|
||||||
|
$draftid, // draftid
|
||||||
|
$this->context->id, // context
|
||||||
|
'question', // component
|
||||||
|
'answerfeedback', // filarea
|
||||||
|
!empty($answerid)?(int)$answerid:null, // itemid
|
||||||
|
$this->fileoptions, // options
|
||||||
|
$text // text
|
||||||
|
);
|
||||||
|
$question->feedbackfalse['itemid'] = $draftid;
|
||||||
}
|
}
|
||||||
parent::set_data($question);
|
parent::set_data($question);
|
||||||
}
|
}
|
||||||
|
|
31
question/type/truefalse/lib.php
Normal file
31
question/type/truefalse/lib.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve question type files
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @package qtype
|
||||||
|
* @subpackage qtype_truefalse
|
||||||
|
* @copyright The Open Unviersity
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
function qtype_truefalse_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
question_pluginfile($course, $context, 'qtype_truefalse', $filearea, $args, $forcedownload);
|
||||||
|
}
|
|
@ -1,5 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// This file is part of Moodle - http://moodle.org/
|
||||||
|
//
|
||||||
|
// Moodle is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Moodle is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
/// TRUEFALSE ///
|
/// TRUEFALSE ///
|
||||||
/////////////////
|
/////////////////
|
||||||
|
@ -24,34 +41,52 @@ class question_truefalse_qtype extends default_questiontype {
|
||||||
$oldanswers = array();
|
$oldanswers = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$feedbacktext = $question->feedbacktrue['text'];
|
||||||
|
$feedbackitemid = $question->feedbacktrue['itemid'];
|
||||||
|
$feedbackformat = $question->feedbacktrue['format'];
|
||||||
// Save answer 'True'
|
// Save answer 'True'
|
||||||
if ($true = array_shift($oldanswers)) { // Existing answer, so reuse it
|
if ($true = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||||
$true->answer = get_string("true", "quiz");
|
$true->answer = get_string("true", "quiz");
|
||||||
$true->fraction = $question->correctanswer;
|
$true->fraction = $question->correctanswer;
|
||||||
$true->feedback = $question->feedbacktrue;
|
$true->feedback = $question->feedbacktrue;
|
||||||
|
$true->feedback = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $true->id, self::$fileoptions, $feedbacktext);
|
||||||
|
$true->feedbackformat = $feedbackformat;
|
||||||
$DB->update_record("question_answers", $true);
|
$DB->update_record("question_answers", $true);
|
||||||
} else {
|
} else {
|
||||||
unset($true);
|
unset($true);
|
||||||
|
$true = new stdclass;
|
||||||
$true->answer = get_string("true", "quiz");
|
$true->answer = get_string("true", "quiz");
|
||||||
$true->question = $question->id;
|
$true->question = $question->id;
|
||||||
$true->fraction = $question->correctanswer;
|
$true->fraction = $question->correctanswer;
|
||||||
$true->feedback = $question->feedbacktrue;
|
$true->feedback = '';
|
||||||
|
$true->feedbackformat = $feedbackformat;
|
||||||
$true->id = $DB->insert_record("question_answers", $true);
|
$true->id = $DB->insert_record("question_answers", $true);
|
||||||
|
$feedbacktext = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $true->id, self::$fileoptions, $feedbacktext);
|
||||||
|
$DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$true->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$feedbacktext = $question->feedbackfalse['text'];
|
||||||
|
$feedbackitemid = $question->feedbackfalse['itemid'];
|
||||||
|
$feedbackformat = $question->feedbackfalse['format'];
|
||||||
|
|
||||||
// Save answer 'False'
|
// Save answer 'False'
|
||||||
if ($false = array_shift($oldanswers)) { // Existing answer, so reuse it
|
if ($false = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||||
$false->answer = get_string("false", "quiz");
|
$false->answer = get_string("false", "quiz");
|
||||||
$false->fraction = 1 - (int)$question->correctanswer;
|
$false->fraction = 1 - (int)$question->correctanswer;
|
||||||
$false->feedback = $question->feedbackfalse;
|
$false->feedback = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $false->id, self::$fileoptions, $feedbacktext);
|
||||||
|
$false->feedbackformat = $feedbackformat;
|
||||||
$DB->update_record("question_answers", $false);
|
$DB->update_record("question_answers", $false);
|
||||||
} else {
|
} else {
|
||||||
unset($false);
|
unset($false);
|
||||||
|
$false = new stdclass;
|
||||||
$false->answer = get_string("false", "quiz");
|
$false->answer = get_string("false", "quiz");
|
||||||
$false->question = $question->id;
|
$false->question = $question->id;
|
||||||
$false->fraction = 1 - (int)$question->correctanswer;
|
$false->fraction = 1 - (int)$question->correctanswer;
|
||||||
$false->feedback = $question->feedbackfalse;
|
$false->feedback = '';
|
||||||
|
$false->feedbackformat = $feedbackformat;
|
||||||
$false->id = $DB->insert_record("question_answers", $false);
|
$false->id = $DB->insert_record("question_answers", $false);
|
||||||
|
$feedbacktext = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $false->id, self::$fileoptions, $feedbacktext);
|
||||||
|
$DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$false->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete any leftover old answer records (there couldn't really be any, but who knows)
|
// delete any leftover old answer records (there couldn't really be any, but who knows)
|
||||||
|
@ -134,9 +169,9 @@ class question_truefalse_qtype extends default_questiontype {
|
||||||
/**
|
/**
|
||||||
* Prints the main content of the question including any interactions
|
* Prints the main content of the question including any interactions
|
||||||
*/
|
*/
|
||||||
function print_question_formulation_and_controls(&$question, &$state,
|
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||||
$cmoptions, $options) {
|
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
$context = $this->get_context_by_category_id($question->category);
|
||||||
|
|
||||||
$readonly = $options->readonly ? ' disabled="disabled"' : '';
|
$readonly = $options->readonly ? ' disabled="disabled"' : '';
|
||||||
|
|
||||||
|
@ -148,7 +183,6 @@ class question_truefalse_qtype extends default_questiontype {
|
||||||
$questiontext = format_text($question->questiontext,
|
$questiontext = format_text($question->questiontext,
|
||||||
$question->questiontextformat,
|
$question->questiontextformat,
|
||||||
$formatoptions, $cmoptions->course);
|
$formatoptions, $cmoptions->course);
|
||||||
$image = get_question_image($question);
|
|
||||||
|
|
||||||
$answers = &$question->options->answers;
|
$answers = &$question->options->answers;
|
||||||
$trueanswer = &$answers[$question->options->trueanswer];
|
$trueanswer = &$answers[$question->options->trueanswer];
|
||||||
|
@ -198,12 +232,33 @@ class question_truefalse_qtype extends default_questiontype {
|
||||||
$feedback = '';
|
$feedback = '';
|
||||||
if ($options->feedback and isset($answers[$response])) {
|
if ($options->feedback and isset($answers[$response])) {
|
||||||
$chosenanswer = $answers[$response];
|
$chosenanswer = $answers[$response];
|
||||||
|
$chosenanswer->feedback = quiz_rewrite_question_urls($chosenanswer->feedback, 'pluginfile.php', $context->id, 'question', 'answerfeedback', array($state->attempt, $state->question), $chosenanswer->id);
|
||||||
$feedback = format_text($chosenanswer->feedback, true, $formatoptions, $cmoptions->course);
|
$feedback = format_text($chosenanswer->feedback, true, $formatoptions, $cmoptions->course);
|
||||||
}
|
}
|
||||||
|
|
||||||
include("$CFG->dirroot/question/type/truefalse/display.html");
|
include("$CFG->dirroot/question/type/truefalse/display.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args) {
|
||||||
|
if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||||
|
|
||||||
|
$answerid = reset($args); // itemid is answer id.
|
||||||
|
$answers = &$question->options->answers;
|
||||||
|
if (isset($state->responses[''])) {
|
||||||
|
$response = $state->responses[''];
|
||||||
|
} else {
|
||||||
|
$response = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options->feedback && isset($answers[$response]) && $answerid == $response;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||||
|
$filearea, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function grade_responses(&$question, &$state, $cmoptions) {
|
function grade_responses(&$question, &$state, $cmoptions) {
|
||||||
if (isset($state->responses['']) && isset($question->options->answers[$state->responses['']])) {
|
if (isset($state->responses['']) && isset($question->options->answers[$state->responses['']])) {
|
||||||
$state->raw_grade = $question->options->answers[$state->responses['']]->fraction * $question->maxgrade;
|
$state->raw_grade = $question->options->answers[$state->responses['']]->fraction * $question->maxgrade;
|
||||||
|
@ -363,6 +418,34 @@ class question_truefalse_qtype extends default_questiontype {
|
||||||
|
|
||||||
return $this->save_question($question, $form, $course);
|
return $this->save_question($question, $form, $course);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* When move the category of questions, the belonging files should be moved as well
|
||||||
|
* @param object $question, question information
|
||||||
|
* @param object $newcategory, target category information
|
||||||
|
*/
|
||||||
|
function move_files($question, $newcategory) {
|
||||||
|
global $DB;
|
||||||
|
parent::move_files($question, $newcategory);
|
||||||
|
|
||||||
|
$fs = get_file_storage();
|
||||||
|
// process files in answer
|
||||||
|
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||||
|
$oldanswers = array();
|
||||||
|
}
|
||||||
|
$component = 'question';
|
||||||
|
$filearea = 'answerfeedback';
|
||||||
|
foreach ($oldanswers as $answer) {
|
||||||
|
$files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
|
||||||
|
foreach ($files as $storedfile) {
|
||||||
|
if (!$storedfile->is_directory()) {
|
||||||
|
$newfile = new object();
|
||||||
|
$newfile->contextid = (int)$newcategory->contextid;
|
||||||
|
$fs->create_file_from_storedfile($newfile, $storedfile);
|
||||||
|
$storedfile->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//// END OF CLASS ////
|
//// END OF CLASS ////
|
||||||
|
|
||||||
|
@ -370,4 +453,3 @@ class question_truefalse_qtype extends default_questiontype {
|
||||||
//// INITIATION - Without this line the question type is not in use... ///
|
//// INITIATION - Without this line the question type is not in use... ///
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
question_register_questiontype(new question_truefalse_qtype());
|
question_register_questiontype(new question_truefalse_qtype());
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// This is compared against the values stored in the database to determine
|
// This is compared against the values stored in the database to determine
|
||||||
// whether upgrades should be performed (see lib/db/*.php)
|
// whether upgrades should be performed (see lib/db/*.php)
|
||||||
|
|
||||||
$version = 2010080307; // YYYYMMDD = date of the last version bump
|
$version = 2010080901; // YYYYMMDD = date of the last version bump
|
||||||
// XX = daily increments
|
// XX = daily increments
|
||||||
|
|
||||||
$release = '2.0 Preview 4+ (Build: 20100810)'; // Human-friendly version name
|
$release = '2.0 Preview 4+ (Build: 20100810)'; // Human-friendly version name
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue