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" ?>
|
||||
<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"
|
||||
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="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="info" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="stamp"/>
|
||||
<FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="info" NEXT="parent"/>
|
||||
<FIELD NAME="info" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="infoformat"/>
|
||||
<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="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="999" SEQUENCE="false" PREVIOUS="parent"/>
|
||||
</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="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="questiontextformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="questiontext" NEXT="image"/>
|
||||
<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="image" 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="questiontextformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="questiontext" 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="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="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="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"/>
|
||||
|
@ -1293,9 +1294,11 @@
|
|||
<FIELDS>
|
||||
<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="answer" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="fraction"/>
|
||||
<FIELD NAME="fraction" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="answer" NEXT="feedback"/>
|
||||
<FIELD NAME="feedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="fraction"/>
|
||||
<FIELD NAME="answer" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="answerformat"/>
|
||||
<FIELD NAME="answerformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="answer" NEXT="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>
|
||||
<KEYS>
|
||||
<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="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="manualcomment" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="sumpenalty" 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="manualcomment"/>
|
||||
<FIELD NAME="manualcomment" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="sumpenalty" NEXT="manualcommentformat"/>
|
||||
<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>
|
||||
<KEYS>
|
||||
<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"/>
|
||||
</KEYS>
|
||||
</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>
|
||||
<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"/>
|
||||
|
@ -2709,4 +2713,4 @@
|
|||
</KEYS>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
</XMLDB>
|
||||
|
|
|
@ -4911,7 +4911,170 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -851,18 +851,31 @@ function question_delete_activity($cm, $feedback=true) {
|
|||
*
|
||||
* @global object
|
||||
* @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) {
|
||||
global $DB;
|
||||
|
||||
function question_move_questions_to_category($questionids, $newcategoryid) {
|
||||
global $DB, $QTYPES;
|
||||
$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.
|
||||
$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.
|
||||
$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.
|
||||
|
||||
|
@ -1080,6 +1093,7 @@ function question_load_states(&$questions, &$states, $cmoptions, $attempt, $last
|
|||
$states[$qid]->last_graded = clone($states[$qid]);
|
||||
}
|
||||
} else {
|
||||
|
||||
if ($lastattemptid) {
|
||||
// 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
|
||||
|
@ -2091,7 +2105,7 @@ function question_init_qengine_js() {
|
|||
$module = array(
|
||||
'name' => 'core_question_flags',
|
||||
'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';
|
||||
$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 $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;
|
||||
$QTYPES[$question->qtype]->print_question($question, $state, $number, $cmoptions, $options);
|
||||
$QTYPES[$question->qtype]->print_question($question, $state, $number, $cmoptions, $options, $context);
|
||||
}
|
||||
/**
|
||||
* Saves question options
|
||||
|
@ -3191,4 +3205,124 @@ class question_edit_contexts {
|
|||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -571,7 +575,7 @@ class quiz_attempt extends quiz {
|
|||
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() {
|
||||
return $this->attempt->preview;
|
||||
}
|
||||
|
@ -629,10 +633,12 @@ class quiz_attempt extends quiz {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function get_render_options($state) {
|
||||
return quiz_get_renderoptions($this->quiz, $this->attempt, $this->context, $state);
|
||||
public function get_render_options($questionid) {
|
||||
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_EVENTCLOSE:
|
||||
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) {
|
||||
return question_get_feedback_class($state->last_graded->raw_grade /
|
||||
$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.
|
||||
*/
|
||||
public function get_question_score($questionid) {
|
||||
$options = $this->get_render_options($this->states[$questionid]);
|
||||
$options = $this->get_render_options($questionid);
|
||||
if ($options->scores) {
|
||||
return quiz_format_question_grade($this->quiz, $this->states[$questionid]->last_graded->grade);
|
||||
} else {
|
||||
|
@ -805,7 +811,7 @@ class quiz_attempt extends quiz {
|
|||
if ($reviewing) {
|
||||
$options = $this->get_review_options();
|
||||
} else {
|
||||
$options = $this->get_render_options($this->states[$id]);
|
||||
$options = $this->get_render_options($id);
|
||||
}
|
||||
if ($thispageurl) {
|
||||
$this->quiz->thispageurl = $thispageurl;
|
||||
|
@ -816,6 +822,20 @@ class quiz_attempt extends quiz {
|
|||
$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.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
|
@ -100,8 +100,9 @@
|
|||
<FIELDS>
|
||||
<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="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="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="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="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"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
|
|
|
@ -341,6 +341,22 @@ function xmldb_quiz_upgrade($oldversion) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@
|
|||
$grade = get_string('outofshort', 'quiz', $a);
|
||||
}
|
||||
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;
|
||||
|
|
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) {
|
||||
global $DB;
|
||||
$cmid = $quiz->coursemodule;
|
||||
|
||||
// Process the options from the form.
|
||||
$quiz->created = time();
|
||||
|
@ -982,10 +983,10 @@ function quiz_process_options(&$quiz) {
|
|||
if (isset($quiz->feedbacktext)) {
|
||||
// Clean up the boundary text.
|
||||
for ($i = 0; $i < count($quiz->feedbacktext); $i += 1) {
|
||||
if (empty($quiz->feedbacktext[$i])) {
|
||||
$quiz->feedbacktext[$i] = '';
|
||||
if (empty($quiz->feedbacktext[$i]['text'])) {
|
||||
$quiz->feedbacktext[$i]['text'] = '';
|
||||
} 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1145,17 +1146,25 @@ function quiz_process_options(&$quiz) {
|
|||
*/
|
||||
function quiz_after_add_or_update($quiz) {
|
||||
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
|
||||
$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->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->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.
|
||||
|
@ -1421,23 +1430,44 @@ function quiz_reset_userdata($data) {
|
|||
* @param int $questionid int question id
|
||||
* @return boolean to indicate access granted or denied
|
||||
*/
|
||||
function quiz_check_file_access($attemptuniqueid, $questionid) {
|
||||
global $USER, $DB;
|
||||
function quiz_check_file_access($attemptuniqueid, $questionid, $context = null) {
|
||||
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));
|
||||
$quiz = $DB->get_record('quiz', array('id' => $attempt->quiz));
|
||||
$context = get_context_instance(CONTEXT_COURSE, $quiz->course);
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
|
||||
// access granted if the current user submitted this file
|
||||
if ($attempt->userid == $USER->id) {
|
||||
return true;
|
||||
// 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;
|
||||
// does question exist?
|
||||
if (!$question = $DB->get_record('question', array('id' => $questionid))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// otherwise, this user does not have permission
|
||||
return false;
|
||||
if ($context === null) {
|
||||
$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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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;
|
||||
$feedback = $DB->get_field_select('quiz_feedback', 'feedbacktext',
|
||||
"quizid = ? AND mingrade <= ? AND $grade < maxgrade", array($quizid, $grade));
|
||||
|
||||
if (empty($feedback)) {
|
||||
$feedback = '';
|
||||
$feedback = $DB->get_record_select('quiz_feedback', "quizid = ? AND mingrade <= ? AND $grade < maxgrade", array($quiz->id, $grade));
|
||||
|
||||
if (empty($feedback->feedbacktext)) {
|
||||
$feedback->feedbacktext = '';
|
||||
}
|
||||
|
||||
// Clean the text, ready for display.
|
||||
$formatoptions = new stdClass;
|
||||
$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'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,7 +296,7 @@ class mod_quiz_mod_form extends moodleform_mod {
|
|||
$mform->addElement('static', 'gradeboundarystatic1', get_string('gradeboundary', 'quiz'), '100%');
|
||||
|
||||
$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);
|
||||
$repeatarray[] = &MoodleQuickForm::createElement('text', 'feedbackboundaries', get_string('gradeboundary', 'quiz'), array('size' => 10));
|
||||
$mform->setType('feedbackboundaries', PARAM_NOTAGS);
|
||||
|
@ -313,7 +313,7 @@ class mod_quiz_mod_form extends moodleform_mod {
|
|||
get_string('addmoreoverallfeedbacks', 'quiz'), true);
|
||||
|
||||
// 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');
|
||||
|
||||
$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)) {
|
||||
$key = 0;
|
||||
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) {
|
||||
$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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@
|
|||
}
|
||||
|
||||
/// 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) {
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('feedback', 'quiz') .
|
||||
'</th><td class="cell">' . $feedback . '</td></tr>';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// 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->cron = 0; // How often should cron check this module (seconds)?
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@
|
|||
|
||||
if ($feedbackcolumn && $attempt->timefinish > 0) {
|
||||
if ($attemptoptions->overallfeedback) {
|
||||
$row[] = quiz_feedback_for_grade($attemptgrade, $quiz->id);
|
||||
$row[] = quiz_feedback_for_grade($attemptgrade, $quiz, $context, $cm);
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
@ -330,7 +330,7 @@
|
|||
}
|
||||
if ($feedbackcolumn) {
|
||||
$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) {
|
||||
|
|
|
@ -630,6 +630,12 @@ if ($component === 'blog') {
|
|||
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) {
|
||||
$modname = substr($component, 4);
|
||||
|
|
|
@ -12,7 +12,7 @@ require_once(dirname(__FILE__) . '/../config.php');
|
|||
require_once(dirname(__FILE__) . '/editlib.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)){
|
||||
$courseid = required_param('courseid', PARAM_INT);
|
||||
|
@ -165,6 +165,9 @@ if ($contextmoveform->is_cancelled()){
|
|||
if (!question_move_questions_to_category($ids, $tocat->id)) {
|
||||
print_error('errormovingquestions', 'question', $returnurl, $ids);
|
||||
}
|
||||
if ($returnurl) {
|
||||
$returnurl = new moodle_url('/' . $returnurl);
|
||||
}
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Page to edit the question bank
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package questionbank
|
||||
*//** */
|
||||
* Page to edit the question bank
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package questionbank
|
||||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
require_once("editlib.php");
|
||||
|
@ -67,7 +67,7 @@
|
|||
|
||||
$context = $contexts->lowest();
|
||||
$streditingquestions = get_string('editquestions', "quiz");
|
||||
$PAGE->set_title($streditingquestions);
|
||||
$PAGE->set_title($streditingquestions);
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
|
|
@ -1402,7 +1402,7 @@ class question_bank_view {
|
|||
$questionids[] = $key;
|
||||
}
|
||||
}
|
||||
if ($questionids){
|
||||
if ($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";
|
||||
if (!$questions = $DB->get_records_sql($sql, $params)){
|
||||
|
@ -1426,8 +1426,9 @@ class question_bank_view {
|
|||
} else {
|
||||
$returnurl = str_replace($CFG->wwwroot . '/', '', $returnurl);
|
||||
$movecontexturl = new moodle_url('/question/contextmoveq.php',
|
||||
array('returnurl' => $returnurl, 'ids' => $questionids,
|
||||
'tocatid' => $tocategoryid));
|
||||
array('returnurl' => $returnurl,
|
||||
'ids' => implode(',', $questionids),
|
||||
'tocatid' => $tocategoryid));
|
||||
if (!empty($cm->id)){
|
||||
$movecontexturl->param('cmid', $cm->id);
|
||||
} else {
|
||||
|
|
|
@ -862,6 +862,7 @@ class qformat_default {
|
|||
* performs the conversion.
|
||||
*/
|
||||
function format_question_text($question) {
|
||||
global $DB;
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions->noclean = true;
|
||||
$formatoptions->para = false;
|
||||
|
@ -870,10 +871,7 @@ class qformat_default {
|
|||
} else {
|
||||
$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_heading($COURSE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
if (!empty($quizid)) {
|
||||
echo '<p class="quemodname">'.get_string('modulename', 'quiz') . ': ';
|
||||
p(format_string($quiz->name));
|
||||
|
@ -219,7 +219,7 @@
|
|||
}
|
||||
$number = 1;
|
||||
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 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);
|
||||
} elseif ($courseid) {
|
||||
require_login($courseid, false);
|
||||
$PAGE->set_pagelayout('course');
|
||||
$thiscontext = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||
$module = null;
|
||||
$cm = null;
|
||||
|
@ -106,7 +107,7 @@ if ($id) {
|
|||
|
||||
} else if ($categoryid) {
|
||||
// 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->param('validationerror', 1);
|
||||
redirect($addurl);
|
||||
|
@ -151,6 +152,8 @@ if ($id) {
|
|||
} else { // creating a new question
|
||||
require_capability('moodle/question:add', $categorycontext);
|
||||
$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->movecontext = false;
|
||||
}
|
||||
|
@ -189,7 +192,9 @@ if ($cm !== null){
|
|||
} else {
|
||||
$toform->courseid = $COURSE->id;
|
||||
}
|
||||
|
||||
$toform->inpopup = $inpopup;
|
||||
|
||||
$mform->set_data($toform);
|
||||
|
||||
if ($mform->is_cancelled()){
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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"
|
||||
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="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="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="partiallycorrectfeedback"/>
|
||||
<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="incorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="partiallycorrectfeedback" 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="incorrectfeedback"/>
|
||||
<FIELD NAME="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="correctfeedbackformat"/>
|
||||
<FIELD NAME="correctfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="correctfeedback" NEXT="partiallycorrectfeedback"/>
|
||||
<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="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>
|
||||
<KEYS>
|
||||
<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');
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -19,12 +35,12 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
* @var question_calculated_qtype
|
||||
*/
|
||||
public $qtypeobj;
|
||||
public $questiondisplay ;
|
||||
public $activecategory ;
|
||||
public $categorychanged = false ;
|
||||
public $questiondisplay;
|
||||
public $activecategory;
|
||||
public $categorychanged = false;
|
||||
public $initialname = '';
|
||||
public $reload = false ;
|
||||
|
||||
public $reload = false;
|
||||
|
||||
function question_edit_calculated_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
||||
global $QTYPES, $SESSION, $CFG, $DB;
|
||||
$this->question = $question;
|
||||
|
@ -42,20 +58,20 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
$regs= array();
|
||||
if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
|
||||
$question->name = str_replace($regs[0], '', $question->name);
|
||||
};
|
||||
};
|
||||
}
|
||||
}else {
|
||||
}
|
||||
}
|
||||
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
||||
}
|
||||
|
||||
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
||||
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
||||
$repeated = array();
|
||||
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
||||
$repeated = array();
|
||||
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
|
||||
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
||||
$repeatedoptions['fraction']['default'] = 0;
|
||||
$answersoption = 'answers';
|
||||
|
@ -63,8 +79,8 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
$mform->setType('answer', PARAM_NOTAGS);
|
||||
|
||||
$addrepeated = array();
|
||||
$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('text', 'tolerance', get_string('tolerance', 'qtype_calculated'));
|
||||
$addrepeated[] =& $mform->createElement('select', 'tolerancetype', get_string('tolerancetype', 'quiz'), $this->qtypeobj->tolerance_types());
|
||||
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
|
||||
$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'));
|
||||
$addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
|
||||
array_splice($repeated, 3, 0, $addrepeated);
|
||||
$repeated[1]->setLabel(get_string('correctanswerformula', 'quiz').'=');
|
||||
$repeated[1]->setLabel(get_string('correctanswerformula', 'quiz').'=');
|
||||
|
||||
return $repeated;
|
||||
}
|
||||
|
@ -87,8 +103,8 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
function definition_inner(&$mform) {
|
||||
global $QTYPES;
|
||||
$this->qtypeobj =& $QTYPES[$this->qtype()];
|
||||
// echo code left for testing period
|
||||
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
||||
// echo code left for testing period
|
||||
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
||||
$label = get_string('sharedwildcards', 'qtype_calculated');
|
||||
$mform->addElement('hidden', 'initialcategory', 1);
|
||||
$mform->addElement('hidden', 'reload', 1);
|
||||
|
@ -100,43 +116,42 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
};
|
||||
$addfieldsname='updatecategory';
|
||||
$addstring=get_string("updatecategory", "qtype_calculated");
|
||||
$mform->registerNoSubmitButton($addfieldsname);
|
||||
$mform->registerNoSubmitButton($addfieldsname);
|
||||
|
||||
$mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
||||
$mform->registerNoSubmitButton('createoptionbutton');
|
||||
|
||||
//editing as regular
|
||||
$mform->setType('single', PARAM_INT);
|
||||
$mform->setType('single', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden','shuffleanswers', '1');
|
||||
$mform->setType('shuffleanswers', PARAM_INT);
|
||||
$mform->addElement('hidden','answernumbering', 'abc');
|
||||
$mform->setType('answernumbering', PARAM_SAFEDIR);
|
||||
$mform->addElement('hidden','shuffleanswers', '1');
|
||||
$mform->setType('shuffleanswers', PARAM_INT);
|
||||
$mform->addElement('hidden','answernumbering', 'abc');
|
||||
$mform->setType('answernumbering', PARAM_SAFEDIR);
|
||||
|
||||
$creategrades = get_grade_options();
|
||||
|
||||
$this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
|
||||
$creategrades->gradeoptions, 1, 1);
|
||||
|
||||
$this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'), $creategrades->gradeoptions, 1, 1);
|
||||
|
||||
$repeated = array();
|
||||
|
||||
$QTYPES['numerical']->add_units_options($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) {
|
||||
$mform->addElement('hidden', $feedbackname);
|
||||
$mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_calculated'), null, $this->editoroptions);
|
||||
$mform->setType($feedbackname, PARAM_RAW);
|
||||
}
|
||||
|
||||
//hidden elements
|
||||
$mform->addElement('hidden', 'synchronize', '');
|
||||
$mform->setType('synchronize', PARAM_INT);
|
||||
$mform->addElement('hidden', 'wizard', 'datasetdefinitions');
|
||||
$mform->setType('wizard', PARAM_ALPHA);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
function data_preprocessing($question) {
|
||||
global $QTYPES;
|
||||
|
||||
$default_values = array();
|
||||
|
@ -145,26 +160,58 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
if (count($answers)) {
|
||||
$key = 0;
|
||||
foreach ($answers as $answer){
|
||||
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||
$default_values['answer['.$key.']'] = $answer->answer;
|
||||
$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;
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
$default_values['synchronize'] = $question->options->synchronize ;
|
||||
$QTYPES['numerical']->set_numerical_unit_data($question,$default_values);
|
||||
$default_values['synchronize'] = $question->options->synchronize ;
|
||||
// set unit data, prepare files in instruction area
|
||||
$QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
|
||||
}
|
||||
if (isset($question->options->single)){
|
||||
$default_values['single'] = $question->options->single;
|
||||
$default_values['answernumbering'] = $question->options->answernumbering;
|
||||
$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['correctfeedback'] = $question->options->correctfeedback;
|
||||
//$default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback;
|
||||
//$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['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
|
||||
$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')){
|
||||
*/
|
||||
$qu = new stdClass;
|
||||
$el = new stdClass;
|
||||
/* no need to call elementExists() here */
|
||||
if ($this->_form->elementExists('category')){
|
||||
$el=$this->_form->getElement('category');
|
||||
} else {
|
||||
} else {
|
||||
$el=$this->_form->getElement('categorymoveto');
|
||||
}
|
||||
if($value =$el->getSelected()) {
|
||||
}
|
||||
if($value =$el->getSelected()) {
|
||||
$qu->category =$value[0];
|
||||
}else {
|
||||
$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 ;
|
||||
$question = (object)((array)$question + $default_values);
|
||||
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
|
@ -200,21 +247,21 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
|
||||
function validation($data, $files) {
|
||||
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>data <pre>";print_r($data);echo "</pre></p>";
|
||||
// echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
|
||||
// echo "<p>data <pre>";print_r($data);echo "</pre></p>";
|
||||
|
||||
$errors = parent::validation($data, $files);
|
||||
//verifying for errors in {=...} in question text;
|
||||
$qtext = "";
|
||||
$qtextremaining = $data['questiontext'] ;
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
||||
foreach ($possibledatasets as $name => $value) {
|
||||
$qtextremaining = $data['questiontext']['text'];
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||
foreach ($possibledatasets as $name => $value) {
|
||||
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
||||
}
|
||||
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||
$qtext =$qtext.$qtextsplits[0];
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
|
@ -229,45 +276,45 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
$answers = $data['answer'];
|
||||
$answercount = 0;
|
||||
$maxgrade = false;
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||
$mandatorydatasets = array();
|
||||
foreach ($answers as $key => $answer){
|
||||
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
||||
}
|
||||
if ( count($mandatorydatasets )==0){
|
||||
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||
foreach ($answers as $key => $answer){
|
||||
$errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||
}
|
||||
}
|
||||
// regular calculated
|
||||
foreach ($answers as $key => $answer){
|
||||
//check no of choices
|
||||
// the * for everykind of answer not actually implemented
|
||||
$trimmedanswer = trim($answer);
|
||||
if (($trimmedanswer!='')||$answercount==0){
|
||||
$eqerror = qtype_calculated_find_formula_errors($trimmedanswer);
|
||||
if (FALSE !== $eqerror){
|
||||
$errors['answer['.$key.']'] = $eqerror;
|
||||
}
|
||||
// regular calculated
|
||||
foreach ($answers as $key => $answer){
|
||||
//check no of choices
|
||||
// the * for everykind of answer not actually implemented
|
||||
$trimmedanswer = trim($answer);
|
||||
if (($trimmedanswer!='')||$answercount==0){
|
||||
$eqerror = qtype_calculated_find_formula_errors($trimmedanswer);
|
||||
if (FALSE !== $eqerror){
|
||||
$errors['answer['.$key.']'] = $eqerror;
|
||||
}
|
||||
if ($trimmedanswer!=''){
|
||||
if ('2' == $data['correctanswerformat'][$key]
|
||||
&& '0' == $data['correctanswerlength'][$key]) {
|
||||
}
|
||||
if ($trimmedanswer!=''){
|
||||
if ('2' == $data['correctanswerformat'][$key]
|
||||
&& '0' == $data['correctanswerlength'][$key]) {
|
||||
$errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
|
||||
}
|
||||
if (!is_numeric($data['tolerance'][$key])){
|
||||
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
|
||||
}
|
||||
if ($data['fraction'][$key] == 1) {
|
||||
$maxgrade = true;
|
||||
}
|
||||
|
||||
$answercount++;
|
||||
if (!is_numeric($data['tolerance'][$key])){
|
||||
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
|
||||
}
|
||||
if ($data['fraction'][$key] == 1) {
|
||||
$maxgrade = true;
|
||||
}
|
||||
//check grades
|
||||
|
||||
//TODO how should grade checking work here??
|
||||
$answercount++;
|
||||
}
|
||||
//check grades
|
||||
|
||||
//TODO how should grade checking work here??
|
||||
/*if ($answer != '') {
|
||||
if ($data['fraction'][$key] > 0) {
|
||||
$totalfraction += $data['fraction'][$key];
|
||||
|
@ -276,10 +323,10 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
$maxfraction = $data['fraction'][$key];
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
//grade checking :
|
||||
/// Perform sanity checks on fractional grades
|
||||
//grade checking :
|
||||
/// Perform sanity checks on fractional grades
|
||||
/*if ( ) {
|
||||
if ($maxfraction != 1) {
|
||||
$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);
|
||||
}
|
||||
}
|
||||
$units = $data['unit'];
|
||||
$units = $data['unit'];
|
||||
if (count($units)) {
|
||||
foreach ($units as $key => $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) ;
|
||||
if ($answercount==0){
|
||||
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
||||
}
|
||||
if ($maxgrade == false) {
|
||||
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
||||
}
|
||||
|
||||
$QTYPES['numerical']->validate_numerical_options($data, $errors) ;
|
||||
if ($answercount==0){
|
||||
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
||||
}
|
||||
if ($maxgrade == false) {
|
||||
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
||||
}
|
||||
|
||||
|
||||
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['correctanswershows'] = 'Correct answer shows';
|
||||
$string['correctanswershowsformat'] = 'Format';
|
||||
$string['correctfeedback'] = 'For any correct response';
|
||||
$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['deleteitem'] = 'Delete Item';
|
||||
|
@ -61,6 +62,7 @@ $string['forceregenerationall'] = 'forceregeneration of all wildcards';
|
|||
$string['forceregenerationshared'] = 'forceregeneration of only non-shared wildcards';
|
||||
$string['getnextnow'] = 'Get New \'Item to Add\' Now';
|
||||
$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['itemno'] = 'Item {$a}';
|
||||
$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['nosharedwildcard'] = 'No shared wild card in this category';
|
||||
$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['partiallycorrectfeedback'] = 'For any partially correct response';
|
||||
$string['possiblehdr'] = 'Possible wild cards present only in the question text';
|
||||
$string['questiondatasets'] = 'Question datasets';
|
||||
$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
|
||||
|
||||
$plugin->version = 2010020800;
|
||||
$plugin->version = 2010020801;
|
||||
$plugin->requires = 2007101000;
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
*
|
||||
* @var question_calculatedmulti_qtype
|
||||
*/
|
||||
var $qtypeobj;
|
||||
public $qtypeobj;
|
||||
public $questiondisplay ;
|
||||
public $initialname = '';
|
||||
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;
|
||||
$this->question = $question;
|
||||
$this->qtypeobj =& $QTYPES[$this->question->qtype];
|
||||
|
@ -38,22 +38,21 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
$regs= array();
|
||||
if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
|
||||
$question->name = str_replace($regs[0], '', $question->name);
|
||||
};
|
||||
};
|
||||
}
|
||||
}else {
|
||||
}
|
||||
}
|
||||
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
|
||||
}
|
||||
|
||||
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
|
||||
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
||||
$repeated = array();
|
||||
// $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
|
||||
$repeated = array();
|
||||
$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('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
|
||||
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
||||
$repeatedoptions['fraction']['default'] = 0;
|
||||
$answersoption = 'answers';
|
||||
|
@ -61,8 +60,8 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
$mform->setType('answer', PARAM_NOTAGS);
|
||||
|
||||
$addrepeated = array();
|
||||
$addrepeated[] =& $mform->createElement('hidden', 'tolerance');
|
||||
$addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
|
||||
$addrepeated[] =& $mform->createElement('hidden', 'tolerance');
|
||||
$addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
|
||||
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
|
||||
$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'));
|
||||
$addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
|
||||
array_splice($repeated, 3, 0, $addrepeated);
|
||||
$repeated[1]->setLabel('...<strong>{={x}+..}</strong>...');
|
||||
$repeated[1]->setLabel('...<strong>{={x}+..}</strong>...');
|
||||
|
||||
return $repeated;
|
||||
}
|
||||
|
@ -85,79 +84,78 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
function definition_inner(&$mform) {
|
||||
global $QTYPES;
|
||||
$this->qtypeobj =& $QTYPES[$this->qtype()];
|
||||
// echo code left for testing period
|
||||
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
||||
// echo code left for testing period
|
||||
// echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
|
||||
$label = get_string("sharedwildcards", "qtype_calculated");
|
||||
$mform->addElement('hidden', 'initialcategory', 1);
|
||||
$mform->addElement('hidden', 'reload', 1);
|
||||
$mform->setType('initialcategory', PARAM_INT);
|
||||
|
||||
// $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
|
||||
$html2 ="";
|
||||
// $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
|
||||
$html2 ="";
|
||||
$mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name');
|
||||
if(isset($this->question->id )){
|
||||
$mform->insertElementBefore($mform->createElement('static','initialname',get_string('questionstoredname','qtype_calculated'),$this->initialname),'name');
|
||||
};
|
||||
$addfieldsname='updatecategory';
|
||||
$addstring=get_string("updatecategory", "qtype_calculated");
|
||||
$mform->registerNoSubmitButton($addfieldsname);
|
||||
$mform->registerNoSubmitButton($addfieldsname);
|
||||
$this->editasmultichoice = 1 ;
|
||||
|
||||
|
||||
|
||||
$mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
||||
$mform->registerNoSubmitButton('createoptionbutton');
|
||||
$mform->addElement('hidden', 'multichoice',$this->editasmultichoice);
|
||||
$mform->setType('multichoice', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'multichoice',$this->editasmultichoice);
|
||||
$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('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->setDefault('shuffleanswers', 1);
|
||||
|
||||
$numberingoptions = $QTYPES['multichoice']->get_numbering_styles();
|
||||
$menu = array();
|
||||
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('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated'));
|
||||
$menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice'));
|
||||
$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->setHelpButton('shuffleanswers', array('multichoiceshuffle', get_string('shuffleanswers','qtype_multichoice'), 'qtype_multichoice'));
|
||||
$mform->setDefault('shuffleanswers', 1);
|
||||
|
||||
$numberingoptions = $QTYPES['multichoice']->get_numbering_styles();
|
||||
$menu = array();
|
||||
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');
|
||||
|
||||
$creategrades = get_grade_options();
|
||||
$this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'),
|
||||
$creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START));
|
||||
|
||||
$this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'),
|
||||
$creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START));
|
||||
|
||||
|
||||
$repeated = array();
|
||||
// if ($this->editasmultichoice == 1){
|
||||
$nounits = optional_param('nounits', 1, PARAM_INT);
|
||||
$mform->addElement('hidden', 'nounits', $nounits);
|
||||
$mform->setType('nounits', PARAM_INT);
|
||||
$mform->setConstants(array('nounits'=>$nounits));
|
||||
for ($i=0; $i< $nounits; $i++) {
|
||||
$mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS));
|
||||
$mform->setType('unit'."[$i]", PARAM_NOTAGS);
|
||||
$mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER));
|
||||
$mform->setType('multiplier'."[$i]", PARAM_NUMBER);
|
||||
}
|
||||
$mform->addElement('hidden','unitgradingtype',optional_param('unitgradingtype', '', PARAM_INT)) ;
|
||||
$mform->addElement('hidden','unitpenalty',optional_param('unitpenalty', '', PARAM_NUMBER)) ;
|
||||
$mform->addElement('hidden','showunits',optional_param('showunits', '', PARAM_INT)) ;
|
||||
$mform->addElement('hidden','unitsleft',optional_param('unitsleft', '', PARAM_INT)) ;
|
||||
$mform->addElement('hidden','instructions',optional_param('instructions', '', PARAM_RAW)) ;
|
||||
// if ($this->editasmultichoice == 1){
|
||||
$nounits = optional_param('nounits', 1, PARAM_INT);
|
||||
$mform->addElement('hidden', 'nounits', $nounits);
|
||||
$mform->setType('nounits', PARAM_INT);
|
||||
$mform->setConstants(array('nounits'=>$nounits));
|
||||
for ($i=0; $i< $nounits; $i++) {
|
||||
$mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS));
|
||||
$mform->setType('unit'."[$i]", PARAM_NOTAGS);
|
||||
$mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER));
|
||||
$mform->setType('multiplier'."[$i]", PARAM_NUMBER);
|
||||
}
|
||||
$mform->addElement('hidden','unitgradingtype',optional_param('unitgradingtype', '', PARAM_INT)) ;
|
||||
$mform->addElement('hidden','unitpenalty',optional_param('unitpenalty', '', PARAM_NUMBER)) ;
|
||||
$mform->addElement('hidden','showunits',optional_param('showunits', '', PARAM_INT)) ;
|
||||
$mform->addElement('hidden','unitsleft',optional_param('unitsleft', '', PARAM_INT)) ;
|
||||
$mform->addElement('hidden','instructions',optional_param('instructions', '', PARAM_RAW)) ;
|
||||
|
||||
$mform->setType('addunits','hidden');
|
||||
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
||||
$mform->setType('addunits','hidden');
|
||||
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
||||
|
||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||
$mform->addElement('htmleditor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->setType($feedbackname, PARAM_RAW);
|
||||
}
|
||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||
$mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'), null, $this->editoroptions);
|
||||
$mform->setType($feedbackname, PARAM_RAW);
|
||||
}
|
||||
//hidden elements
|
||||
$mform->addElement('hidden', 'synchronize', '');
|
||||
$mform->setType('synchronize', PARAM_INT);
|
||||
|
@ -168,40 +166,43 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
}
|
||||
$mform->addElement('hidden', 'wizard', 'datasetdefinitions');
|
||||
$mform->setType('wizard', PARAM_ALPHA);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
$default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ;
|
||||
function data_preprocessing($question) {
|
||||
$default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ;
|
||||
if (isset($question->options)){
|
||||
$answers = $question->options->answers;
|
||||
if (count($answers)) {
|
||||
$key = 0;
|
||||
foreach ($answers as $answer){
|
||||
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||
$default_values['answer['.$key.']'] = $answer->answer;
|
||||
$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;
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
// $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 ;
|
||||
$default_values['synchronize'] = $question->options->synchronize ;
|
||||
// $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 ;
|
||||
$default_values['synchronize'] = $question->options->synchronize ;
|
||||
|
||||
if (isset($question->options->units)){
|
||||
$units = array_values($question->options->units);
|
||||
// make sure the default unit is at index 0
|
||||
usort($units, create_function('$a, $b',
|
||||
'if (1.0 === (float)$a->multiplier) { return -1; } else '.
|
||||
'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
|
||||
'if (1.0 === (float)$a->multiplier) { return -1; } else '.
|
||||
'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
|
||||
if (count($units)) {
|
||||
$key = 0;
|
||||
foreach ($units as $unit){
|
||||
|
@ -213,30 +214,51 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
}
|
||||
}
|
||||
if (isset($question->options->single)){
|
||||
$default_values['single'] = $question->options->single;
|
||||
$default_values['answernumbering'] = $question->options->answernumbering;
|
||||
$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['single'] = $question->options->single;
|
||||
$default_values['answernumbering'] = $question->options->answernumbering;
|
||||
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
||||
}
|
||||
$default_values['submitbutton'] = get_string('nextpage', '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
|
||||
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')){
|
||||
|
||||
// prepare draft files
|
||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||
if (!isset($question->options->$feedbackname)) {
|
||||
continue;
|
||||
}
|
||||
$text = $question->options->$feedbackname;
|
||||
$draftid = file_get_submitted_draft_itemid($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_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');
|
||||
} else {
|
||||
} else {
|
||||
$el=$this->_form->getElement('categorymoveto');
|
||||
}
|
||||
if($value =$el->getSelected()) {
|
||||
}
|
||||
if($value =$el->getSelected()) {
|
||||
$qu->category =$value[0];
|
||||
}else {
|
||||
$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);
|
||||
$this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
|
||||
$question = (object)((array)$question + $default_values);
|
||||
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
|
@ -253,21 +274,20 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
}
|
||||
|
||||
function validation($data, $files) {
|
||||
// echo code left for testing period
|
||||
|
||||
// echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
|
||||
// echo "<p>data <pre>";print_r($data);echo "</pre></p>";
|
||||
// echo code left for testing period
|
||||
// echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
|
||||
// echo "<p>data <pre>";print_r($data);echo "</pre></p>";
|
||||
|
||||
$errors = parent::validation($data, $files);
|
||||
//verifying for errors in {=...} in question text;
|
||||
$qtext = "";
|
||||
$qtextremaining = $data['questiontext'] ;
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
||||
foreach ($possibledatasets as $name => $value) {
|
||||
$qtextremaining = $data['questiontext']['text'];
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||
foreach ($possibledatasets as $name => $value) {
|
||||
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
||||
}
|
||||
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
// echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||
$qtext =$qtext.$qtextsplits[0];
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
|
@ -282,13 +302,13 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
$answers = $data['answer'];
|
||||
$answercount = 0;
|
||||
$maxgrade = false;
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||
$mandatorydatasets = array();
|
||||
foreach ($answers as $key => $answer){
|
||||
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
||||
}
|
||||
if ( count($mandatorydatasets )==0){
|
||||
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||
// $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
|
||||
foreach ($answers as $key => $answer){
|
||||
$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 ){
|
||||
foreach ($answers as $key => $answer){
|
||||
$trimmedanswer = trim($answer);
|
||||
if (($trimmedanswer!='')||$answercount==0){
|
||||
if (($trimmedanswer!='')||$answercount==0){
|
||||
//verifying for errors in {=...} in answer text;
|
||||
$qanswer = "";
|
||||
$qanswerremaining = $trimmedanswer ;
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer);
|
||||
foreach ($possibledatasets as $name => $value) {
|
||||
foreach ($possibledatasets as $name => $value) {
|
||||
$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)) {
|
||||
$qanswersplits = explode($regs1[0], $qanswerremaining, 2);
|
||||
$qanswer =$qanswer.$qanswersplits[0];
|
||||
|
@ -320,16 +340,16 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
}
|
||||
if ($trimmedanswer!=''){
|
||||
if ('2' == $data['correctanswerformat'][$key]
|
||||
&& '0' == $data['correctanswerlength'][$key]) {
|
||||
$errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
|
||||
}
|
||||
&& '0' == $data['correctanswerlength'][$key]) {
|
||||
$errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
|
||||
}
|
||||
if (!is_numeric($data['tolerance'][$key])){
|
||||
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
|
||||
}
|
||||
if ($data['fraction'][$key] == 1) {
|
||||
$maxgrade = true;
|
||||
$maxgrade = true;
|
||||
}
|
||||
|
||||
|
||||
$answercount++;
|
||||
}
|
||||
//check grades
|
||||
|
@ -342,14 +362,14 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
if ($data['fraction'][$key] > $maxfraction) {
|
||||
$maxfraction = $data['fraction'][$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($answercount==0){
|
||||
$errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
||||
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
||||
} elseif ($answercount==1){
|
||||
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($answercount==0){
|
||||
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
||||
}
|
||||
if ($maxgrade == false) {
|
||||
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
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
|
||||
|
||||
// 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 ///
|
||||
/////////////////
|
||||
|
||||
/// QUESTION TYPE CLASS //////////////////
|
||||
|
||||
|
||||
|
||||
class question_calculatedmulti_qtype extends question_calculated_qtype {
|
||||
|
||||
// Used by the function custom_generator_tools:
|
||||
var $calcgenerateidhasbeenadded = false;
|
||||
public $calcgenerateidhasbeenadded = false;
|
||||
public $virtualqtype = false;
|
||||
|
||||
function name() {
|
||||
|
@ -28,14 +41,13 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
|
||||
|
||||
function save_question_options($question) {
|
||||
//$options = $question->subtypeoptions;
|
||||
// Get old answers:
|
||||
global $CFG, $DB, $QTYPES ;
|
||||
$context = $question->context;
|
||||
if (isset($question->answer) && !isset($question->answers)) {
|
||||
$question->answers = $question->answer;
|
||||
}
|
||||
// calculated options
|
||||
$update = true ;
|
||||
$update = true ;
|
||||
$options = $DB->get_record("question_calculated_options", array("question" => $question->id));
|
||||
if (!$options) {
|
||||
$update = false;
|
||||
|
@ -46,19 +58,20 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
$options->single = $question->single;
|
||||
$options->answernumbering = $question->answernumbering;
|
||||
$options->shuffleanswers = $question->shuffleanswers;
|
||||
$options->correctfeedback = trim($question->correctfeedback);
|
||||
$options->partiallycorrectfeedback = trim($question->partiallycorrectfeedback);
|
||||
$options->incorrectfeedback = trim($question->incorrectfeedback);
|
||||
|
||||
// save question feedback files
|
||||
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 (!$DB->update_record("question_calculated_options", $options)) {
|
||||
$result->error = "Could not update calculated question options! (id=$options->id)";
|
||||
return $result;
|
||||
}
|
||||
$DB->update_record("question_calculated_options", $options);
|
||||
} else {
|
||||
if (!$DB->insert_record("question_calculated_options", $options)) {
|
||||
$result->error = "Could not insert calculated question options!";
|
||||
return $result;
|
||||
}
|
||||
$DB->insert_record("question_calculated_options", $options);
|
||||
}
|
||||
|
||||
// Get old versions of the objects
|
||||
|
@ -71,8 +84,9 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
}
|
||||
|
||||
// Save the units.
|
||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||
// $result = $virtualqtype->save_numerical_units($question);
|
||||
$virtualqtype = $this->get_virtual_qtype($question);
|
||||
// TODO: What is this?
|
||||
// $result = $virtualqtype->save_numerical_units($question);
|
||||
if (isset($result->error)) {
|
||||
return $result;
|
||||
} else {
|
||||
|
@ -80,21 +94,25 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
}
|
||||
// Insert all the new answers
|
||||
if (isset($question->answer) && !isset($question->answers)) {
|
||||
$question->answers=$question->answer;
|
||||
$question->answers = $question->answer;
|
||||
}
|
||||
foreach ($question->answers as $key => $dataanswer) {
|
||||
if ( trim($dataanswer) != '' ) {
|
||||
if ( trim($dataanswer) != '' ) {
|
||||
$answer = new stdClass;
|
||||
$answer->question = $question->id;
|
||||
$answer->answer = trim($dataanswer);
|
||||
$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
|
||||
$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);
|
||||
} else { // This is a completely new 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
|
||||
|
@ -129,15 +147,15 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
$DB->delete_records('question_calculated', array('id' => $oo->id));
|
||||
}
|
||||
}
|
||||
// $result = $QTYPES['numerical']->save_numerical_options($question);
|
||||
// if (isset($result->error)) {
|
||||
// return $result;
|
||||
// }
|
||||
// $result = $QTYPES['numerical']->save_numerical_options($question);
|
||||
// if (isset($result->error)) {
|
||||
// return $result;
|
||||
// }
|
||||
|
||||
|
||||
if( isset($question->import_process)&&$question->import_process){
|
||||
$this->import_datasets($question);
|
||||
}
|
||||
}
|
||||
// Report any problems.
|
||||
if (!empty($result->notice)) {
|
||||
return $result;
|
||||
|
@ -148,30 +166,25 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
|
||||
// Find out how many datasets are available
|
||||
global $CFG, $DB, $QTYPES, $OUTPUT ;
|
||||
if(!$maxnumber = (int)$DB->get_field_sql(
|
||||
"SELECT MIN(a.itemcount)
|
||||
FROM {question_dataset_definitions} a,
|
||||
{question_datasets} b
|
||||
WHERE b.question = ?
|
||||
AND a.id = b.datasetdefinition", array($question->id))) {
|
||||
$maxnumber = (int)$DB->get_field_sql(
|
||||
"SELECT MIN(a.itemcount)
|
||||
FROM {question_dataset_definitions} a, {question_datasets} b
|
||||
WHERE b.question = ? AND a.id = b.datasetdefinition", array($question->id));
|
||||
if (!$maxnumber) {
|
||||
print_error('cannotgetdsforquestion', 'question', '', $question->id);
|
||||
}
|
||||
$sql = "SELECT i.*
|
||||
FROM {question_datasets} d,
|
||||
{question_dataset_definitions} i
|
||||
WHERE d.question = ?
|
||||
AND d.datasetdefinition = i.id
|
||||
AND i.category != 0
|
||||
";
|
||||
$sql = "SELECT i.*
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
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))) {
|
||||
$synchronize_calculated = false ;
|
||||
}else {
|
||||
// i.e records is true so test coherence
|
||||
$coherence = true ;
|
||||
$a = new stdClass ;
|
||||
$a->qid = $question->id ;
|
||||
$a->qcat = $question->category ;
|
||||
foreach($records as $def ){
|
||||
$synchronize_calculated = false ;
|
||||
} else {
|
||||
// i.e records is true so test coherence
|
||||
$coherence = true ;
|
||||
$a = new stdClass ;
|
||||
$a->qid = $question->id ;
|
||||
$a->qcat = $question->category ;
|
||||
foreach($records as $def ){
|
||||
if ($def->category != $question->category){
|
||||
$a->name = $def->name;
|
||||
$a->sharedcat = $def->category ;
|
||||
|
@ -180,11 +193,11 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
}
|
||||
}
|
||||
if(!$coherence){
|
||||
echo $OUTPUT->notification(get_string('nocoherencequestionsdatyasetcategory','qtype_calculated',$a));
|
||||
}
|
||||
|
||||
$synchronize_calculated = true ;
|
||||
}
|
||||
echo $OUTPUT->notification(get_string('nocoherencequestionsdatyasetcategory','qtype_calculated',$a));
|
||||
}
|
||||
|
||||
$synchronize_calculated = true ;
|
||||
}
|
||||
|
||||
// Choose a random dataset
|
||||
// maxnumber sould not be breater than 100
|
||||
|
@ -194,41 +207,40 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
if ( $synchronize_calculated === false ) {
|
||||
$state->options->datasetitem = rand(1, $maxnumber);
|
||||
}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) {
|
||||
$state->options->datasetitem =1 ;
|
||||
} else if ($state->options->datasetitem > $maxnumber){
|
||||
$state->options->datasetitem = $maxnumber ;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
$state->options->dataset =
|
||||
$this->pick_question_dataset($question,$state->options->datasetitem);
|
||||
// create an array of answerids ??? why so complicated ???
|
||||
$answerids = array_values(array_map(create_function('$val',
|
||||
'return $val->id;'), $question->options->answers));
|
||||
// Shuffle the answers if required
|
||||
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
|
||||
$answerids = swapshuffle($answerids);
|
||||
}
|
||||
$state->options->order = $answerids;
|
||||
// Create empty responses
|
||||
if ($question->options->single) {
|
||||
$state->responses = array('' => '');
|
||||
} else {
|
||||
$state->responses = array();
|
||||
}
|
||||
return true;
|
||||
|
||||
$this->pick_question_dataset($question,$state->options->datasetitem);
|
||||
// create an array of answerids ??? why so complicated ???
|
||||
$answerids = array_values(array_map(create_function('$val',
|
||||
'return $val->id;'), $question->options->answers));
|
||||
// Shuffle the answers if required
|
||||
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
|
||||
$answerids = swapshuffle($answerids);
|
||||
}
|
||||
$state->options->order = $answerids;
|
||||
// Create empty responses
|
||||
if ($question->options->single) {
|
||||
$state->responses = array('' => '');
|
||||
} else {
|
||||
$state->responses = array();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function save_session_and_responses(&$question, &$state) {
|
||||
global $DB;
|
||||
$responses = 'dataset'.$state->options->datasetitem.'-' ;
|
||||
$responses = 'dataset'.$state->options->datasetitem.'-' ;
|
||||
$responses .= implode(',', $state->options->order) . ':';
|
||||
$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))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -241,7 +253,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
foreach ($form->answers as $key => $answer) {
|
||||
$a->answer = trim($form->answer[$key]);
|
||||
$a->fraction = $form->fraction[$key];//new
|
||||
$a->tolerance = $form->tolerance[$key];
|
||||
$a->tolerance = $form->tolerance[$key];
|
||||
$a->tolerancetype = $form->tolerancetype[$key];
|
||||
$a->correctanswerlength = $form->correctanswerlength[$key];
|
||||
$a->correctanswerformat = $form->correctanswerformat[$key];
|
||||
|
@ -251,57 +263,53 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
return $question;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function convert_answers (&$question, &$state){
|
||||
foreach ($question->options->answers as $key => $answer) {
|
||||
$answer->answer = $this->substitute_variables($answer->answer, $state->options->dataset);
|
||||
//evaluate the equations i.e {=5+4)
|
||||
$qtext = "";
|
||||
$qtextremaining = $answer->answer ;
|
||||
// while (preg_match('~\{(=)|%[[:digit]]\.=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
foreach ($question->options->answers as $key => $answer) {
|
||||
$answer->answer = $this->substitute_variables($answer->answer, $state->options->dataset);
|
||||
//evaluate the equations i.e {=5+4)
|
||||
$qtext = "";
|
||||
$qtextremaining = $answer->answer ;
|
||||
// while (preg_match('~\{(=)|%[[:digit]]\.=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
|
||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||
$qtext =$qtext.$qtextsplits[0];
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
if (empty($regs1[1])) {
|
||||
$str = '';
|
||||
} else {
|
||||
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
||||
$str=$formulaerrors ;
|
||||
}else {
|
||||
eval('$str = '.$regs1[1].';');
|
||||
$texteval= qtype_calculated_calculate_answer(
|
||||
$str, $state->options->dataset, $answer->tolerance,
|
||||
$answer->tolerancetype, $answer->correctanswerlength,
|
||||
$answer->correctanswerformat, '');
|
||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||
$qtext = $qtext.$qtextsplits[0];
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
if (empty($regs1[1])) {
|
||||
$str = '';
|
||||
} else {
|
||||
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
||||
$str=$formulaerrors ;
|
||||
}else {
|
||||
eval('$str = '.$regs1[1].';');
|
||||
$texteval= qtype_calculated_calculate_answer(
|
||||
$str, $state->options->dataset, $answer->tolerance,
|
||||
$answer->tolerancetype, $answer->correctanswerlength,
|
||||
$answer->correctanswerformat, '');
|
||||
$str = $texteval->answer;
|
||||
}
|
||||
}
|
||||
$qtext = $qtext.$str ;
|
||||
}
|
||||
}
|
||||
$answer->answer = $qtext.$qtextremaining ; ;
|
||||
$qtext = $qtext.$str ;
|
||||
}
|
||||
$answer->answer = $qtext.$qtextremaining ; ;
|
||||
}
|
||||
}
|
||||
|
||||
function get_default_numerical_unit($question,$virtualqtype){
|
||||
$unit = '';
|
||||
return $unit ;
|
||||
}
|
||||
function get_default_numerical_unit($question, $virtualqtype){
|
||||
$unit = '';
|
||||
return $unit ;
|
||||
}
|
||||
function grade_responses(&$question, &$state, $cmoptions) {
|
||||
// Forward the grading to the virtual qtype
|
||||
// We modify the question to look like a multichoice question
|
||||
// for grading nothing to do
|
||||
// for grading nothing to do
|
||||
/* $numericalquestion = fullclone($question);
|
||||
foreach ($numericalquestion->options->answers as $key => $answer) {
|
||||
$answer = $numericalquestion->options->answers[$key]->answer; // for PHP 4.x
|
||||
$numericalquestion->options->answers[$key]->answer = $this->substitute_variables_and_eval($answer,
|
||||
$state->options->dataset);
|
||||
}*/
|
||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||
}*/
|
||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||
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_questiontext ($numericalquestion, $state);
|
||||
/* $numericalquestion->questiontext = $this->substitute_variables_and_eval(
|
||||
$numericalquestion->questiontext, $state->options->dataset);*/
|
||||
$numericalquestion->questiontext, $state->options->dataset);*/
|
||||
$responses = $virtualqtype->get_all_responses($numericalquestion, $state);
|
||||
$response = reset($responses->responses);
|
||||
$correct = $response->answer.' : ';
|
||||
|
@ -335,8 +343,8 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
|
||||
function create_virtual_qtype() {
|
||||
global $CFG;
|
||||
require_once("$CFG->dirroot/question/type/multichoice/questiontype.php");
|
||||
return new question_multichoice_qtype();
|
||||
require_once("$CFG->dirroot/question/type/multichoice/questiontype.php");
|
||||
return new question_multichoice_qtype();
|
||||
}
|
||||
|
||||
|
||||
|
@ -353,7 +361,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
} else {
|
||||
$strheader .= $delimiter.$answer->answer;
|
||||
}
|
||||
$delimiter = '<br/>';
|
||||
$delimiter = '<br/>';
|
||||
}
|
||||
return $strheader;
|
||||
}
|
||||
|
@ -369,7 +377,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
$unit = $unit->unit;
|
||||
} else {
|
||||
$unit = '';
|
||||
}*/
|
||||
}*/
|
||||
|
||||
$answers = fullclone($answers);
|
||||
$strmin = get_string('min', 'quiz');
|
||||
|
@ -377,29 +385,29 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
$errors = '';
|
||||
$delimiter = ': ';
|
||||
foreach ($answers as $key => $answer) {
|
||||
$answer->answer = $this->substitute_variables($answer->answer, $data);
|
||||
//evaluate the equations i.e {=5+4)
|
||||
$qtext = "";
|
||||
$qtextremaining = $answer->answer ;
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||
$qtext =$qtext.$qtextsplits[0];
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
if (empty($regs1[1])) {
|
||||
$str = '';
|
||||
} else {
|
||||
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
||||
$str=$formulaerrors ;
|
||||
}else {
|
||||
eval('$str = '.$regs1[1].';');
|
||||
}
|
||||
}
|
||||
$qtext = $qtext.$str ;
|
||||
$answer->answer = $this->substitute_variables($answer->answer, $data);
|
||||
//evaluate the equations i.e {=5+4)
|
||||
$qtext = "";
|
||||
$qtextremaining = $answer->answer ;
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||
$qtext =$qtext.$qtextsplits[0];
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
if (empty($regs1[1])) {
|
||||
$str = '';
|
||||
} else {
|
||||
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
|
||||
$str=$formulaerrors ;
|
||||
}else {
|
||||
eval('$str = '.$regs1[1].';');
|
||||
}
|
||||
}
|
||||
$answer->answer = $qtext.$qtextremaining ; ;
|
||||
$comment->stranswers[$key]= $answer->answer ;
|
||||
|
||||
|
||||
$qtext = $qtext.$str ;
|
||||
}
|
||||
$answer->answer = $qtext.$qtextremaining;
|
||||
$comment->stranswers[$key] = $answer->answer;
|
||||
|
||||
|
||||
/* $formula = $this->substitute_variables($answer->answer,$data);
|
||||
$formattedanswer = qtype_calculated_calculate_answer(
|
||||
$answer->answer, $data, $answer->tolerance,
|
||||
|
@ -411,7 +419,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
}else {
|
||||
eval('$answer->answer = '.$formula.';') ;
|
||||
$virtualqtype->get_tolerance_interval($answer);
|
||||
}
|
||||
}
|
||||
if ($answer->min === '') {
|
||||
// This should mean that something is wrong
|
||||
$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] .='';
|
||||
}*/
|
||||
}*/
|
||||
}
|
||||
return fullclone($comment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function get_correct_responses1(&$question, &$state) {
|
||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||
/* if ($question->options->multichoice != 1 ) {
|
||||
|
@ -464,71 +468,148 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
return $correct;
|
||||
}
|
||||
}
|
||||
}else{**/
|
||||
return $virtualqtype->get_correct_responses($question, $state) ;
|
||||
// }
|
||||
}else{**/
|
||||
return $virtualqtype->get_correct_responses($question, $state) ;
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
function get_virtual_qtype() {
|
||||
global $QTYPES;
|
||||
// if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){
|
||||
$this->virtualqtype =& $QTYPES['multichoice'];
|
||||
// }else {
|
||||
// $this->virtualqtype =& $QTYPES['numerical'];
|
||||
// }
|
||||
// if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){
|
||||
$this->virtualqtype =& $QTYPES['multichoice'];
|
||||
// }else {
|
||||
// $this->virtualqtype =& $QTYPES['numerical'];
|
||||
// }
|
||||
return $this->virtualqtype;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function generate_test($name, $courseid = null) {
|
||||
global $DB;
|
||||
list($form, $question) = parent::generate_test($name, $courseid);
|
||||
$form->feedback = 1;
|
||||
$form->multiplier = array(1, 1);
|
||||
$form->shuffleanswers = 1;
|
||||
$form->noanswers = 1;
|
||||
$form->qtype ='calculatedmulti';
|
||||
$question->qtype ='calculatedmulti';
|
||||
$form->answers = array('{a} + {b}');
|
||||
$form->fraction = array(1);
|
||||
$form->tolerance = array(0.01);
|
||||
$form->tolerancetype = array(1);
|
||||
$form->correctanswerlength = array(2);
|
||||
$form->correctanswerformat = array(1);
|
||||
$form->questiontext = "What is {a} + {b}?";
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function generate_test($name, $courseid = null) {
|
||||
global $DB;
|
||||
list($form, $question) = parent::generate_test($name, $courseid);
|
||||
$form->feedback = 1;
|
||||
$form->multiplier = array(1, 1);
|
||||
$form->shuffleanswers = 1;
|
||||
$form->noanswers = 1;
|
||||
$form->qtype ='calculatedmulti';
|
||||
$question->qtype ='calculatedmulti';
|
||||
$form->answers = array('{a} + {b}');
|
||||
$form->fraction = array(1);
|
||||
$form->tolerance = array(0.01);
|
||||
$form->tolerancetype = array(1);
|
||||
$form->correctanswerlength = array(2);
|
||||
$form->correctanswerformat = array(1);
|
||||
$form->questiontext = "What is {a} + {b}?";
|
||||
|
||||
if ($courseid) {
|
||||
$course = $DB->get_record('course', array('id'=> $courseid));
|
||||
}
|
||||
if ($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->nextpageparam["forceregeneration"]= 1;
|
||||
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
||||
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
||||
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
||||
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
||||
$dataset_form->itemid = array(1 => '' , 2 => '');
|
||||
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
||||
$dataset_form->definition = array(1 => "1-0-a",
|
||||
2 => "1-0-b");
|
||||
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
||||
$dataset_form->addbutton = 1;
|
||||
$dataset_form->selectadd = 1;
|
||||
$dataset_form->courseid = $courseid;
|
||||
$dataset_form->cmid = 0;
|
||||
$dataset_form->id = $new_question->id;
|
||||
$this->save_dataset_items($new_question, $dataset_form);
|
||||
$dataset_form = new stdClass();
|
||||
$dataset_form->nextpageparam["forceregeneration"]= 1;
|
||||
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
||||
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
||||
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
||||
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
||||
$dataset_form->itemid = array(1 => '' , 2 => '');
|
||||
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
||||
$dataset_form->definition = array(1 => "1-0-a",
|
||||
2 => "1-0-b");
|
||||
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
||||
$dataset_form->addbutton = 1;
|
||||
$dataset_form->selectadd = 1;
|
||||
$dataset_form->courseid = $courseid;
|
||||
$dataset_form->cmid = 0;
|
||||
$dataset_form->id = $new_question->id;
|
||||
$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 ////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -8,21 +24,17 @@
|
|||
* @package questionbank
|
||||
* @subpackage questiontypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* calculatedsimple editing form definition.
|
||||
*/
|
||||
class question_edit_calculatedsimple_form extends question_edit_form {
|
||||
/**
|
||||
* Handle to the question type for this question.
|
||||
*
|
||||
* @var question_calculatedsimple_qtype
|
||||
*/
|
||||
var $qtypeobj;
|
||||
public $qtypeobj;
|
||||
|
||||
var $wildcarddisplay ;
|
||||
public $wildcarddisplay ;
|
||||
|
||||
var $questiondisplay ;
|
||||
public $questiondisplay ;
|
||||
|
||||
public $datasetdefs;
|
||||
|
||||
|
@ -46,8 +58,6 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
|
||||
public $formdata = array();
|
||||
|
||||
|
||||
|
||||
function question_edit_calculatedsimple_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
|
||||
global $QTYPES, $SESSION, $CFG, $DB;
|
||||
$this->regenerate = true;
|
||||
|
@ -60,17 +70,17 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
//so this should be removed from here
|
||||
// get priority to paramdatasets
|
||||
|
||||
if ( "1" == optional_param('reload','', PARAM_INT )) {
|
||||
$this->reload = true ;
|
||||
if ("1" == optional_param('reload','', PARAM_INT )) {
|
||||
$this->reload = true;
|
||||
}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
|
||||
// else get datasets
|
||||
// echo "<p>question <pre>";print_r($question);echo "</pre></p>";
|
||||
if ( !empty($question->id)) {
|
||||
|
||||
if (!empty($question->id)) {
|
||||
|
||||
/* if (empty($question->options)) {
|
||||
$this->get_question_options($question);
|
||||
}*/
|
||||
|
@ -127,7 +137,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$mandatorydatasets = array();
|
||||
// should not test on adding a new answer
|
||||
// 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...
|
||||
$fraction = optional_param('fraction', '', PARAM_NUMBER);
|
||||
|
@ -297,12 +307,12 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$addfieldsname='updatequestion value';
|
||||
$addstring=get_string("updatecategory", "qtype_calculated");
|
||||
$mform->registerNoSubmitButton($addfieldsname);
|
||||
//put a submit button to stop supplementary answers on update answers parameters
|
||||
// $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
|
||||
// put a submit button to stop supplementary answers on update answers parameters
|
||||
// $mform->insertElementBefore($mform->createElement('submit', $addfieldsname, $addstring), 'listcategory');
|
||||
|
||||
$creategrades = get_grade_options();
|
||||
$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);
|
||||
|
||||
|
@ -327,7 +337,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$this->noofitems = 0;
|
||||
}
|
||||
if(!empty($this->datasetdefs)){//So there are some datadefs
|
||||
// we put them on the page
|
||||
// we put them on the page
|
||||
$key = 0;
|
||||
$mform->addElement('header', 'additemhdr', get_string('wildcardparam', 'qtype_calculatedsimple'));
|
||||
$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 ;
|
||||
//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
|
||||
* we could force all wild cards values display if there is an error in values.
|
||||
* as using a , in a number */
|
||||
$this->numbererrors = array();
|
||||
/*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.
|
||||
* as using a , in a number */
|
||||
$this->numbererrors = array();
|
||||
if(!empty($this->datasetdefs)){
|
||||
$j = $this->noofitems * count($this->datasetdefs);
|
||||
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
||||
$data = array();
|
||||
$numbererrors = array() ;
|
||||
$comment = new stdClass;
|
||||
$comment->stranswers = array();
|
||||
$comment->outsidelimit = false ;
|
||||
$comment->answers = array();
|
||||
$j = $this->noofitems * count($this->datasetdefs);
|
||||
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
||||
$data = array();
|
||||
$numbererrors = array() ;
|
||||
$comment = new stdClass;
|
||||
$comment->stranswers = array();
|
||||
$comment->outsidelimit = false ;
|
||||
$comment->answers = array();
|
||||
|
||||
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||
if (isset($datasetdef->items[$itemnumber])){
|
||||
$this->formdata["definition[$j]"] = $defid;
|
||||
$this->formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
|
||||
$data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
|
||||
$this->formdata["number[$j]"] = $number = $datasetdef->items[$itemnumber]->value;
|
||||
if(! is_numeric($number)){
|
||||
$a = new stdClass;
|
||||
$a->name = '{'.$datasetdef->name.'}' ;
|
||||
$a->value = $datasetdef->items[$itemnumber]->value ;
|
||||
if (stristr($number,',')){
|
||||
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||
if (isset($datasetdef->items[$itemnumber])){
|
||||
$this->formdata["definition[$j]"] = $defid;
|
||||
$this->formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
|
||||
$data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
|
||||
$this->formdata["number[$j]"] = $number = $datasetdef->items[$itemnumber]->value;
|
||||
if(! is_numeric($number)){
|
||||
$a = new stdClass;
|
||||
$a->name = '{'.$datasetdef->name.'}' ;
|
||||
$a->value = $datasetdef->items[$itemnumber]->value ;
|
||||
if (stristr($number,',')){
|
||||
$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);
|
||||
$numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
|
||||
//$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';
|
||||
$this->formdata['selectadd'] = '1';
|
||||
$j = $this->noofitems * count($this->datasetdefs)+1;
|
||||
$data = array(); // data for comment_on_datasetitems later
|
||||
if($this->noofitems != 0 ) {
|
||||
if (empty($numbererrors)) {
|
||||
if (!isset($this->question->id)) {
|
||||
$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 ;
|
||||
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||
$this->formdata["datasetdef[$idx]"] = $defid;
|
||||
$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';
|
||||
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');
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
$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('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('static','warningnowildcards','','<span class="error">'.get_string('atleastonewildcard', 'qtype_calculatedsimple').'</span>');
|
||||
$mform->closeHeaderBefore('warningnowildcards');
|
||||
}
|
||||
|
||||
$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
|
||||
//hidden elements
|
||||
|
||||
|
@ -536,50 +549,64 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$mform->setDefault('cmid', 0);
|
||||
if (!empty($this->question->id)){
|
||||
if ($this->question->formoptions->cansaveasnew){
|
||||
$mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
|
||||
$mform->closeHeaderBefore('additemhdr');
|
||||
$mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
|
||||
$mform->closeHeaderBefore('additemhdr');
|
||||
|
||||
$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;
|
||||
$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;
|
||||
$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;
|
||||
$key++;
|
||||
}
|
||||
// prepare draft files
|
||||
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||
$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
|
||||
!empty($answer->feedback)?$answer->feedback:'' // text
|
||||
);
|
||||
$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);
|
||||
/* if (isset($question->options)){
|
||||
}
|
||||
$default_values['synchronize'] = 0 ;
|
||||
$QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
|
||||
/* if (isset($question->options)){
|
||||
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
||||
$default_values['unitpenalty'] = $question->options->unitpenalty ;
|
||||
switch ($question->options->showunits){
|
||||
case 'O' :
|
||||
case '1' :
|
||||
case '1' :
|
||||
$default_values['showunits0'] = $question->options->showunits ;
|
||||
$default_values['unitrole'] = 0 ;
|
||||
break;
|
||||
case '2' :
|
||||
case '3' :
|
||||
case '3' :
|
||||
$default_values['showunits1'] = $question->options->showunits ;
|
||||
$default_values['unitrole'] = 1 ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$default_values['unitsleft'] = $question->options->unitsleft ;
|
||||
$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();
|
||||
$fromform = new stdClass();
|
||||
//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.
|
||||
/* if(!empty($this->datasetdefs)){
|
||||
/* if(!empty($this->datasetdefs)){
|
||||
$j = $this->noofitems * count($this->datasetdefs);
|
||||
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
||||
for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
|
||||
$data = array();
|
||||
foreach ($this->datasetdefs as $defid => $datasetdef){
|
||||
if (isset($datasetdef->items[$itemnumber])){
|
||||
|
@ -613,27 +640,27 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
}
|
||||
$j--;
|
||||
}
|
||||
// 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>answers avant comment <pre>";print_r($answer);echo"</pre></p>";
|
||||
// echo "<p>data avant comment <pre>";print_r($data);echo"</pre></p>";
|
||||
|
||||
if($this->noofitems != 0 ) {
|
||||
if(!isset($question->id)) $question->id = 0 ;
|
||||
$comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this->
|
||||
if ($comment->outsidelimit) {
|
||||
$this->outsidelimit=$comment->outsidelimit ;
|
||||
}
|
||||
$totalcomment='';
|
||||
// echo "<p> comment <pre>";print_r($comment);echo"</pre></p>";
|
||||
$comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this->
|
||||
if ($comment->outsidelimit) {
|
||||
$this->outsidelimit=$comment->outsidelimit ;
|
||||
}
|
||||
$totalcomment='';
|
||||
// echo "<p> comment <pre>";print_r($comment);echo"</pre></p>";
|
||||
|
||||
foreach ($this->nonemptyanswer as $key => $answer) {
|
||||
$totalcomment .= $comment->stranswers[$key].'<br/>';
|
||||
}
|
||||
foreach ($this->nonemptyanswer as $key => $answer) {
|
||||
$totalcomment .= $comment->stranswers[$key].'<br/>';
|
||||
}
|
||||
|
||||
$formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
|
||||
$formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
|
||||
}
|
||||
}
|
||||
}
|
||||
// $formdata['reload'] = '1';
|
||||
// $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
|
||||
// $formdata['reload'] = '1';
|
||||
// $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
|
||||
$formdata['selectdelete'] = '1';
|
||||
$formdata['selectadd'] = '1';
|
||||
$j = $this->noofitems * count($this->datasetdefs)+1;
|
||||
|
@ -644,10 +671,10 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$idx++;
|
||||
}
|
||||
$formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
|
||||
}*/
|
||||
}*/
|
||||
$question = (object)((array)$question + $default_values+$this->formdata );
|
||||
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
|
@ -659,8 +686,8 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$errors = parent::validation($data, $files);
|
||||
//verifying for errors in {=...} in question text;
|
||||
$qtext = "";
|
||||
$qtextremaining = $data['questiontext'] ;
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
||||
$qtextremaining = $data['questiontext']['text'];
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||
foreach ($possibledatasets as $name => $value) {
|
||||
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
|
||||
}
|
||||
|
@ -679,7 +706,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$answers = $data['answer'];
|
||||
$answercount = 0;
|
||||
$maxgrade = false;
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
|
||||
$possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
|
||||
$mandatorydatasets = array();
|
||||
foreach ($answers as $key => $answer){
|
||||
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
|
||||
|
@ -797,4 +824,3 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
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
|
||||
|
||||
// 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 ///
|
||||
/////////////////
|
||||
|
||||
/// QUESTION TYPE CLASS //////////////////
|
||||
|
||||
|
||||
|
||||
class question_calculatedsimple_qtype extends question_calculated_qtype {
|
||||
|
||||
// Used by the function custom_generator_tools:
|
||||
var $calcgenerateidhasbeenadded = false;
|
||||
public $calcgenerateidhasbeenadded = false;
|
||||
public $virtualqtype = false;
|
||||
|
||||
function name() {
|
||||
return 'calculatedsimple';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function save_question_options($question) {
|
||||
global $CFG, $DB , $QTYPES;
|
||||
$context = $question->context;
|
||||
//$options = $question->subtypeoptions;
|
||||
// Get old answers:
|
||||
global $CFG, $DB , $QTYPES;
|
||||
|
||||
if (isset($question->answer) && !isset($question->answers)) {
|
||||
$question->answers = $question->answer;
|
||||
|
@ -52,18 +63,22 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
$question->answers=$question->answer;
|
||||
}
|
||||
foreach ($question->answers as $key => $dataanswer) {
|
||||
if ( trim($dataanswer) != '' ) {
|
||||
if ( trim($dataanswer) != '' ) {
|
||||
$answer = new stdClass;
|
||||
$answer->question = $question->id;
|
||||
$answer->answer = trim($dataanswer);
|
||||
$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
|
||||
$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);
|
||||
} else { // This is a completely new answer
|
||||
$answer->feedback = '';
|
||||
$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
|
||||
|
@ -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);
|
||||
}else {
|
||||
} else {
|
||||
//save datasets and datatitems from form i.e in question
|
||||
// $datasetdefs = $this->get_dataset_definitions($question->id, array());
|
||||
$question->dataset = $question->datasetdef ;
|
||||
// $this->save_dataset_definitions($question);
|
||||
// Save datasets
|
||||
$datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
|
||||
$tmpdatasets = array_flip($question->dataset);
|
||||
$defids = array_keys($datasetdefinitions);
|
||||
$datasetdefs = array();
|
||||
foreach ($defids as $defid) {
|
||||
$datasetdef = &$datasetdefinitions[$defid];
|
||||
if (isset($datasetdef->id)) {
|
||||
if (!isset($tmpdatasets[$defid])) {
|
||||
// This dataset is not used any more, delete it
|
||||
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $datasetdef->id));
|
||||
// if ($datasetdef->category == 0) { // Question local dataset
|
||||
// $datasetdefs = $this->get_dataset_definitions($question->id, array());
|
||||
$question->dataset = $question->datasetdef ;
|
||||
// $this->save_dataset_definitions($question);
|
||||
// Save datasets
|
||||
$datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
|
||||
$tmpdatasets = array_flip($question->dataset);
|
||||
$defids = array_keys($datasetdefinitions);
|
||||
$datasetdefs = array();
|
||||
foreach ($defids as $defid) {
|
||||
$datasetdef = &$datasetdefinitions[$defid];
|
||||
if (isset($datasetdef->id)) {
|
||||
if (!isset($tmpdatasets[$defid])) {
|
||||
// This dataset is not used any more, delete it
|
||||
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $datasetdef->id));
|
||||
// if ($datasetdef->category == 0) { // Question local dataset
|
||||
$DB->delete_records('question_dataset_definitions', array('id' => $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]);
|
||||
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]);
|
||||
}
|
||||
// Remove local obsolete datasets as well as relations
|
||||
// to datasets in other categories:
|
||||
if (!empty($datasetdefinitions)) {
|
||||
foreach ($datasetdefinitions as $def) {
|
||||
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $def->id));
|
||||
if ($def->category == 0) { // Question local dataset
|
||||
$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) {
|
||||
$DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $def->id));
|
||||
if ($def->category == 0) { // Question local dataset
|
||||
$DB->delete_records('question_dataset_definitions', array('id' => $def->id));
|
||||
$DB->delete_records('question_dataset_items', array('definition' => $def->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
$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++;
|
||||
}
|
||||
$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.
|
||||
//convert to calculated
|
||||
if(!empty($question->makecopy) && !empty($question->convert)) {
|
||||
|
@ -190,39 +205,34 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
function finished_edit_wizard(&$form) {
|
||||
function finished_edit_wizard(&$form) {
|
||||
return true ; //isset($form->backtoquiz);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* this version save the available data at the different steps of the question editing process
|
||||
* without using global $SESSION as storage between steps
|
||||
* at the first step $wizardnow = 'question'
|
||||
* when creating a new question
|
||||
* when modifying a question
|
||||
* when copying as a new question
|
||||
* the general parameters and answers are saved using parent::save_question
|
||||
* then the datasets are prepared and saved
|
||||
* at the second step $wizardnow = 'datasetdefinitions'
|
||||
* the datadefs final type are defined as private, category or not a datadef
|
||||
* at the third step $wizardnow = 'datasetitems'
|
||||
* the datadefs parameters and the data items are created or defined
|
||||
*
|
||||
* @param object question
|
||||
* @param object $form
|
||||
* @param int $course
|
||||
* @param PARAM_ALPHA $wizardnow should be added as we are coming from question2.php
|
||||
*/
|
||||
* this version save the available data at the different steps of the question editing process
|
||||
* without using global $SESSION as storage between steps
|
||||
* at the first step $wizardnow = 'question'
|
||||
* when creating a new question
|
||||
* when modifying a question
|
||||
* when copying as a new question
|
||||
* the general parameters and answers are saved using parent::save_question
|
||||
* then the datasets are prepared and saved
|
||||
* at the second step $wizardnow = 'datasetdefinitions'
|
||||
* the datadefs final type are defined as private, category or not a datadef
|
||||
* at the third step $wizardnow = 'datasetitems'
|
||||
* the datadefs parameters and the data items are created or defined
|
||||
*
|
||||
* @param object question
|
||||
* @param object $form
|
||||
* @param int $course
|
||||
* @param PARAM_ALPHA $wizardnow should be added as we are coming from question2.php
|
||||
*/
|
||||
function save_question($question, $form, $course) {
|
||||
$question = default_questiontype::save_question($question, $form, $course);
|
||||
return $question;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function custom_generator_tools_part(&$mform, $idx, $j){
|
||||
|
||||
$minmaxgrp = array();
|
||||
|
@ -247,14 +257,14 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
$strheader = "";
|
||||
$delimiter = '';
|
||||
|
||||
// $answers = $question->options->answers;
|
||||
// $answers = $question->options->answers;
|
||||
|
||||
foreach ($answers as $key => $answer) {
|
||||
/* if (is_string($answer)) {
|
||||
$strheader .= $delimiter.$answer;
|
||||
} else {*/
|
||||
$strheader .= $delimiter.$answer->answer;
|
||||
// }
|
||||
} else {*/
|
||||
$strheader .= $delimiter.$answer->answer;
|
||||
// }
|
||||
$delimiter = '<br/><br/><br/>';
|
||||
}
|
||||
return $strheader;
|
||||
|
@ -262,18 +272,18 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
|
||||
function tolerance_types() {
|
||||
return array('1' => get_string('relative', 'quiz'),
|
||||
'2' => get_string('nominal', 'quiz'),
|
||||
// '3' => get_string('geometric', 'quiz')
|
||||
);
|
||||
'2' => get_string('nominal', 'quiz'),
|
||||
// '3' => get_string('geometric', 'quiz')
|
||||
);
|
||||
}
|
||||
|
||||
function dataset_options($form, $name, $mandatory=true,$renameabledatasets=false) {
|
||||
// Takes datasets from the parent implementation but
|
||||
// filters options that are currently not accepted by calculated
|
||||
// It also determines a default selection...
|
||||
//$renameabledatasets not implemented anmywhere
|
||||
// Takes datasets from the parent implementation but
|
||||
// filters options that are currently not accepted by calculated
|
||||
// It also determines a default selection...
|
||||
//$renameabledatasets not implemented anmywhere
|
||||
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) {
|
||||
if (!preg_match('~^1-~', $key) && $key != '0') {
|
||||
|
@ -282,7 +292,7 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
}
|
||||
if (!$selected) {
|
||||
if ($mandatory){
|
||||
$selected = "1-0-$name"; // Default
|
||||
$selected = "1-0-$name"; // Default
|
||||
}else {
|
||||
$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.
|
||||
* Alternate DB table prefix may be used to facilitate data deletion.
|
||||
*/
|
||||
function generate_test($name, $courseid = null) {
|
||||
global $DB;
|
||||
list($form, $question) = parent::generate_test($name, $courseid);
|
||||
$form->feedback = 1;
|
||||
$form->multiplier = array(1, 1);
|
||||
$form->shuffleanswers = 1;
|
||||
$form->noanswers = 1;
|
||||
$form->qtype ='calculatedsimple';
|
||||
$question->qtype ='calculatedsimple';
|
||||
$form->answers = array('{a} + {b}');
|
||||
$form->fraction = array(1);
|
||||
$form->tolerance = array(0.01);
|
||||
$form->tolerancetype = array(1);
|
||||
$form->correctanswerlength = array(2);
|
||||
$form->correctanswerformat = array(1);
|
||||
$form->questiontext = "What is {a} + {b}?";
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function generate_test($name, $courseid = null) {
|
||||
global $DB;
|
||||
list($form, $question) = parent::generate_test($name, $courseid);
|
||||
$form->feedback = 1;
|
||||
$form->multiplier = array(1, 1);
|
||||
$form->shuffleanswers = 1;
|
||||
$form->noanswers = 1;
|
||||
$form->qtype ='calculatedsimple';
|
||||
$question->qtype ='calculatedsimple';
|
||||
$form->answers = array('{a} + {b}');
|
||||
$form->fraction = array(1);
|
||||
$form->tolerance = array(0.01);
|
||||
$form->tolerancetype = array(1);
|
||||
$form->correctanswerlength = array(2);
|
||||
$form->correctanswerformat = array(1);
|
||||
$form->questiontext = "What is {a} + {b}?";
|
||||
|
||||
if ($courseid) {
|
||||
$course = $DB->get_record('course', array('id'=> $courseid));
|
||||
}
|
||||
if ($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->nextpageparam["forceregeneration"]= 1;
|
||||
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
||||
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
||||
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
||||
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
||||
$dataset_form->itemid = array(1 => '' , 2 => '');
|
||||
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
||||
$dataset_form->definition = array(1 => "1-0-a",
|
||||
2 => "1-0-b");
|
||||
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
||||
$dataset_form->addbutton = 1;
|
||||
$dataset_form->selectadd = 1;
|
||||
$dataset_form->courseid = $courseid;
|
||||
$dataset_form->cmid = 0;
|
||||
$dataset_form->id = $new_question->id;
|
||||
$this->save_dataset_items($new_question, $dataset_form);
|
||||
$dataset_form = new stdClass();
|
||||
$dataset_form->nextpageparam["forceregeneration"]= 1;
|
||||
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
|
||||
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
|
||||
$dataset_form->calclength = array(1 => 1, 2 => 1);
|
||||
$dataset_form->number = array(1 => 5.4 , 2 => 4.9);
|
||||
$dataset_form->itemid = array(1 => '' , 2 => '');
|
||||
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
|
||||
$dataset_form->definition = array(1 => "1-0-a",
|
||||
2 => "1-0-b");
|
||||
$dataset_form->nextpageparam = array('forceregeneration' => false);
|
||||
$dataset_form->addbutton = 1;
|
||||
$dataset_form->selectadd = 1;
|
||||
$dataset_form->courseid = $courseid;
|
||||
$dataset_form->cmid = 0;
|
||||
$dataset_form->id = $new_question->id;
|
||||
$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 ////
|
||||
|
||||
|
@ -349,5 +429,3 @@ question_register_questiontype(new question_calculatedsimple_qtype());
|
|||
if ( ! defined ("CALCULATEDSIMPLE")) {
|
||||
define("CALCULATEDSIMPLE", "calculatedsimple");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
<?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.
|
||||
*
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
<div class="qtext">
|
||||
<?php echo $questiontext; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php if ($generalfeedback) { ?>
|
||||
<div class="generalfeedback">
|
||||
|
|
|
@ -68,7 +68,6 @@ class description_qtype extends default_questiontype {
|
|||
$editlink = $this->get_question_edit_link($question, $cmoptions, $options);
|
||||
|
||||
$questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions);
|
||||
$image = get_question_image($question);
|
||||
|
||||
$generalfeedback = '';
|
||||
if ($isfinished && $options->generalfeedback) {
|
||||
|
@ -91,4 +90,3 @@ class description_qtype extends default_questiontype {
|
|||
}
|
||||
// Register this question type with questionlib.php.
|
||||
question_register_questiontype(new description_qtype());
|
||||
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -7,7 +23,7 @@
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package questionbank
|
||||
* @subpackage questiontypes
|
||||
*//** */
|
||||
*/
|
||||
|
||||
/**
|
||||
* Form definition base class. This defines the common fields that
|
||||
|
@ -27,24 +43,44 @@ class question_edit_form extends moodleform {
|
|||
* @var object
|
||||
*/
|
||||
public $question;
|
||||
|
||||
public $contexts;
|
||||
public $category;
|
||||
public $categorycontext;
|
||||
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){
|
||||
global $DB;
|
||||
|
||||
$this->question = $question;
|
||||
|
||||
$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->categorycontext = get_context_instance_by_id($category->contextid);
|
||||
|
||||
//** *
|
||||
//course id or site id depending on question cat context
|
||||
$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);
|
||||
|
||||
}
|
||||
|
@ -106,26 +142,9 @@ class question_edit_form extends moodleform {
|
|||
$mform->setType('name', PARAM_TEXT);
|
||||
$mform->addRule('name', null, 'required', null, 'client');
|
||||
|
||||
//TODO: MDL-16094 convert to new editor element
|
||||
$mform->addElement('htmleditor', 'questiontext', get_string('questiontext', 'quiz'),
|
||||
array('rows' => 15, 'course' => $this->coursefilesid));
|
||||
$mform->addElement('editor', 'questiontext', get_string('questiontext', 'quiz'),
|
||||
array('rows' => 15, 'course' => $this->coursefilesid), $this->editoroptions);
|
||||
$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'),
|
||||
array('size' => 3));
|
||||
|
@ -140,8 +159,8 @@ class question_edit_form extends moodleform {
|
|||
$mform->addHelpButton('penalty', 'penaltyfactor', 'question');
|
||||
$mform->setDefault('penalty', 0.1);
|
||||
|
||||
$mform->addElement('htmleditor', 'generalfeedback', get_string('generalfeedback', 'quiz'),
|
||||
array('rows' => 10, 'course' => $this->coursefilesid));
|
||||
$mform->addElement('editor', 'generalfeedback', get_string('generalfeedback', 'quiz'),
|
||||
array('rows' => 10, 'course' => $this->coursefilesid), $this->editoroptions);
|
||||
$mform->setType('generalfeedback', PARAM_RAW);
|
||||
$mform->addHelpButton('generalfeedback', 'generalfeedback', 'quiz');
|
||||
|
||||
|
@ -235,7 +254,7 @@ class question_edit_form extends moodleform {
|
|||
$errors= parent::validation($fromform, $files);
|
||||
if (empty($fromform->makecopy) && isset($this->question->id)
|
||||
&& ($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');
|
||||
}
|
||||
return $errors;
|
||||
|
@ -264,8 +283,8 @@ class question_edit_form extends moodleform {
|
|||
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
|
||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid), $this->editoroptions);
|
||||
$repeatedoptions['answer']['type'] = PARAM_RAW;
|
||||
$repeatedoptions['fraction']['default'] = 0;
|
||||
$answersoption = 'answers';
|
||||
|
@ -302,9 +321,33 @@ class question_edit_form extends moodleform {
|
|||
|
||||
function set_data($question) {
|
||||
global $QTYPES;
|
||||
if (empty($question->image)){
|
||||
unset($question->image);
|
||||
// prepare question text
|
||||
$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.
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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 '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
<?php echo $questiontext; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
|
||||
<div class="ablock clearfix">
|
||||
<div class="prompt">
|
||||
<?php echo $stranswer; ?>
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -19,8 +35,7 @@ class question_edit_essay_form extends question_edit_form {
|
|||
* @param MoodleQuickForm $mform the form being built.
|
||||
*/
|
||||
function definition_inner(&$mform) {
|
||||
$mform->addElement('htmleditor', 'feedback', get_string("feedback", "quiz"),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->addElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
|
||||
$mform->setType('feedback', PARAM_RAW);
|
||||
|
||||
$mform->addElement('hidden', 'fraction', 0);
|
||||
|
@ -32,17 +47,29 @@ class question_edit_essay_form extends question_edit_form {
|
|||
$mform->setType('penalty', PARAM_RAW);
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
function data_preprocessing($question) {
|
||||
if (!empty($question->options) && !empty($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;
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
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
|
||||
|
||||
// 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 ///
|
||||
/////////////////
|
||||
|
@ -21,6 +36,7 @@ class question_essay_qtype extends default_questiontype {
|
|||
|
||||
function save_question_options($question) {
|
||||
global $DB;
|
||||
$context = $question->context;
|
||||
$result = true;
|
||||
$update = true;
|
||||
$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;
|
||||
$update = false;
|
||||
}
|
||||
$answer->answer = $question->feedback;
|
||||
$answer->feedback = $question->feedback;
|
||||
$answer->feedbackformat = $question->feedback['format'];
|
||||
$answer->answerformat = $question->feedback['format'];
|
||||
$answer->fraction = $question->fraction;
|
||||
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);
|
||||
} 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;
|
||||
}
|
||||
|
@ -43,12 +66,14 @@ class question_essay_qtype extends default_questiontype {
|
|||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||
global $CFG;
|
||||
|
||||
$answers = &$question->options->answers;
|
||||
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
||||
$context = $this->get_context_by_category_id($question->category);
|
||||
|
||||
$answers = &$question->options->answers;
|
||||
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
||||
|
||||
// Only use the rich text editor for the first essay question on a page.
|
||||
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions->noclean = true;
|
||||
$formatoptions->para = false;
|
||||
|
||||
|
@ -60,13 +85,12 @@ class question_essay_qtype extends default_questiontype {
|
|||
$question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
|
||||
$image = get_question_image($question);
|
||||
|
||||
// feedback handling
|
||||
$feedback = '';
|
||||
if ($options->feedback && !empty($answers)) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
}
|
||||
//// 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... ///
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
question_register_questiontype(new question_essay_qtype());
|
||||
|
||||
|
|
|
@ -1,5 +1,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>
|
||||
<TABLE NAME="question_match" COMMENT="Defines fixed matching questions" NEXT="question_match_sub">
|
||||
<FIELDS>
|
||||
|
@ -18,8 +21,9 @@
|
|||
<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="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="answertext" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="questiontext"/>
|
||||
<FIELD NAME="questiontext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="questiontextformat"/>
|
||||
<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>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
||||
|
@ -27,4 +31,4 @@
|
|||
</KEYS>
|
||||
</TABLE>
|
||||
</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; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
|
||||
<div class="ablock clearfix">
|
||||
|
||||
<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) {
|
||||
$repeated = array();
|
||||
$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));
|
||||
$repeatedoptions['subquestions']['type'] = PARAM_RAW;
|
||||
$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);
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
if (isset($question->options)){
|
||||
function data_preprocessing($question) {
|
||||
if (isset($question->options)) {
|
||||
$subquestions = $question->options->subquestions;
|
||||
if (count($subquestions)) {
|
||||
$key = 0;
|
||||
foreach ($subquestions as $subquestion){
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
||||
$question = (object)((array)$question + $default_values);
|
||||
}
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
|
@ -69,7 +83,7 @@ class question_edit_match_form extends question_edit_form {
|
|||
$questioncount = 0;
|
||||
$answercount = 0;
|
||||
foreach ($questions as $key => $question){
|
||||
$trimmedquestion = trim($question);
|
||||
$trimmedquestion = trim($question['text']);
|
||||
$trimmedanswer = trim($answers[$key]);
|
||||
if ($trimmedquestion != ''){
|
||||
$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
|
||||
|
||||
// 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 ///
|
||||
/////////////
|
||||
|
@ -24,6 +39,7 @@ class question_match_qtype extends default_questiontype {
|
|||
|
||||
function save_question_options($question) {
|
||||
global $DB;
|
||||
$context = $question->context;
|
||||
$result = new stdClass;
|
||||
|
||||
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
|
||||
foreach ($question->subquestions as $key => $questiontext) {
|
||||
$questiontext = trim($questiontext);
|
||||
$itemid = $questiontext['itemid'];
|
||||
$format = $questiontext['format'];
|
||||
$questiontext = trim($questiontext['text']);
|
||||
$answertext = trim($question->subanswers[$key]);
|
||||
if ($questiontext != '' || $answertext != '') {
|
||||
if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it
|
||||
$subquestion->questiontext = $questiontext;
|
||||
$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);
|
||||
} else {
|
||||
$subquestion = new stdClass;
|
||||
// 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))) {
|
||||
$subquestion->code = rand();
|
||||
}
|
||||
$subquestion->question = $question->id;
|
||||
$subquestion->questiontext = $questiontext;
|
||||
$subquestion->answertext = $answertext;
|
||||
$subquestion->questiontextformat = $format;
|
||||
$subquestion->answertext = $answertext;
|
||||
$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;
|
||||
}
|
||||
|
@ -228,6 +250,7 @@ class question_match_qtype extends default_questiontype {
|
|||
|
||||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||
global $CFG, $OUTPUT;
|
||||
$context = $this->get_context_by_category_id($question->category);
|
||||
$subquestions = $state->options->subquestions;
|
||||
$correctanswers = $this->get_correct_responses($question, $state);
|
||||
$nameprefix = $question->name_prefix;
|
||||
|
@ -263,15 +286,14 @@ class question_match_qtype extends default_questiontype {
|
|||
// Print formulation
|
||||
$questiontext = $this->format_text($question->questiontext,
|
||||
$question->questiontextformat, $cmoptions);
|
||||
$image = get_question_image($question);
|
||||
|
||||
// Print the input controls
|
||||
foreach ($subquestions as $key => $subquestion) {
|
||||
if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) {
|
||||
// Subquestion text:
|
||||
$a = new stdClass;
|
||||
$a->text = $this->format_text($subquestion->questiontext,
|
||||
$question->questiontextformat, $cmoptions);
|
||||
$text = quiz_rewrite_question_urls($subquestion->questiontext, 'pluginfile.php', $context->id, 'qtype_match', 'subquestion', array($state->attempt, $state->question), $subquestion->id);
|
||||
$a->text = $this->format_text($text, $subquestion->questiontextformat, $cmoptions);
|
||||
|
||||
// Drop-down list:
|
||||
$menuname = $nameprefix.$subquestion->id;
|
||||
|
@ -757,6 +779,53 @@ class question_match_qtype extends default_questiontype {
|
|||
|
||||
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 ////
|
||||
|
||||
|
@ -764,4 +833,3 @@ class question_match_qtype extends default_questiontype {
|
|||
//// INITIATION - Without this line the question type is not in use... ///
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
question_register_questiontype(new question_match_qtype());
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
$plugin->version = 2006032200;
|
||||
$plugin->version = 2009072100;
|
||||
$plugin->requires = 2007101000;
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
<?php echo $questiontext; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($anss) { ?>
|
||||
<div class="ablock clearfix">
|
||||
<div class="prompt">
|
||||
|
@ -21,4 +17,4 @@
|
|||
<?php } ?>
|
||||
</table>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
|
|
|
@ -42,7 +42,6 @@ class question_missingtype_qtype extends default_questiontype {
|
|||
$questiontext = format_text($question->questiontext,
|
||||
$question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
$image = get_question_image($question);
|
||||
|
||||
// Print each answer in a separate row if there are any
|
||||
$anss = array();
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
class question_edit_multianswer_form extends question_edit_form {
|
||||
|
||||
// $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
|
||||
var $savedquestion ;
|
||||
var $savedquestiondisplay ;
|
||||
var $used_in_quiz = false ;
|
||||
var $qtype_change = false ;
|
||||
var $negative_diff = 0 ;
|
||||
var $nb_of_quiz = 0;
|
||||
var $nb_of_attempts = 0;
|
||||
public $savedquestion ;
|
||||
public $savedquestiondisplay ;
|
||||
public $used_in_quiz = false ;
|
||||
public $qtype_change = false ;
|
||||
public $negative_diff = 0 ;
|
||||
public $nb_of_quiz = 0;
|
||||
public $nb_of_attempts = 0;
|
||||
public $confirm = 0 ;
|
||||
public $reload = false ;
|
||||
|
||||
|
@ -35,9 +35,9 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
}else {
|
||||
$this->reload = false ;
|
||||
}
|
||||
// $this->question = $question;
|
||||
$this->used_in_quiz =false;
|
||||
// echo "<p> question <pre>";print_r($question);echo "</pre></p>";
|
||||
// $this->question = $question;
|
||||
$this->used_in_quiz =false;
|
||||
// echo "<p> question <pre>";print_r($question);echo "</pre></p>";
|
||||
if(isset($question->id) && $question->id != 0 ){
|
||||
$this->savedquestiondisplay =fullclone($question ) ;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function definition_inner(&$mform) {
|
||||
$mform->addElement('hidden', 'reload', 1);
|
||||
$mform->setType('reload', PARAM_INT);
|
||||
|
@ -69,7 +63,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
$mform->removeElement('defaultgrade');
|
||||
$this->confirm = optional_param('confirm','0', PARAM_RAW);
|
||||
|
||||
// display the questions from questiontext;
|
||||
// display the questions from questiontext;
|
||||
if ( "" != 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
|
||||
$this->questiondisplay = fullclone($this->savedquestiondisplay);
|
||||
foreach($this->questiondisplay->options->questions as $subquestion){
|
||||
if (!empty($subquestion)){
|
||||
$subquestion->answer = array('');
|
||||
foreach($subquestion->options->answers as $ans){
|
||||
$subquestion->answer[]=$ans->answer ;
|
||||
if (!empty($subquestion)){
|
||||
$subquestion->answer = array('');
|
||||
foreach($subquestion->options->answers as $ans){
|
||||
$subquestion->answer[]=$ans->answer ;
|
||||
}
|
||||
// $subquestion->answer = fullclone($subquestion->options->answers);
|
||||
}
|
||||
// $subquestion->answer = fullclone($subquestion->options->answers);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
$this->questiondisplay = "";
|
||||
}
|
||||
|
@ -97,7 +91,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
$countsavedsubquestions =0;
|
||||
foreach($this->savedquestiondisplay->options->questions as $subquestion){
|
||||
if (!empty($subquestion)){
|
||||
$countsavedsubquestions++;
|
||||
$countsavedsubquestions++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -108,24 +102,24 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
$countsubquestions =0;
|
||||
foreach($this->questiondisplay->options->questions as $subquestion){
|
||||
if (!empty($subquestion)){
|
||||
$countsubquestions++;
|
||||
$countsubquestions++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$countsubquestions =0;
|
||||
}
|
||||
}else{
|
||||
$countsubquestions =$countsavedsubquestions ;
|
||||
} else {
|
||||
$countsubquestions =0;
|
||||
}
|
||||
// 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>";
|
||||
}else{
|
||||
$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->registerNoSubmitButton('analyzequestion');
|
||||
echo '<div class="ablock clearfix">';
|
||||
echo '<div class=" clearfix">';
|
||||
if ( $this->reload ){
|
||||
$mform->addElement('submit', 'analyzequestion', get_string('decodeverifyquestiontext','qtype_multianswer'));
|
||||
$mform->registerNoSubmitButton('analyzequestion');
|
||||
echo '<div class="ablock clearfix">';
|
||||
echo '<div class=" clearfix">';
|
||||
if ( $this->reload ){
|
||||
for ($sub =1;$sub <=$countsubquestions ;$sub++) {
|
||||
|
||||
$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);
|
||||
}
|
||||
$storemess = '';
|
||||
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
|
||||
$this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
|
||||
$this->qtype_change = true ;
|
||||
$storemess = "<font class=\"error\"> STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype]."</font >";
|
||||
}
|
||||
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
|
||||
$this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
|
||||
$this->qtype_change = true ;
|
||||
$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',
|
||||
'{#'.$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));
|
||||
|
||||
|
@ -153,16 +147,16 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
$mform->addElement('static', 'sub_'.$sub."_".'defaultgrade', get_string('defaultgrade', 'quiz'));
|
||||
$mform->setDefault('sub_'.$sub."_".'defaultgrade',$this->questiondisplay->options->questions[$sub]->defaultgrade);
|
||||
|
||||
if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
|
||||
$mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'quiz'));
|
||||
}
|
||||
if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
|
||||
$mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'quiz'));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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 ) {
|
||||
$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>';
|
||||
$this->negative_diff =$countsavedsubquestions - $countsubquestions ;
|
||||
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) {
|
||||
//$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 )
|
||||
{
|
||||
$mform->addElement('static', 'alert1', "<strong>".get_string('questiontypechanged','qtype_multianswer')."</strong>",get_string('questiontypechangedcomment','qtype_multianswer'));
|
||||
if($this->qtype_change ) {
|
||||
$mform->addElement('static', 'alert1', "<strong>".get_string('questiontypechanged','qtype_multianswer')."</strong>",get_string('questiontypechangedcomment','qtype_multianswer'));
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
@ -219,11 +211,11 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
|
||||
foreach ($question->options->questions as $key => $wrapped) {
|
||||
if(!empty($wrapped)){
|
||||
// The old way of restoring the definitions is kept to gradually
|
||||
// update all multianswer questions
|
||||
if (empty($wrapped->questiontext)) {
|
||||
$parsableanswerdef = '{' . $wrapped->defaultgrade . ':';
|
||||
switch ($wrapped->qtype) {
|
||||
// The old way of restoring the definitions is kept to gradually
|
||||
// update all multianswer questions
|
||||
if (empty($wrapped->questiontext)) {
|
||||
$parsableanswerdef = '{' . $wrapped->defaultgrade . ':';
|
||||
switch ($wrapped->qtype) {
|
||||
case 'multichoice':
|
||||
$parsableanswerdef .= 'MULTICHOICE:';
|
||||
break;
|
||||
|
@ -235,62 +227,62 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
break;
|
||||
default:
|
||||
print_error('unknownquestiontype', 'question', '', $wrapped->qtype);
|
||||
}
|
||||
$separator= '';
|
||||
foreach ($wrapped->options->answers as $subanswer) {
|
||||
$parsableanswerdef .= $separator
|
||||
}
|
||||
$separator= '';
|
||||
foreach ($wrapped->options->answers as $subanswer) {
|
||||
$parsableanswerdef .= $separator
|
||||
. '%' . round(100*$subanswer->fraction) . '%';
|
||||
$parsableanswerdef .= $subanswer->answer;
|
||||
if (!empty($wrapped->options->tolerance)) {
|
||||
// Special for numerical answers:
|
||||
$parsableanswerdef .= ":{$wrapped->options->tolerance}";
|
||||
// We only want tolerance for the first alternative, it will
|
||||
// be applied to all of the alternatives.
|
||||
unset($wrapped->options->tolerance);
|
||||
$parsableanswerdef .= $subanswer->answer;
|
||||
if (!empty($wrapped->options->tolerance)) {
|
||||
// Special for numerical answers:
|
||||
$parsableanswerdef .= ":{$wrapped->options->tolerance}";
|
||||
// We only want tolerance for the first alternative, it will
|
||||
// be applied to all of the alternatives.
|
||||
unset($wrapped->options->tolerance);
|
||||
}
|
||||
if ($subanswer->feedback) {
|
||||
$parsableanswerdef .= "#$subanswer->feedback";
|
||||
}
|
||||
$separator = '~';
|
||||
}
|
||||
if ($subanswer->feedback) {
|
||||
$parsableanswerdef .= "#$subanswer->feedback";
|
||||
}
|
||||
$separator = '~';
|
||||
$parsableanswerdef .= '}';
|
||||
// Fix the questiontext fields of old questions
|
||||
$DB->set_field('question', 'questiontext', $parsableanswerdef, array('id' => $wrapped->id));
|
||||
} else {
|
||||
$parsableanswerdef = str_replace('&#', '&\#', $wrapped->questiontext);
|
||||
}
|
||||
$parsableanswerdef .= '}';
|
||||
// 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);
|
||||
}
|
||||
$question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set default to $questiondisplay questions elements
|
||||
if ( $this->reload ){
|
||||
if (isset($this->questiondisplay->options->questions)) {
|
||||
$subquestions = fullclone($this->questiondisplay->options->questions) ;
|
||||
if (count($subquestions)) {
|
||||
$sub =1;
|
||||
foreach ($subquestions as $subquestion) {
|
||||
$prefix = 'sub_'.$sub.'_' ;
|
||||
if (isset($this->questiondisplay->options->questions)) {
|
||||
$subquestions = fullclone($this->questiondisplay->options->questions) ;
|
||||
if (count($subquestions)) {
|
||||
$sub =1;
|
||||
foreach ($subquestions as $subquestion) {
|
||||
$prefix = 'sub_'.$sub.'_' ;
|
||||
|
||||
// validate parameters
|
||||
$answercount = 0;
|
||||
$maxgrade = false;
|
||||
$maxfraction = -1;
|
||||
if ($subquestion->qtype =='shortanswer' ) {
|
||||
switch ($subquestion->usecase) {
|
||||
// validate parameters
|
||||
$answercount = 0;
|
||||
$maxgrade = false;
|
||||
$maxfraction = -1;
|
||||
if ($subquestion->qtype =='shortanswer' ) {
|
||||
switch ($subquestion->usecase) {
|
||||
case '1':
|
||||
$default_values[$prefix.'usecase']= get_string('caseyes', 'quiz');
|
||||
break;
|
||||
case '0':
|
||||
default :
|
||||
$default_values[$prefix.'usecase']= get_string('caseno', 'quiz');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($subquestion->qtype == 'multichoice' ) {
|
||||
$default_values[$prefix.'layout'] = $subquestion->layout ;
|
||||
switch ($subquestion->layout) {
|
||||
if ($subquestion->qtype == 'multichoice' ) {
|
||||
$default_values[$prefix.'layout'] = $subquestion->layout ;
|
||||
switch ($subquestion->layout) {
|
||||
case '0':
|
||||
$default_values[$prefix.'layout']= get_string('layoutselectinline', 'qtype_multianswer');
|
||||
break;
|
||||
|
@ -302,53 +294,53 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
break;
|
||||
default:
|
||||
$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);
|
||||
}
|
||||
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));
|
||||
$default_values[$prefix.'answer['.$key.']'] = htmlspecialchars ($answer);
|
||||
}
|
||||
}
|
||||
if ($maxgrade == false) {
|
||||
$this->_form->setElementError($prefix.'fraction[0]' ,get_string('fractionsnomax', 'question'));
|
||||
}
|
||||
foreach ($subquestion->feedback as $key=>$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 ($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);
|
||||
}
|
||||
foreach ( $subquestion->fraction as $key=>$answer) {
|
||||
$default_values[$prefix.'fraction['.$key.']'] = $answer;
|
||||
}
|
||||
$default_values[$prefix.'feedback['.$key.']'] = htmlspecialchars ($answer);
|
||||
}
|
||||
foreach ( $subquestion->fraction as $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 != "") {
|
||||
$question = (object)((array)$question + $default_values);
|
||||
|
@ -358,14 +350,11 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
|
||||
function 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)) {
|
||||
|
||||
$subquestions = fullclone($questiondisplay->options->questions) ;
|
||||
$subquestions = fullclone($questiondisplay->options->questions) ;
|
||||
if (count($subquestions)) {
|
||||
$sub =1;
|
||||
foreach ($subquestions as $subquestion) {
|
||||
|
@ -373,17 +362,17 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
$answercount = 0;
|
||||
$maxgrade = false;
|
||||
$maxfraction = -1;
|
||||
if(isset($this->savedquestiondisplay->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];
|
||||
}
|
||||
if(isset($this->savedquestiondisplay->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];
|
||||
}
|
||||
foreach ( $subquestion->answer as $key=>$answer) {
|
||||
$trimmedanswer = trim($answer);
|
||||
if ($trimmedanswer !== '') {
|
||||
$answercount++;
|
||||
if ($subquestion->qtype =='numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
|
||||
$errors[$prefix.'answer['.$key.']']= get_string('answermustbenumberorstar', 'qtype_numerical');
|
||||
}
|
||||
}
|
||||
if ($subquestion->fraction[$key] == 1) {
|
||||
$maxgrade = true;
|
||||
}
|
||||
|
@ -408,18 +397,17 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
$errors['questiontext']=get_string('questionsmissing', 'qtype_multianswer');
|
||||
}
|
||||
}
|
||||
// $question = qtype_multianswer_extract_question($data['questiontext']);
|
||||
// if (isset $question->options->questions
|
||||
// $question = qtype_multianswer_extract_question($data['questiontext']);
|
||||
// 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 ){
|
||||
$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() {
|
||||
return 'multianswer';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -307,10 +307,6 @@ class embedded_cloze_qtype extends default_questiontype {
|
|||
}
|
||||
|
||||
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,
|
||||
$question->questiontextformat, $formatoptions, $cmoptions->course);
|
||||
|
@ -986,9 +982,7 @@ function qtype_multianswer_extract_question($text) {
|
|||
$question->options->questions = array();
|
||||
$question->defaultgrade = 0; // Will be increased for each answer norm
|
||||
|
||||
for ($positionkey=1
|
||||
; preg_match('/'.ANSWER_REGEX.'/', $question->questiontext, $answerregs)
|
||||
; ++$positionkey ) {
|
||||
for ($positionkey=1; preg_match('/'.ANSWER_REGEX.'/', $question->questiontext['text'], $answerregs); ++$positionkey ) {
|
||||
$wrapped = new stdClass;
|
||||
if (isset($answerregs[ANSWER_REGEX_NORM])&& $answerregs[ANSWER_REGEX_NORM]!== ''){
|
||||
$wrapped->defaultgrade = $answerregs[ANSWER_REGEX_NORM];
|
||||
|
@ -1087,4 +1081,3 @@ function qtype_multianswer_extract_question($text) {
|
|||
$question->questiontext = $question->questiontext;
|
||||
return $question;
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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"
|
||||
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="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="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="partiallycorrectfeedback"/>
|
||||
<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="incorrectfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="partiallycorrectfeedback" 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="incorrectfeedback"/>
|
||||
<FIELD NAME="correctfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any correct response." PREVIOUS="shuffleanswers" NEXT="correctfeedbackformat"/>
|
||||
<FIELD NAME="correctfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="correctfeedback" NEXT="partiallycorrectfeedback"/>
|
||||
<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="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>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="question"/>
|
||||
|
@ -23,4 +26,4 @@
|
|||
</KEYS>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
</XMLDB>
|
|
@ -52,6 +52,61 @@ function xmldb_qtype_multichoice_upgrade($oldversion) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
<?php echo $questiontext; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
|
||||
<div class="ablock clearfix">
|
||||
<div class="prompt">
|
||||
<?php echo $answerprompt; ?>
|
||||
|
|
|
@ -1,4 +1,22 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -47,14 +65,14 @@ class question_edit_multichoice_form extends question_edit_form {
|
|||
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
||||
|
||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||
$mform->addElement('htmleditor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'),
|
||||
array('course' => $this->coursefilesid), $this->editoroptions);
|
||||
$mform->setType($feedbackname, PARAM_RAW);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
function data_preprocessing($question) {
|
||||
if (isset($question->options)){
|
||||
$answers = $question->options->answers;
|
||||
if (count($answers)) {
|
||||
|
@ -62,19 +80,44 @@ class question_edit_multichoice_form extends question_edit_form {
|
|||
foreach ($answers as $answer){
|
||||
$default_values['answer['.$key.']'] = $answer->answer;
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
$default_values['single'] = $question->options->single;
|
||||
$default_values['answernumbering'] = $question->options->answernumbering;
|
||||
$default_values['shuffleanswers'] = $question->options->shuffleanswers;
|
||||
$default_values['correctfeedback'] = $question->options->correctfeedback;
|
||||
$default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback;
|
||||
$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_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);
|
||||
}
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
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));
|
||||
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.'!');
|
||||
return false;
|
||||
echo $OUTPUT->notification('Error: Missing question answers for multichoice question'.$question->id.'!');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -38,6 +38,7 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
|
||||
function save_question_options($question) {
|
||||
global $DB;
|
||||
$context = $question->context;
|
||||
$result = new stdClass;
|
||||
if (!$oldanswers = $DB->get_records("question_answers", array("question" => $question->id), "id ASC")) {
|
||||
$oldanswers = array();
|
||||
|
@ -65,18 +66,23 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
|
||||
foreach ($question->answer as $key => $dataanswer) {
|
||||
if ($dataanswer != "") {
|
||||
$feedbackformat = $question->feedback[$key]['format'];
|
||||
if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||
$answer->answer = $dataanswer;
|
||||
$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);
|
||||
} else {
|
||||
unset($answer);
|
||||
$answer->answer = $dataanswer;
|
||||
$answer->question = $question->id;
|
||||
$answer->fraction = $question->fraction[$key];
|
||||
$answer->feedback = $question->feedback[$key];
|
||||
$answer->feedback = '';
|
||||
$answer->feedbackformat = $feedbackformat;
|
||||
$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;
|
||||
|
||||
|
@ -100,13 +106,19 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
$options->answers = implode(",",$answers);
|
||||
$options->single = $question->single;
|
||||
if(isset($question->layout)){
|
||||
$options->layout = $question->layout;
|
||||
$options->layout = $question->layout;
|
||||
}
|
||||
$options->answernumbering = $question->answernumbering;
|
||||
$options->shuffleanswers = $question->shuffleanswers;
|
||||
$options->correctfeedback = trim($question->correctfeedback);
|
||||
$options->partiallycorrectfeedback = trim($question->partiallycorrectfeedback);
|
||||
$options->incorrectfeedback = trim($question->incorrectfeedback);
|
||||
|
||||
foreach (array('correct', 'partiallycorrect', 'incorrect') as $feedbacktype) {
|
||||
$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) {
|
||||
$DB->update_record("question_multichoice", $options);
|
||||
} else {
|
||||
|
@ -139,11 +151,11 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
}
|
||||
|
||||
/**
|
||||
* Deletes question from the question-type specific tables
|
||||
*
|
||||
* @return boolean Success/Failure
|
||||
* @param object $question The question being deleted
|
||||
*/
|
||||
* Deletes question from the question-type specific tables
|
||||
*
|
||||
* @return boolean Success/Failure
|
||||
* @param object $question The question being deleted
|
||||
*/
|
||||
function delete_question($questionid) {
|
||||
global $DB;
|
||||
$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) {
|
||||
// create an array of answerids ??? why so complicated ???
|
||||
$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
|
||||
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
|
||||
$answerids = swapshuffle($answerids);
|
||||
$answerids = swapshuffle($answerids);
|
||||
}
|
||||
$state->options->order = $answerids;
|
||||
// Create empty responses
|
||||
|
@ -203,7 +215,7 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
$state->responses = array_flip($state->responses);
|
||||
// Set the value of each element to be equal to the index
|
||||
array_walk($state->responses, create_function('&$a, $b',
|
||||
'$a = $b;'));
|
||||
'$a = $b;'));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -252,6 +264,10 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
|
||||
global $CFG;
|
||||
|
||||
// required by file api
|
||||
$context = $this->get_context_by_category_id($question->category);
|
||||
$component = 'qtype_' . $question->qtype;
|
||||
|
||||
$answers = &$question->options->answers;
|
||||
$correctanswers = $this->get_correct_responses($question, $state);
|
||||
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
||||
|
@ -261,10 +277,8 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
$formatoptions->para = false;
|
||||
|
||||
// Print formulation
|
||||
$questiontext = format_text($question->questiontext,
|
||||
$question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
$image = get_question_image($question);
|
||||
$questiontext = format_text($question->questiontext, $question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
$answerprompt = ($question->options->single) ? get_string('singleanswer', 'quiz') :
|
||||
get_string('multipleanswers', 'quiz');
|
||||
|
||||
|
@ -311,11 +325,13 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
|
||||
// Print the answer text
|
||||
$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
|
||||
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 {
|
||||
$a->feedback = '';
|
||||
}
|
||||
|
@ -327,14 +343,18 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
if ($options->feedback) {
|
||||
if ($state->raw_grade >= $question->maxgrade/1.01) {
|
||||
$feedback = $question->options->correctfeedback;
|
||||
$feedbacktype = 'correctfeedback';
|
||||
} else if ($state->raw_grade > 0) {
|
||||
$feedback = $question->options->partiallycorrectfeedback;
|
||||
$feedbacktype = 'partiallycorrectfeedback';
|
||||
} else {
|
||||
$feedback = $question->options->incorrectfeedback;
|
||||
$feedbacktype = 'incorrectfeedback';
|
||||
}
|
||||
$feedback = format_text($feedback,
|
||||
$question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
|
||||
$feedback = quiz_rewrite_question_urls($feedback, 'pluginfile.php', $context->id, $component, $feedbacktype, array($state->attempt, $state->question), $question->id);
|
||||
$feedbackformat = $feedbacktype . 'format';
|
||||
$feedback = format_text($feedback, $question->options->$feedbackformat, $formatoptions, $cmoptions->course);
|
||||
}
|
||||
|
||||
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
|
||||
$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
|
||||
$state->penalty = $question->penalty * $question->maxgrade;
|
||||
|
@ -401,7 +421,7 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
}
|
||||
return $totalfraction / count($question->options->answers);
|
||||
}
|
||||
/// BACKUP FUNCTIONS ////////////////////////////
|
||||
/// BACKUP FUNCTIONS ////////////////////////////
|
||||
|
||||
/*
|
||||
* Backup the data in the question
|
||||
|
@ -436,7 +456,7 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
return $status;
|
||||
}
|
||||
|
||||
/// RESTORE FUNCTIONS /////////////////
|
||||
/// RESTORE FUNCTIONS /////////////////
|
||||
|
||||
/*
|
||||
* Restores the data in the question
|
||||
|
@ -575,31 +595,31 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
|
||||
// Decode links in the question_multichoice table.
|
||||
if ($multichoices = $DB->get_records_list('question_multichoice', 'question',
|
||||
$questionids, '', 'id, correctfeedback, partiallycorrectfeedback, incorrectfeedback')) {
|
||||
$questionids, '', 'id, correctfeedback, partiallycorrectfeedback, incorrectfeedback')) {
|
||||
|
||||
foreach ($multichoices as $multichoice) {
|
||||
$correctfeedback = restore_decode_content_links_worker($multichoice->correctfeedback, $restore);
|
||||
$partiallycorrectfeedback = restore_decode_content_links_worker($multichoice->partiallycorrectfeedback, $restore);
|
||||
$incorrectfeedback = restore_decode_content_links_worker($multichoice->incorrectfeedback, $restore);
|
||||
if ($correctfeedback != $multichoice->correctfeedback ||
|
||||
foreach ($multichoices as $multichoice) {
|
||||
$correctfeedback = restore_decode_content_links_worker($multichoice->correctfeedback, $restore);
|
||||
$partiallycorrectfeedback = restore_decode_content_links_worker($multichoice->partiallycorrectfeedback, $restore);
|
||||
$incorrectfeedback = restore_decode_content_links_worker($multichoice->incorrectfeedback, $restore);
|
||||
if ($correctfeedback != $multichoice->correctfeedback ||
|
||||
$partiallycorrectfeedback != $multichoice->partiallycorrectfeedback ||
|
||||
$incorrectfeedback != $multichoice->incorrectfeedback) {
|
||||
$subquestion->correctfeedback = $correctfeedback;
|
||||
$subquestion->partiallycorrectfeedback = $partiallycorrectfeedback;
|
||||
$subquestion->incorrectfeedback = $incorrectfeedback;
|
||||
$DB->update_record('question_multichoice', $multichoice);
|
||||
}
|
||||
$subquestion->correctfeedback = $correctfeedback;
|
||||
$subquestion->partiallycorrectfeedback = $partiallycorrectfeedback;
|
||||
$subquestion->incorrectfeedback = $incorrectfeedback;
|
||||
$DB->update_record('question_multichoice', $multichoice);
|
||||
}
|
||||
|
||||
// Do some output.
|
||||
if (++$i % 5 == 0 && !defined('RESTORE_SILENTLY')) {
|
||||
echo ".";
|
||||
if ($i % 100 == 0) {
|
||||
echo "<br />";
|
||||
// Do some output.
|
||||
if (++$i % 5 == 0 && !defined('RESTORE_SILENTLY')) {
|
||||
echo ".";
|
||||
if ($i % 100 == 0) {
|
||||
echo "<br />";
|
||||
}
|
||||
backup_flush(300);
|
||||
}
|
||||
backup_flush(300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
@ -625,16 +645,16 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
*/
|
||||
function number_in_style($num, $style) {
|
||||
switch($style) {
|
||||
case 'abc':
|
||||
return $this->number_html(chr(ord('a') + $num));
|
||||
case 'ABCD':
|
||||
return $this->number_html(chr(ord('A') + $num));
|
||||
case '123':
|
||||
return $this->number_html(($num + 1));
|
||||
case 'none':
|
||||
return '';
|
||||
default:
|
||||
return 'ERR';
|
||||
case 'abc':
|
||||
return $this->number_html(chr(ord('a') + $num));
|
||||
case 'ABCD':
|
||||
return $this->number_html(chr(ord('A') + $num));
|
||||
case '123':
|
||||
return $this->number_html(($num + 1));
|
||||
case 'none':
|
||||
return '';
|
||||
default:
|
||||
return 'ERR';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -708,8 +728,82 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
|
||||
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.
|
||||
question_register_questiontype(new question_multichoice_qtype());
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
$plugin->version = 2009021800;
|
||||
$plugin->version = 2009021801;
|
||||
$plugin->requires = 2007101000;
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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"
|
||||
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
|
@ -23,8 +23,9 @@
|
|||
<FIELDS>
|
||||
<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="instructions" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="question" NEXT="showunits"/>
|
||||
<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="instructions" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response." PREVIOUS="question" NEXT="instructionsformat"/>
|
||||
<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="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"/>
|
||||
|
@ -50,4 +51,4 @@
|
|||
</INDEXES>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
</XMLDB>
|
|
@ -51,6 +51,35 @@ function xmldb_qtype_numerical_upgrade($oldversion) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
<?php echo $questiontext; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
|
||||
<div class="ablock clearfix">
|
||||
<div class="prompt">
|
||||
<?php echo get_string("answer", "quiz").': '; ?>
|
||||
|
@ -237,7 +233,7 @@
|
|||
</div>
|
||||
<?php if (!empty($question->options->instructions)){?>
|
||||
<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>
|
||||
<?php }?>
|
||||
</fieldset>
|
||||
|
@ -250,5 +246,3 @@
|
|||
<?php } ?>
|
||||
<?php $this->print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -39,30 +55,36 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
$creategrades->gradeoptions);
|
||||
//------------------------------------------------------------------------------------------
|
||||
$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) {
|
||||
global $QTYPES ;
|
||||
function data_preprocessing($question) {
|
||||
global $QTYPES ;
|
||||
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;
|
||||
if (count($answers)) {
|
||||
$key = 0;
|
||||
foreach ($answers as $answer){
|
||||
$draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
|
||||
$default_values['answer['.$key.']'] = $answer->answer;
|
||||
$default_values['fraction['.$key.']'] = $answer->fraction;
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
$QTYPES['numerical']->set_numerical_unit_data($question,$default_values);
|
||||
$QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
|
||||
|
||||
/* if (isset($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);
|
||||
}
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
function validation($data, $files) {
|
||||
global $QTYPES;
|
||||
$errors = parent::validation($data, $files);
|
||||
|
@ -95,7 +118,7 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
if ($data['fraction'][$key] == 1) {
|
||||
$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');
|
||||
$answercount++;
|
||||
}
|
||||
|
@ -110,6 +133,7 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
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
|
||||
|
||||
// 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.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package questionbank
|
||||
* @subpackage questiontypes
|
||||
*//** */
|
||||
*/
|
||||
|
||||
require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
|
||||
|
||||
|
@ -19,6 +35,7 @@ require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
|
|||
* @package questionbank
|
||||
* @subpackage questiontypes
|
||||
*/
|
||||
|
||||
class question_numerical_qtype extends question_shortanswer_qtype {
|
||||
|
||||
public $virtualqtype = false;
|
||||
|
@ -52,7 +69,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
$this->get_numerical_units($question);
|
||||
//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);
|
||||
|
||||
// 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))) {
|
||||
$question->options->unitgradingtype = 0; // total grade
|
||||
$question->options->unitpenalty = 0;
|
||||
// the default
|
||||
// the default
|
||||
if ($defaultunit = $this->get_default_numerical_unit($question)) {
|
||||
// so units can be graded
|
||||
$question->options->showunits = NUMERICALQUESTIONUNITTEXTINPUTDISPLAY ;
|
||||
|
@ -85,18 +102,20 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
$question->options->showunits = NUMERICALQUESTIONUNITNODISPLAY ;
|
||||
}
|
||||
$question->options->unitsleft = 0 ;
|
||||
$question->options->instructions = '' ;
|
||||
$question->options->instructions = '';
|
||||
$question->options->instructionsformat = editors_get_preferred_format();
|
||||
} else {
|
||||
$question->options->unitgradingtype = $options->unitgradingtype;
|
||||
$question->options->unitpenalty = $options->unitpenalty;
|
||||
$question->options->showunits = $options->showunits ;
|
||||
$question->options->unitsleft = $options->unitsleft ;
|
||||
$question->options->instructions = $options->instructions ;
|
||||
$question->options->showunits = $options->showunits;
|
||||
$question->options->unitsleft = $options->unitsleft;
|
||||
$question->options->instructions = $options->instructions;
|
||||
$question->options->instructionsformat = $options->instructionsformat;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function get_numerical_units(&$question) {
|
||||
global $DB;
|
||||
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) {
|
||||
global $DB;
|
||||
$context = $question->context;
|
||||
|
||||
// Get old versions of the objects
|
||||
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||
$oldanswers = array();
|
||||
|
@ -148,7 +169,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
foreach ($question->answer as $key => $dataanswer) {
|
||||
// Check for, and ingore, completely blank answer from the form.
|
||||
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
|
||||
html_is_blank($question->feedback[$key])) {
|
||||
html_is_blank($question->feedback[$key]['text'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -163,13 +184,23 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
}
|
||||
$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
|
||||
$feedbacktext = file_save_draft_area_files($draftid, $context->id, 'question', 'answerfeedback', $oldanswer->id, self::$fileoptions, $feedbacktext);
|
||||
$answer->feedback = $feedbacktext;
|
||||
$answer->id = $oldanswer->id;
|
||||
$DB->update_record("question_answers", $answer);
|
||||
} else { // This is a completely new answer
|
||||
$answer->feedback = $feedbacktext;
|
||||
$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
|
||||
|
@ -220,10 +251,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
|
||||
function save_numerical_options(&$question) {
|
||||
global $DB;
|
||||
|
||||
$result = new stdClass;
|
||||
// numerical options
|
||||
$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) {
|
||||
$update = false;
|
||||
$options = new stdClass;
|
||||
|
@ -246,7 +278,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}else {
|
||||
$options->showunits = $question->showunits1;
|
||||
}
|
||||
}else {
|
||||
}else {
|
||||
if(isset($question->showunits)){
|
||||
$options->showunits = $question->showunits;
|
||||
}else {
|
||||
|
@ -264,22 +296,27 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}else {
|
||||
$options->unitsleft = 0 ;
|
||||
}
|
||||
$options->instructionsformat = $question->instructions['format'];
|
||||
if(isset($question->instructions)){
|
||||
$options->instructions = trim($question->instructions);
|
||||
$options->instructions = trim($question->instructions['text']);
|
||||
}else {
|
||||
$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 (!$DB->update_record("question_numerical_options", $options)) {
|
||||
$result->error = "Could not update numerical question options! (id=$options->id)";
|
||||
return $result;
|
||||
}
|
||||
$DB->update_record("question_numerical_options", $options);
|
||||
} else {
|
||||
if (!$DB->insert_record("question_numerical_options", $options)) {
|
||||
$result->error = "Could not insert numerical question options!";
|
||||
return $result;
|
||||
}
|
||||
$id = $DB->insert_record("question_numerical_options", $options);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -320,7 +357,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
$state->responses = array();
|
||||
$state->responses['answer'] = '';
|
||||
$state->responses['unit'] = '';
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
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));
|
||||
if (preg_match('~^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$~',
|
||||
$rawresponse, $responseparts)) {
|
||||
if(isset($responseparts[5]) ){
|
||||
if(isset($responseparts[5]) ){
|
||||
$unit = $responseparts[5] ;
|
||||
}
|
||||
if(isset($responseparts[1]) ){
|
||||
if(isset($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) {
|
||||
global $CFG;
|
||||
$context = $this->get_context_by_category_id($question->category);
|
||||
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions->noclean = true;
|
||||
$formatoptions->para = false;
|
||||
$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
|
||||
|
||||
$questiontext = format_text($question->questiontext,
|
||||
$question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
$image = get_question_image($question);
|
||||
|
||||
/// Print input controls
|
||||
// as the entry is controlled the question type here is numerical
|
||||
// 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
|
||||
// If $question->options->showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY"
|
||||
// radio elements display the defined unit
|
||||
// The code allows the input number elememt to be displayed
|
||||
// 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\"";
|
||||
$nameanswer = "name=\"".$question->name_prefix."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'] );
|
||||
}
|
||||
|
@ -438,7 +478,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
if (isset($state->responses['unit']) && $state->responses['unit']!='') {
|
||||
$valueunit = ' value="'.s($state->responses['unit']).'" ';
|
||||
} else {
|
||||
} else {
|
||||
$valueunit = ' value="" ';
|
||||
if ($question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ){
|
||||
$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
|
||||
// having to test for * so response as long as not empty
|
||||
$response = $this->extract_numerical_response($state->responses['answer']);
|
||||
$break = 0 ;
|
||||
$break = 0 ;
|
||||
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 !== '*' ) {
|
||||
$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 === '*') {
|
||||
$answerasterisk = true ;
|
||||
$rawgrade = $answer->fraction ;
|
||||
$rawgrade = $answer->fraction ;
|
||||
$class = question_get_feedback_class($answer->fraction);
|
||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||
$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);
|
||||
if ($answer->feedback) {
|
||||
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
||||
}
|
||||
if ( isset($question->options->units))
|
||||
{
|
||||
if ( isset($question->options->units))
|
||||
{
|
||||
$valid_numerical_unit = true ;
|
||||
}
|
||||
$break = 1 ;
|
||||
} else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
|
||||
$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.
|
||||
$testresponse = $response /$unit->multiplier ;
|
||||
$testresponse = $response /$unit->multiplier ;
|
||||
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
|
||||
$unittested = $unit->unit ;
|
||||
$rawgrade = $answer->fraction ;
|
||||
$rawgrade = $answer->fraction ;
|
||||
$class = question_get_feedback_class($answer->fraction);
|
||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||
if ($answer->feedback) {
|
||||
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
||||
}
|
||||
if($state->responses['unit'] == $unit->unit){
|
||||
if($state->responses['unit'] == $unit->unit){
|
||||
$classunitvalue = $answer->fraction ;
|
||||
}else {
|
||||
}else {
|
||||
$classunitvalue == 0 ;
|
||||
}
|
||||
$classunit = question_get_feedback_class($classunitvalue);
|
||||
$classunit = question_get_feedback_class($classunitvalue);
|
||||
$feedbackimgunit = question_get_feedback_image($classunitvalue, $options->feedback);
|
||||
$break = 1 ;
|
||||
$break = 1 ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if($response !== false && ($answer->min <= $response && $response <= $answer->max) ) {
|
||||
$rawgrade = $answer->fraction ;
|
||||
} else if($response !== false && ($answer->min <= $response && $response <= $answer->max) ) {
|
||||
$rawgrade = $answer->fraction ;
|
||||
$class = question_get_feedback_class($answer->fraction);
|
||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||
if ($answer->feedback) {
|
||||
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
|
||||
$feedback = format_text($answer->feedback, $answer->feedbackformat, $formatoptions, $cmoptions->course);
|
||||
}
|
||||
$break = 1 ;
|
||||
}
|
||||
if ($break) break;
|
||||
if ($break) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$state->options->raw_unitpenalty = 0 ;
|
||||
$raw_unitpenalty = 0 ;
|
||||
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
||||
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
||||
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
|
||||
$classunitvalue = 1 ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if($classunitvalue == 0){
|
||||
if($question->options->unitgradingtype == 1){
|
||||
|
@ -537,10 +580,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}else {
|
||||
$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
|
||||
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
|
||||
* answer or in one of the unit , false if it doesn't.
|
||||
* 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 ) {
|
||||
// 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
|
||||
* 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
|
||||
* the $state->responses['unit'] comes from either
|
||||
* the $state->responses['unit'] comes from either
|
||||
* a multichoice radio element NUMERICALQUESTIONUNITMULTICHOICEDISPLAY
|
||||
* where the $state->responses['unit'] value is the key => unit object
|
||||
* in the the $question->options->units array
|
||||
* or an input text element NUMERICALUNITTEXTINPUTDISPLAY
|
||||
* which contains the student response
|
||||
* for NUMERICALQUESTIONUNITTEXTDISPLAY and NUMERICALQUESTIONUNITNODISPLAY
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
|
||||
if (!isset($state->responses['answer']) && isset($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.
|
||||
$this->get_tolerance_interval($answer);
|
||||
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) {
|
||||
foreach($question->options->units as $key =>$unit){
|
||||
foreach($question->options->units as $key =>$unit){
|
||||
$testresponse = $response /$unit->multiplier ;
|
||||
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
|
||||
* number and unit of numerical or calculated questions
|
||||
* The code handles also the case when there no unit defined by the user or
|
||||
* when used in a multianswer (Cloze) question.
|
||||
* number and unit of numerical or calculated questions
|
||||
* The code handles also the case when there no unit defined by the user or
|
||||
* when used in a multianswer (Cloze) question.
|
||||
* This function performs response processing and grading and updates
|
||||
* the state accordingly.
|
||||
* @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[''])){
|
||||
$state->responses['answer'] = $state->responses[''];
|
||||
}
|
||||
|
||||
|
||||
//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
|
||||
// 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 ;
|
||||
$response = $this->extract_numerical_response($state->responses['answer']);
|
||||
$answerasterisk = false ;
|
||||
|
||||
$break = 0 ;
|
||||
|
||||
$break = 0 ;
|
||||
foreach($question->options->answers as $answer) {
|
||||
if ($answer->answer !== '*' ) {
|
||||
// The student did type a number, so check it with tolerances.
|
||||
$this->get_tolerance_interval($answer);
|
||||
}
|
||||
|
||||
// if * then everything is OK even unit
|
||||
// if * then everything is OK even unit
|
||||
if ($answer->answer === '*') {
|
||||
$state->raw_grade = $answer->fraction;
|
||||
if ( isset($question->options->units)){
|
||||
if ( isset($question->options->units)){
|
||||
$valid_numerical_unit = true ;
|
||||
}
|
||||
$answerasterisk = true ;
|
||||
$answerasterisk = true ;
|
||||
$break = 1 ;
|
||||
}else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
|
||||
$hasunits = 1 ;
|
||||
foreach($question->options->units as $key => $unit){
|
||||
$testresponse = $response /$unit->multiplier ;
|
||||
|
||||
foreach($question->options->units as $key => $unit){
|
||||
$testresponse = $response /$unit->multiplier ;
|
||||
|
||||
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
|
||||
$state->raw_grade = $answer->fraction;
|
||||
$unittested = $unit->unit ;
|
||||
$break = 1 ;
|
||||
$break = 1 ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if ($response !== false) {
|
||||
if($this->test_response($question, $state, $answer)) {
|
||||
|
@ -700,9 +742,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
if ($break) break;
|
||||
} //foreach($question->options
|
||||
|
||||
|
||||
// in all cases the unit should be tested
|
||||
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
||||
if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
|
||||
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
|
||||
$valid_numerical_unit = true ;
|
||||
}else {
|
||||
|
@ -714,7 +756,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
$valid_numerical_unit = true ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// apply unit penalty
|
||||
$raw_unitpenalty = 0 ;
|
||||
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 ;
|
||||
}
|
||||
|
||||
|
||||
// Make sure we don't assign negative or too high marks.
|
||||
$state->raw_grade = min(max((float) $state->raw_grade,
|
||||
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 ,
|
||||
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
|
||||
$replace = array('', '');
|
||||
}else { // remove spaces and normalise , to a . .
|
||||
}else { // remove spaces and normalise , to a . .
|
||||
$replace = array('', '.');
|
||||
}
|
||||
$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 ,
|
||||
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
|
||||
$replace = array('', '');
|
||||
}else { // remove spaces and normalise , to a . .
|
||||
}else { // remove spaces and normalise , to a . .
|
||||
$replace = array('', '.');
|
||||
}
|
||||
$rawresponse = str_replace($search, $replace, $rawresponse);
|
||||
|
@ -920,10 +962,10 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
|
||||
/**
|
||||
* function used in function definition_inner()
|
||||
* of edit_..._form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
* function used in function definition_inner()
|
||||
* of edit_..._form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
function add_units_options(&$mform, &$that){
|
||||
$mform->addElement('header', 'unithandling', get_string('unitshandling', 'qtype_numerical'));
|
||||
// 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('selectunits', 'qtype_numerical') , get_string('unitchoice', 'qtype_numerical'),1);
|
||||
$mform->addGroup($showunits0grp, 'showunits0grp', get_string('studentunitanswer', 'qtype_numerical'),' OR ' , false);
|
||||
$mform->addElement('htmleditor', 'instructions', get_string('instructions', 'qtype_numerical'),
|
||||
array('rows' => 10, 'course' => $that->coursefilesid));
|
||||
$mform->addElement('editor', 'instructions', get_string('instructions', 'qtype_numerical'), null, $that->editoroptions);
|
||||
$mform->addElement('static', 'separator1', '<HR/>', '<HR/>');
|
||||
// Units are not graded
|
||||
$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('showunits1','unitrole','eq','0');
|
||||
$mform->disabledIf('showunits0','unitrole','eq','1');
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -974,7 +1017,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
* of edit_..._form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
function add_units_elements(& $mform,& $that) {
|
||||
function add_units_elements(& $mform,& $that) {
|
||||
$repeated = array();
|
||||
$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 ()
|
||||
* of edit_..._form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
function set_numerical_unit_data(&$question,&$default_values){
|
||||
* function used in in function data_preprocessing() of edit_numerical_form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
function set_numerical_unit_data($mform, &$question, &$default_values){
|
||||
|
||||
list($categoryid) = explode(',', $question->category);
|
||||
$context = $this->get_context_by_category_id($categoryid);
|
||||
|
||||
if (isset($question->options)){
|
||||
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
|
||||
$default_values['unitpenalty'] = $question->options->unitpenalty ;
|
||||
switch ($question->options->showunits){
|
||||
case 'O' :
|
||||
case '1' :
|
||||
case '1' :
|
||||
$default_values['showunits0'] = $question->options->showunits ;
|
||||
$default_values['unitrole'] = 0 ;
|
||||
break;
|
||||
case '2' :
|
||||
case '3' :
|
||||
case '3' :
|
||||
$default_values['showunits1'] = $question->options->showunits ;
|
||||
$default_values['unitrole'] = 1 ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$default_values['unitsleft'] = $question->options->unitsleft ;
|
||||
$default_values['instructions'] = $question->options->instructions ;
|
||||
|
||||
if (isset($question->options->units)){
|
||||
|
||||
// processing files
|
||||
$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);
|
||||
if (!empty($units)) {
|
||||
foreach ($units as $key => $unit){
|
||||
|
@ -1042,11 +1102,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function use in in function validation()
|
||||
* of edit_..._form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
/**
|
||||
* function use in in function validation()
|
||||
* of edit_..._form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
|
||||
function validate_numerical_options(& $data, & $errors){
|
||||
$units = $data['unit'];
|
||||
|
@ -1055,9 +1115,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}else {
|
||||
$showunits = $data['showunits1'];
|
||||
}
|
||||
|
||||
if (($showunits == NUMERICALQUESTIONUNITTEXTINPUTDISPLAY) ||
|
||||
($showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY ) ||
|
||||
|
||||
if (($showunits == NUMERICALQUESTIONUNITTEXTINPUTDISPLAY) ||
|
||||
($showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY ) ||
|
||||
($showunits == NUMERICALQUESTIONUNITTEXTDISPLAY )){
|
||||
if (trim($units[0]) == ''){
|
||||
$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.
|
||||
$alreadyseenunits = array();
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
$plugin->version = 2009100100;
|
||||
$plugin->version = 2009100101;
|
||||
$plugin->requires = 2007101000;
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -30,6 +46,7 @@ require_once($CFG->libdir . '/questionlib.php');
|
|||
* @subpackage questiontypes
|
||||
*/
|
||||
class default_questiontype {
|
||||
public static $fileoptions = array('subdirs'=>false, 'maxfiles'=>-1, 'maxbytes'=>0);
|
||||
|
||||
/**
|
||||
* Name of the question type
|
||||
|
@ -294,31 +311,35 @@ class default_questiontype {
|
|||
*/
|
||||
function save_question($question, $form, $course) {
|
||||
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
|
||||
// question types.
|
||||
|
||||
// First, save the basic question itself
|
||||
$question->name = trim($form->name);
|
||||
$question->questiontext = trim($form->questiontext);
|
||||
$question->questiontextformat = $form->questiontextformat;
|
||||
$question->parent = isset($form->parent) ? $form->parent : 0;
|
||||
$question->length = $this->actual_number_of_questions($question);
|
||||
$question->penalty = isset($form->penalty) ? $form->penalty : 0;
|
||||
|
||||
if (empty($form->image)) {
|
||||
$question->image = '';
|
||||
if (empty($form->questiontext['text'])) {
|
||||
$question->questiontext = '';
|
||||
} 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 = '';
|
||||
} 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)) {
|
||||
$question->name = shorten_text(strip_tags($question->questiontext), 15);
|
||||
$question->name = shorten_text(strip_tags($form->questiontext['text']), 15);
|
||||
if (empty($question->name)) {
|
||||
$question->name = '-';
|
||||
}
|
||||
|
@ -332,14 +353,16 @@ class default_questiontype {
|
|||
$question->defaultgrade = $form->defaultgrade;
|
||||
}
|
||||
|
||||
list($question->category) = explode(',', $form->category);
|
||||
|
||||
if (!empty($question->id)) {
|
||||
/// Question already exists, update.
|
||||
$question->modifiedby = $USER->id;
|
||||
$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 {
|
||||
/// New question.
|
||||
// Set the unique code
|
||||
|
@ -349,6 +372,12 @@ class default_questiontype {
|
|||
$question->timecreated = time();
|
||||
$question->timemodified = time();
|
||||
$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
|
||||
|
@ -356,11 +385,14 @@ class default_questiontype {
|
|||
$form->qtype = $question->qtype;
|
||||
$form->category = $question->category;
|
||||
$form->questiontext = $question->questiontext;
|
||||
$form->questiontextformat = $question->questiontextformat;
|
||||
// current context
|
||||
$form->context = $context;
|
||||
|
||||
$result = $this->save_question_options($form);
|
||||
|
||||
if (!empty($result->error)) {
|
||||
print_error('questionsaveerror', 'question', '', $result->error);
|
||||
print_error($result->error);
|
||||
}
|
||||
|
||||
if (!empty($result->notice)) {
|
||||
|
@ -888,12 +920,18 @@ class default_questiontype {
|
|||
* @param object $cmoptions
|
||||
* @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
|
||||
provided the member functions it calls are overridden where required.
|
||||
The layout is determined by the template question.html */
|
||||
|
||||
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);
|
||||
|
||||
if (isset($question->randomquestionid)) {
|
||||
|
@ -908,7 +946,7 @@ class default_questiontype {
|
|||
$generalfeedback = '';
|
||||
if ($isgraded && $options->generalfeedback) {
|
||||
$generalfeedback = $this->format_text($question->generalfeedback,
|
||||
$question->questiontextformat, $cmoptions);
|
||||
$question->generalfeedbackformat, $cmoptions);
|
||||
}
|
||||
|
||||
$grade = '';
|
||||
|
@ -1246,6 +1284,22 @@ class default_questiontype {
|
|||
.' 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
|
||||
*
|
||||
|
@ -1494,29 +1548,6 @@ class default_questiontype {
|
|||
*/
|
||||
function find_file_links($question, $courseid){
|
||||
$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.
|
||||
$urls += question_find_file_links_from_html($question->questiontext, $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){
|
||||
global $CFG, $DB;
|
||||
$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.
|
||||
$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);
|
||||
|
@ -1802,5 +1818,45 @@ class default_questiontype {
|
|||
$question->qtype = $this->qtype;
|
||||
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->closeHeaderBefore('buttonar');
|
||||
}
|
||||
|
||||
function validation($fromform, $files) {
|
||||
//validation of category
|
||||
//is not relevant for this question type
|
||||
return array();
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
return 'random';
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ class random_qtype extends default_questiontype {
|
|||
}
|
||||
|
||||
function display_question_editing_page(&$mform, $question, $wizardnow){
|
||||
global $OUTPUT;
|
||||
$heading = $this->get_heading(empty($question->id));
|
||||
echo $OUTPUT->heading_with_help($heading, $this->name(), $this->plugin_name());
|
||||
$mform->display();
|
||||
|
@ -424,5 +425,3 @@ class random_qtype extends default_questiontype {
|
|||
//// INITIATION - Without this line the question type is not in use... ///
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
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.
|
||||
*/
|
||||
function definition_inner(&$mform) {
|
||||
$mform->removeElement('image');
|
||||
|
||||
$questionstoselect = array();
|
||||
for ($i=2; $i<=QUESTION_NUMANS; $i++){
|
||||
$questionstoselect[$i] = $i;
|
||||
|
@ -33,15 +31,15 @@ class question_edit_randomsamatch_form extends question_edit_form {
|
|||
$mform->setType('fraction', PARAM_RAW);
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
function data_preprocessing($question) {
|
||||
if (empty($question->name)) {
|
||||
$question->name = get_string("randomsamatch", "quiz");
|
||||
}
|
||||
|
||||
if (empty($question->questiontext)) {
|
||||
$question->questiontext = get_string("randomsamatchintro", "quiz");
|
||||
$question->questiontext = get_string("randomsamatchintro", "quiz");
|
||||
}
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
|
||||
function qtype() {
|
||||
|
@ -70,7 +68,5 @@ class question_edit_randomsamatch_form extends question_edit_form {
|
|||
$errors['choose'] = get_string('notenoughsaincategory', 'qtype_randomsamatch', $a);
|
||||
}
|
||||
return $errors;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
<?php echo $questiontext; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
|
||||
<div class="ablock clearfix">
|
||||
<div class="prompt">
|
||||
<?php echo get_string("answer", "quiz").': '; ?>
|
||||
|
|
|
@ -1,4 +1,22 @@
|
|||
<?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.
|
||||
*
|
||||
|
@ -30,22 +48,40 @@ class question_edit_shortanswer_form extends question_edit_form {
|
|||
$creategrades->gradeoptions);
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
function data_preprocessing($question) {
|
||||
if (isset($question->options)){
|
||||
$answers = $question->options->answers;
|
||||
$answers_ids = array();
|
||||
if (count($answers)) {
|
||||
$key = 0;
|
||||
foreach ($answers as $answer){
|
||||
$answers_ids[] = $answer->id;
|
||||
$default_values['answer['.$key.']'] = $answer->answer;
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
$default_values['usecase'] = $question->options->usecase;
|
||||
$default_values['usecase'] = $question->options->usecase;
|
||||
$question = (object)((array)$question + $default_values);
|
||||
}
|
||||
parent::set_data($question);
|
||||
return $question;
|
||||
}
|
||||
function 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) {
|
||||
$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');
|
||||
$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
|
||||
|
||||
// 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 ///
|
||||
///////////////////
|
||||
|
@ -27,17 +42,48 @@ class question_shortanswer_qtype extends default_questiontype {
|
|||
}
|
||||
|
||||
function extra_question_fields() {
|
||||
return array('question_shortanswer','answers','usecase');
|
||||
return array('question_shortanswer', 'answers', 'usecase');
|
||||
}
|
||||
|
||||
function questionid_column_name() {
|
||||
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) {
|
||||
global $DB;
|
||||
$result = new stdClass;
|
||||
|
||||
$context = $question->context;
|
||||
|
||||
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
|
||||
$oldanswers = array();
|
||||
}
|
||||
|
@ -49,23 +95,36 @@ class question_shortanswer_qtype extends default_questiontype {
|
|||
foreach ($question->answer as $key => $dataanswer) {
|
||||
// Check for, and ingore, completely blank answer from the form.
|
||||
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
|
||||
html_is_blank($question->feedback[$key])) {
|
||||
html_is_blank($question->feedback[$key]['text'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$feedbackformat = $question->feedback[$key]['format'];
|
||||
|
||||
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||
$answer = $oldanswer;
|
||||
$answer->answer = trim($dataanswer);
|
||||
$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);
|
||||
} else { // This is a completely new answer
|
||||
$answer = new stdClass;
|
||||
$answer->answer = trim($dataanswer);
|
||||
$answer->question = $question->id;
|
||||
$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);
|
||||
|
||||
// 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;
|
||||
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) {
|
||||
global $CFG;
|
||||
$context = $this->get_context_by_category_id($question->category);
|
||||
/// This implementation is also used by question type 'numerical'
|
||||
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
|
||||
$formatoptions = new stdClass;
|
||||
|
@ -109,7 +170,6 @@ class question_shortanswer_qtype extends default_questiontype {
|
|||
$questiontext = format_text($question->questiontext,
|
||||
$question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
$image = get_question_image($question);
|
||||
|
||||
/// Print input controls
|
||||
|
||||
|
@ -135,6 +195,7 @@ class question_shortanswer_qtype extends default_questiontype {
|
|||
$class = question_get_feedback_class($answer->fraction);
|
||||
$feedbackimg = question_get_feedback_image($answer->fraction);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
@ -145,7 +206,7 @@ class question_shortanswer_qtype extends default_questiontype {
|
|||
/// Removed correct answer, to be displayed later MDL-7496
|
||||
include($this->get_display_html_path());
|
||||
}
|
||||
|
||||
|
||||
function get_display_html_path() {
|
||||
global $CFG;
|
||||
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_string('gradingdetails', 'quiz', $grade) ;
|
||||
// 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
|
||||
if(isset($state->options->raw_unitpenalty) && $state->options->raw_unitpenalty > 0.0 ){
|
||||
echo ' ';
|
||||
print_string('unitappliedpenalty','qtype_numerical',question_format_grade($cmoptions, $state->options->raw_unitpenalty ));
|
||||
}
|
||||
}
|
||||
if ($cmoptions->penaltyscheme) {
|
||||
// print details of grade adjustment due to penalties
|
||||
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);
|
||||
}
|
||||
|
||||
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 ////
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
<?php echo $questiontext; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($image) { ?>
|
||||
<img class="qimage" src="<?php echo $image; ?>" alt="" />
|
||||
<?php } ?>
|
||||
|
||||
<div class="ablock clearfix">
|
||||
<div class="prompt">
|
||||
<?php print_string('answer', 'quiz') ?>:
|
||||
|
@ -27,4 +23,4 @@
|
|||
</div>
|
||||
<?php } ?>
|
||||
<?php $this->print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
<?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')) {
|
||||
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');
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @package questionbank
|
||||
* @subpackage questiontypes
|
||||
*//** */
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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'),
|
||||
array(0 => get_string('false', 'qtype_truefalse'), 1 => get_string('true', 'qtype_truefalse')));
|
||||
|
||||
$mform->addElement('htmleditor', 'feedbacktrue', get_string('feedbacktrue', 'qtype_truefalse'),
|
||||
array('course' => $this->coursefilesid));;
|
||||
$mform->addElement('editor', 'feedbacktrue', get_string('feedbacktrue', 'qtype_truefalse'), null, $this->editoroptions);;
|
||||
$mform->setType('feedbacktrue', PARAM_RAW);
|
||||
|
||||
$mform->addElement('htmleditor', 'feedbackfalse', get_string('feedbackfalse', 'qtype_truefalse'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->addElement('editor', 'feedbackfalse', get_string('feedbackfalse', 'qtype_truefalse'), null, $this->editoroptions);
|
||||
$mform->setType('feedbackfalse', PARAM_RAW);
|
||||
|
||||
// Fix penalty factor at 1.
|
||||
|
@ -43,9 +58,45 @@ class question_edit_truefalse_form extends question_edit_form {
|
|||
function set_data($question) {
|
||||
if (!empty($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->feedbacktrue = $trueanswer->feedback;
|
||||
$question->feedbackfalse = $question->options->answers[$question->options->falseanswer]->feedback;
|
||||
$question->feedbacktrue = array();
|
||||
$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);
|
||||
}
|
||||
|
|
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
|
||||
|
||||
// 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 ///
|
||||
/////////////////
|
||||
|
@ -24,34 +41,52 @@ class question_truefalse_qtype extends default_questiontype {
|
|||
$oldanswers = array();
|
||||
}
|
||||
|
||||
$feedbacktext = $question->feedbacktrue['text'];
|
||||
$feedbackitemid = $question->feedbacktrue['itemid'];
|
||||
$feedbackformat = $question->feedbacktrue['format'];
|
||||
// Save answer 'True'
|
||||
if ($true = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||
$true->answer = get_string("true", "quiz");
|
||||
$true->fraction = $question->correctanswer;
|
||||
$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);
|
||||
} else {
|
||||
unset($true);
|
||||
$true = new stdclass;
|
||||
$true->answer = get_string("true", "quiz");
|
||||
$true->question = $question->id;
|
||||
$true->fraction = $question->correctanswer;
|
||||
$true->feedback = $question->feedbacktrue;
|
||||
$true->feedback = '';
|
||||
$true->feedbackformat = $feedbackformat;
|
||||
$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'
|
||||
if ($false = array_shift($oldanswers)) { // Existing answer, so reuse it
|
||||
$false->answer = get_string("false", "quiz");
|
||||
$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);
|
||||
} else {
|
||||
unset($false);
|
||||
$false = new stdclass;
|
||||
$false->answer = get_string("false", "quiz");
|
||||
$false->question = $question->id;
|
||||
$false->fraction = 1 - (int)$question->correctanswer;
|
||||
$false->feedback = $question->feedbackfalse;
|
||||
$false->feedback = '';
|
||||
$false->feedbackformat = $feedbackformat;
|
||||
$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)
|
||||
|
@ -134,9 +169,9 @@ class question_truefalse_qtype extends default_questiontype {
|
|||
/**
|
||||
* Prints the main content of the question including any interactions
|
||||
*/
|
||||
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);
|
||||
|
||||
$readonly = $options->readonly ? ' disabled="disabled"' : '';
|
||||
|
||||
|
@ -148,7 +183,6 @@ class question_truefalse_qtype extends default_questiontype {
|
|||
$questiontext = format_text($question->questiontext,
|
||||
$question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
$image = get_question_image($question);
|
||||
|
||||
$answers = &$question->options->answers;
|
||||
$trueanswer = &$answers[$question->options->trueanswer];
|
||||
|
@ -198,12 +232,33 @@ class question_truefalse_qtype extends default_questiontype {
|
|||
$feedback = '';
|
||||
if ($options->feedback and isset($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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (isset($state->responses['']) && isset($question->options->answers[$state->responses['']])) {
|
||||
$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);
|
||||
}
|
||||
/**
|
||||
* 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 ////
|
||||
|
||||
|
@ -370,4 +453,3 @@ class question_truefalse_qtype extends default_questiontype {
|
|||
//// INITIATION - Without this line the question type is not in use... ///
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
question_register_questiontype(new question_truefalse_qtype());
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// This is compared against the values stored in the database to determine
|
||||
// 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
|
||||
|
||||
$release = '2.0 Preview 4+ (Build: 20100810)'; // Human-friendly version name
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue