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"/>
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -3192,3 +3206,123 @@ class question_edit_contexts {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
|
161
mod/quiz/lib.php
161
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
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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,7 +1426,8 @@ class question_bank_view {
|
|||
} else {
|
||||
$returnurl = str_replace($CFG->wwwroot . '/', '', $returnurl);
|
||||
$movecontexturl = new moodle_url('/question/contextmoveq.php',
|
||||
array('returnurl' => $returnurl, 'ids' => $questionids,
|
||||
array('returnurl' => $returnurl,
|
||||
'ids' => implode(',', $questionids),
|
||||
'tocatid' => $tocategoryid));
|
||||
if (!empty($cm->id)){
|
||||
$movecontexturl->param('cmid', $cm->id);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -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,11 +35,11 @@ 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;
|
||||
|
@ -48,14 +64,14 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
}
|
||||
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[] =& $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';
|
||||
|
@ -115,28 +131,27 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
|
||||
$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);
|
||||
// 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');
|
||||
|
@ -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() {
|
||||
|
@ -208,8 +255,8 @@ class question_edit_calculated_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);
|
||||
}
|
||||
|
@ -229,7 +276,7 @@ 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);
|
||||
|
@ -323,4 +370,3 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
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';
|
||||
|
@ -93,6 +95,7 @@ $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['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);
|
||||
}
|
|
@ -1,17 +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/>.
|
||||
|
||||
|
||||
/////////////////
|
||||
// CALCULATED ///
|
||||
/////////////////
|
||||
|
||||
/// QUESTION TYPE CLASS //////////////////
|
||||
|
||||
|
||||
|
||||
class question_calculated_qtype extends default_questiontype {
|
||||
|
||||
// Used by the function custom_generator_tools:
|
||||
var $calcgenerateidhasbeenadded = false;
|
||||
public $calcgenerateidhasbeenadded = false;
|
||||
public $virtualqtype = false;
|
||||
|
||||
function name() {
|
||||
|
@ -40,7 +54,6 @@ class question_calculated_qtype extends default_questiontype {
|
|||
$question->options->correctfeedback = '';
|
||||
$question->options->partiallycorrectfeedback = '';
|
||||
$question->options->incorrectfeedback = '';
|
||||
|
||||
}
|
||||
|
||||
if (!$question->options->answers = $DB->get_records_sql(
|
||||
|
@ -66,16 +79,12 @@ class question_calculated_qtype extends default_questiontype {
|
|||
}
|
||||
|
||||
function get_datasets_for_export(&$question){
|
||||
global $DB;
|
||||
global $DB, $CFG;
|
||||
$datasetdefs = array();
|
||||
if (!empty($question->id)) {
|
||||
global $CFG;
|
||||
$sql = "SELECT i.*
|
||||
FROM {question_datasets} d,
|
||||
{question_dataset_definitions} i
|
||||
WHERE d.question = ?
|
||||
AND d.datasetdefinition = i.id
|
||||
";
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE d.question = ? AND d.datasetdefinition = i.id";
|
||||
if ($records = $DB->get_records_sql($sql, array($question->id))) {
|
||||
foreach ($records as $r) {
|
||||
$def = $r ;
|
||||
|
@ -112,10 +121,9 @@ class question_calculated_qtype extends default_questiontype {
|
|||
}
|
||||
|
||||
function save_question_options($question) {
|
||||
//$options = $question->subtypeoptions;
|
||||
// Get old answers:
|
||||
// the code is used for calculated, calculatedsimple and calculatedmulti qtypes
|
||||
global $CFG, $DB, $QTYPES ;
|
||||
// the code is used for calculated, calculatedsimple and calculatedmulti qtypes
|
||||
$context = $question->context;
|
||||
if (isset($question->answer) && !isset($question->answers)) {
|
||||
$question->answers = $question->answer;
|
||||
}
|
||||
|
@ -136,19 +144,19 @@ class question_calculated_qtype extends default_questiontype {
|
|||
$options->single = 0; //$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);
|
||||
|
||||
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
|
||||
$feedback = $question->$feedbackname;
|
||||
$options->$feedbackname = trim($feedback['text']);
|
||||
$feedbackformat = $feedbackname . 'format';
|
||||
$options->$feedbackformat = trim($feedback['format']);
|
||||
$options->$feedbackname = file_save_draft_area_files($feedback['itemid'], $context->id, 'qtype_calculated', $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
|
||||
|
@ -178,13 +186,17 @@ class question_calculated_qtype extends default_questiontype {
|
|||
$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', $oldanswer->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
|
||||
|
@ -219,12 +231,12 @@ class question_calculated_qtype extends default_questiontype {
|
|||
$DB->delete_records('question_calculated', array('id' => $oo->id));
|
||||
}
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
@ -316,19 +328,15 @@ class question_calculated_qtype extends default_questiontype {
|
|||
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))) {
|
||||
FROM {question_dataset_definitions} a, {question_datasets} b
|
||||
WHERE b.question = ? AND a.id = b.datasetdefinition", array($question->id))) {
|
||||
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
|
||||
";
|
||||
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 {
|
||||
|
@ -373,8 +381,6 @@ class question_calculated_qtype extends default_questiontype {
|
|||
return $virtualqtype->create_session_and_responses($question, $state, $cmoptions, $attempt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function save_session_and_responses(&$question, &$state) {
|
||||
global $DB;
|
||||
$responses = 'dataset'.$state->options->datasetitem.'-' ;
|
||||
|
@ -536,9 +542,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
$mform->display();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -558,7 +562,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
$possibledatasets = $this->find_dataset_names($form->questiontext);
|
||||
$mandatorydatasets = array();
|
||||
foreach ($form->answers as $answer) {
|
||||
$mandatorydatasets += $this->find_dataset_names($answer);
|
||||
//$mandatorydatasets += $this->find_dataset_names($answer);
|
||||
}
|
||||
// if there are identical datasetdefs already saved in the original question.
|
||||
// either when editing a question or saving as new
|
||||
|
@ -600,12 +604,9 @@ class question_calculated_qtype extends default_questiontype {
|
|||
global $DB;
|
||||
$categorydatasetdefs = $DB->get_records_sql(
|
||||
"SELECT a.*
|
||||
FROM {question_datasets} b,
|
||||
{question_dataset_definitions} a
|
||||
WHERE a.id = b.datasetdefinition
|
||||
AND a.type = '1'
|
||||
AND a.category != 0
|
||||
AND b.question = ? ORDER BY a.name ",array($question->id));
|
||||
FROM {question_datasets} b, {question_dataset_definitions} a
|
||||
WHERE a.id = b.datasetdefinition AND a.type = '1' AND a.category != 0 AND b.question = ?
|
||||
ORDER BY a.name ", array($question->id));
|
||||
$questionname = $question->name ;
|
||||
$regs= array();
|
||||
if(preg_match('~#\{([^[:space:]]*)#~',$questionname , $regs)){
|
||||
|
@ -780,8 +781,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
$tolerancemaxset = true ;
|
||||
}
|
||||
}
|
||||
$question->questiontext = $this->substitute_variables(
|
||||
$question->questiontext, $state->options->dataset);
|
||||
$question->questiontext = $this->substitute_variables($question->questiontext, $state->options->dataset);
|
||||
//evaluate the equations i.e {=5+4)
|
||||
$qtext = "";
|
||||
$qtextremaining = $question->questiontext ;
|
||||
|
@ -968,8 +968,6 @@ class question_calculated_qtype extends default_questiontype {
|
|||
|
||||
$distriboptions = array('uniform' => get_string('uniform', 'qtype_calculated'), 'loguniform' => get_string('loguniform', 'qtype_calculated'));
|
||||
$mform->addElement('select', "calcdistribution[$idx]", get_string('calcdistribution', 'qtype_calculated'), $distriboptions);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function custom_generator_set_data($datasetdefs, $formdata){
|
||||
|
@ -1276,7 +1274,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
return $strheader;
|
||||
}
|
||||
|
||||
function comment_on_datasetitems($qtypeobj,$questionid,$questiontext, $answers,$data, $number) {
|
||||
function comment_on_datasetitems($qtypeobj, $questionid, $questiontext, $answers, $data, $number) {
|
||||
global $DB, $QTYPES;
|
||||
$comment = new stdClass;
|
||||
$comment->stranswers = array();
|
||||
|
@ -1332,7 +1330,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
}
|
||||
return fullclone($comment);
|
||||
}
|
||||
function multichoice_comment_on_datasetitems($questionid,$questiontext, $answers,$data, $number) {
|
||||
function multichoice_comment_on_datasetitems($questionid, $questiontext, $answers,$data, $number) {
|
||||
global $DB;
|
||||
$comment = new stdClass;
|
||||
$comment->stranswers = array();
|
||||
|
@ -1537,11 +1535,8 @@ class question_calculated_qtype extends default_questiontype {
|
|||
if (!empty($questionid)) {
|
||||
global $CFG;
|
||||
$sql = "SELECT i.*
|
||||
FROM {question_datasets} d,
|
||||
{question_dataset_definitions} i
|
||||
WHERE d.question = ?
|
||||
AND d.datasetdefinition = i.id
|
||||
";
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE d.question = ? AND d.datasetdefinition = i.id";
|
||||
if ($records = $DB->get_records_sql($sql, array($questionid))) {
|
||||
foreach ($records as $r) {
|
||||
$datasetdefs["$r->type-$r->category-$r->name"] = $r;
|
||||
|
@ -1573,6 +1568,9 @@ class question_calculated_qtype extends default_questiontype {
|
|||
global $DB;
|
||||
// save synchronize
|
||||
|
||||
if (empty($form->dataset)) {
|
||||
$form->dataset = array();
|
||||
}
|
||||
// Save datasets
|
||||
$datasetdefinitions = $this->get_dataset_definitions($form->id, $form->dataset);
|
||||
$tmpdatasets = array_flip($form->dataset);
|
||||
|
@ -1601,7 +1599,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
// By first creating the datasetdefinition above we
|
||||
// can manage to automatically take care of
|
||||
// some possible realtime concurrence
|
||||
if ($olderdatasetdefs = $DB->get_records_select( 'question_dataset_definitions',
|
||||
if ($olderdatasetdefs = $DB->get_records_select('question_dataset_definitions',
|
||||
"type = ?
|
||||
AND name = ?
|
||||
AND category = ?
|
||||
|
@ -1737,7 +1735,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
}
|
||||
}
|
||||
|
||||
/// Dataset functionality
|
||||
/// Dataset functionality
|
||||
function pick_question_dataset($question, $datasetitem) {
|
||||
// Select a dataset in the following format:
|
||||
// An array indexed by the variable names (d.name) pointing to the value
|
||||
|
@ -1745,13 +1743,9 @@ class question_calculated_qtype extends default_questiontype {
|
|||
global $CFG, $DB;
|
||||
if (!$dataitems = $DB->get_records_sql(
|
||||
"SELECT i.id, d.name, i.value
|
||||
FROM {question_dataset_definitions} d,
|
||||
{question_dataset_items} i,
|
||||
{question_datasets} q
|
||||
WHERE q.question = ?
|
||||
AND q.datasetdefinition = d.id
|
||||
AND d.id = i.definition
|
||||
AND i.itemnumber = ? ORDER by i.id DESC ", array($question->id, $datasetitem))) {
|
||||
FROM {question_dataset_definitions} d, {question_dataset_items} i, {question_datasets} q
|
||||
WHERE q.question = ? AND q.datasetdefinition = d.id AND d.id = i.definition AND i.itemnumber = ?
|
||||
ORDER by i.id DESC ", array($question->id, $datasetitem))) {
|
||||
print_error('cannotgetdsfordependent', 'question', '', array($question->id, $datasetitem));
|
||||
}
|
||||
$dataset = Array();
|
||||
|
@ -1780,16 +1774,13 @@ class question_calculated_qtype extends default_questiontype {
|
|||
}else {
|
||||
|
||||
// Construct question local options
|
||||
if ( ! $currentdatasetdef = $DB->get_record_sql(
|
||||
"SELECT a.*
|
||||
FROM {question_dataset_definitions} a,
|
||||
{question_datasets} b
|
||||
WHERE a.id = b.datasetdefinition
|
||||
AND a.type = '1'
|
||||
AND b.question = ?
|
||||
AND a.name = ?", array($form->id, $name))){
|
||||
$sql = "SELECT a.*
|
||||
FROM {question_dataset_definitions} a, {question_datasets} b
|
||||
WHERE a.id = b.datasetdefinition AND a.type = '1' AND b.question = ? AND a.name = ?";
|
||||
$currentdatasetdef = $DB->get_record_sql($sql, array($form->id, $name));
|
||||
if (!$currentdatasetdef) {
|
||||
$currentdatasetdef->type = '0';
|
||||
};
|
||||
}
|
||||
$key = "$type-0-$name";
|
||||
if ($currentdatasetdef->type == $type
|
||||
and $currentdatasetdef->category == 0) {
|
||||
|
@ -1846,10 +1837,8 @@ class question_calculated_qtype extends default_questiontype {
|
|||
$lnamemax = 30;
|
||||
if (!empty($form->category)) {
|
||||
$sql = "SELECT i.*,d.*
|
||||
FROM {question_datasets} d,
|
||||
{question_dataset_definitions} i
|
||||
WHERE i.id = d.datasetdefinition
|
||||
AND i.category = ?";
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE i.id = d.datasetdefinition AND i.category = ?";
|
||||
if ($records = $DB->get_records_sql($sql, array($form->category))) {
|
||||
foreach ($records as $r) {
|
||||
if ( !isset ($datasetdefs["$r->name"])) $datasetdefs["$r->name"] = $r->itemcount;
|
||||
|
@ -1866,7 +1855,6 @@ class question_calculated_qtype extends default_questiontype {
|
|||
* This table is intended to be add before the question text to help the user use
|
||||
* these wild cards
|
||||
*/
|
||||
|
||||
function print_dataset_definitions_category($form) {
|
||||
global $CFG, $DB;
|
||||
$datasetdefs = array();
|
||||
|
@ -1946,10 +1934,8 @@ class question_calculated_qtype extends default_questiontype {
|
|||
if (!empty($question->category)) {
|
||||
list($category) = explode(',', $question->category);
|
||||
$sql = "SELECT i.*,d.*
|
||||
FROM {question_datasets} d,
|
||||
{question_dataset_definitions} i
|
||||
WHERE i.id = d.datasetdefinition
|
||||
AND i.category = ?";
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE i.id = d.datasetdefinition AND i.category = ?";
|
||||
if ($records = $DB->get_records_sql($sql, array($category))) {
|
||||
foreach ($records as $r) {
|
||||
$sql1 = "SELECT q.*
|
||||
|
@ -2038,7 +2024,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
if (empty($regs1[1])) {
|
||||
$str = '';
|
||||
} else {
|
||||
*/
|
||||
*/
|
||||
while (preg_match('~\{=([^[:space:]}]*)}~', $text, $regs)) {
|
||||
$equations[] = $regs[1];
|
||||
$text = str_replace($regs[0], '', $text);
|
||||
|
@ -2053,7 +2039,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
}
|
||||
|
||||
|
||||
/// BACKUP FUNCTIONS ////////////////////////////
|
||||
/// BACKUP FUNCTIONS ////////////////////////////
|
||||
|
||||
/*
|
||||
* Backup the data in the question
|
||||
|
@ -2105,7 +2091,7 @@ class question_calculated_qtype extends default_questiontype {
|
|||
return $status;
|
||||
}
|
||||
|
||||
/// RESTORE FUNCTIONS /////////////////
|
||||
/// RESTORE FUNCTIONS /////////////////
|
||||
|
||||
/*
|
||||
* Restores the data in the question
|
||||
|
@ -2254,6 +2240,78 @@ class question_calculated_qtype extends default_questiontype {
|
|||
|
||||
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 = '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') {
|
||||
|
||||
// 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 if (in_array($filearea, array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'))) {
|
||||
// TODO: calculated type doesn't display question feedback yet
|
||||
return false;
|
||||
} else {
|
||||
return parent::check_file_access($question, $state, $options, $contextid, $component,
|
||||
$filearea, $args);
|
||||
}
|
||||
}
|
||||
}
|
||||
//// END OF CLASS ////
|
||||
|
||||
|
@ -2268,10 +2326,10 @@ if ( ! defined ("CALCULATEDQUESTIONMAXITEMNUMBER")) {
|
|||
|
||||
function qtype_calculated_calculate_answer($formula, $individualdata,
|
||||
$tolerance, $tolerancetype, $answerlength, $answerformat='1', $unit='') {
|
||||
/// The return value has these properties:
|
||||
/// ->answer the correct answer
|
||||
/// ->min the lower bound for an acceptable response
|
||||
/// ->max the upper bound for an accetpable response
|
||||
/// The return value has these properties:
|
||||
/// ->answer the correct answer
|
||||
/// ->min the lower bound for an acceptable response
|
||||
/// ->max the upper bound for an accetpable response
|
||||
|
||||
/// Exchange formula variables with the correct values...
|
||||
global $QTYPES;
|
||||
|
@ -2365,9 +2423,9 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
|
|||
|
||||
|
||||
function qtype_calculated_find_formula_errors($formula) {
|
||||
/// Validates the formula submitted from the question edit page.
|
||||
/// Returns false if everything is alright.
|
||||
/// Otherwise it constructs an error message
|
||||
/// Validates the formula submitted from the question edit page.
|
||||
/// Returns false if everything is alright.
|
||||
/// Otherwise it constructs an error message
|
||||
// Strip away dataset names
|
||||
while (preg_match('~\\{[[:alpha:]][^>} <{"\']*\\}~', $formula, $regs)) {
|
||||
$formula = str_replace($regs[0], '1', $formula);
|
||||
|
@ -2381,7 +2439,6 @@ function qtype_calculated_find_formula_errors($formula) {
|
|||
|
||||
while ( preg_match("~(^|[$safeoperatorchar,(])([a-z0-9_]*)\\(($operatorornumber+(,$operatorornumber+((,$operatorornumber+)+)?)?)?\\)~",
|
||||
$formula, $regs)) {
|
||||
|
||||
switch ($regs[2]) {
|
||||
// Simple parenthesis
|
||||
case '':
|
||||
|
@ -2452,13 +2509,4 @@ function qtype_calculated_find_formula_errors($formula) {
|
|||
// Formula just might be valid
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function dump($obj) {
|
||||
echo "<pre>\n";
|
||||
var_dump($obj);
|
||||
echo "</pre><br />\n";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
@ -52,8 +52,7 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
// 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';
|
||||
|
@ -110,13 +109,13 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
$mform->setType('multichoice', PARAM_INT);
|
||||
|
||||
|
||||
// $mform->addElement('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated'));
|
||||
// $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->setHelpButton('shuffleanswers', array('multichoiceshuffle', get_string('shuffleanswers','qtype_multichoice'), 'qtype_multichoice'));
|
||||
$mform->setDefault('shuffleanswers', 1);
|
||||
|
||||
$numberingoptions = $QTYPES['multichoice']->get_numbering_styles();
|
||||
|
@ -154,8 +153,7 @@ class question_edit_calculatedmulti_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'), null, $this->editoroptions);
|
||||
$mform->setType($feedbackname, PARAM_RAW);
|
||||
}
|
||||
//hidden elements
|
||||
|
@ -168,24 +166,27 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
}
|
||||
$mform->addElement('hidden', 'wizard', 'datasetdefinitions');
|
||||
$mform->setType('wizard', PARAM_ALPHA);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
@ -216,17 +217,38 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
$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['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
|
||||
|
||||
// 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;
|
||||
|
@ -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() {
|
||||
|
@ -254,15 +275,14 @@ 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>";
|
||||
|
||||
$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);
|
||||
}
|
||||
|
@ -282,7 +302,7 @@ 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);
|
||||
|
@ -366,7 +386,6 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if ($answercount==0){
|
||||
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
|
||||
}
|
||||
|
@ -378,4 +397,3 @@ class question_edit_calculatedmulti_form extends question_edit_form {
|
|||
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,9 +41,8 @@ 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;
|
||||
}
|
||||
|
@ -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,7 +84,8 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
}
|
||||
|
||||
// Save the units.
|
||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||
$virtualqtype = $this->get_virtual_qtype($question);
|
||||
// TODO: What is this?
|
||||
// $result = $virtualqtype->save_numerical_units($question);
|
||||
if (isset($result->error)) {
|
||||
return $result;
|
||||
|
@ -80,7 +94,7 @@ 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) != '' ) {
|
||||
|
@ -88,13 +102,17 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
$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
|
||||
|
@ -148,24 +166,19 @@ 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(
|
||||
$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))) {
|
||||
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
|
||||
";
|
||||
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 {
|
||||
} else {
|
||||
// i.e records is true so test coherence
|
||||
$coherence = true ;
|
||||
$a = new stdClass ;
|
||||
|
@ -219,7 +232,6 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
$state->responses = array();
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function save_session_and_responses(&$question, &$state) {
|
||||
|
@ -251,10 +263,6 @@ 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);
|
||||
|
@ -265,7 +273,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
|
||||
|
||||
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
|
||||
$qtext =$qtext.$qtextsplits[0];
|
||||
$qtext = $qtext.$qtextsplits[0];
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
if (empty($regs1[1])) {
|
||||
$str = '';
|
||||
|
@ -287,7 +295,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
}
|
||||
}
|
||||
|
||||
function get_default_numerical_unit($question,$virtualqtype){
|
||||
function get_default_numerical_unit($question, $virtualqtype){
|
||||
$unit = '';
|
||||
return $unit ;
|
||||
}
|
||||
|
@ -300,7 +308,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
$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);
|
||||
return $virtualqtype->grade_responses($question, $state, $cmoptions) ;
|
||||
}
|
||||
|
@ -396,8 +404,8 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
}
|
||||
$qtext = $qtext.$str ;
|
||||
}
|
||||
$answer->answer = $qtext.$qtextremaining ; ;
|
||||
$comment->stranswers[$key]= $answer->answer ;
|
||||
$answer->answer = $qtext.$qtextremaining;
|
||||
$comment->stranswers[$key] = $answer->answer;
|
||||
|
||||
|
||||
/* $formula = $this->substitute_variables($answer->answer,$data);
|
||||
|
@ -437,10 +445,6 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
return fullclone($comment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function get_correct_responses1(&$question, &$state) {
|
||||
$virtualqtype = $this->get_virtual_qtype( $question);
|
||||
/* if ($question->options->multichoice != 1 ) {
|
||||
|
@ -528,7 +532,84 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
|
|||
|
||||
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,16 +70,16 @@ 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);
|
||||
|
@ -297,8 +307,8 @@ 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}'),
|
||||
|
@ -398,9 +408,12 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$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 (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 ;
|
||||
}
|
||||
|
@ -470,7 +483,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$mform->registerNoSubmitButton('updatedatasets');
|
||||
$mform->setAdvanced("updatedatasets",true);
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
$j = $this->noofitems * count($this->datasetdefs);
|
||||
$k = 1 ;
|
||||
if ("" != optional_param('selectshow')){
|
||||
|
@ -520,7 +533,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
//non standard name for button element needed so not using add_action_buttons
|
||||
//hidden elements
|
||||
|
||||
|
@ -546,9 +559,8 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
}
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
function data_preprocessing($question) {
|
||||
global $QTYPES;
|
||||
|
||||
$answer = $this->answer;
|
||||
$default_values = array();
|
||||
if (count($answer)) {
|
||||
|
@ -560,11 +572,26 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
$default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
|
||||
$default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
|
||||
$default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
|
||||
|
||||
// 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);
|
||||
$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 ;
|
||||
|
@ -647,7 +674,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
|
|||
}*/
|
||||
$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;
|
||||
|
@ -57,13 +68,17 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
$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,10 +114,9 @@ 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 ;
|
||||
|
@ -164,6 +178,7 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
}
|
||||
$i++;
|
||||
}
|
||||
$maxnumber = -1;
|
||||
if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber){
|
||||
$maxnumber = $addeditem->itemnumber;
|
||||
foreach ($datasetdefs as $key => $newdef) {
|
||||
|
@ -194,9 +209,6 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
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
|
||||
|
@ -221,8 +233,6 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
return $question;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function custom_generator_tools_part(&$mform, $idx, $j){
|
||||
|
||||
$minmaxgrp = array();
|
||||
|
@ -291,7 +301,7 @@ 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.
|
||||
*/
|
||||
|
@ -338,6 +348,76 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
|
|||
|
||||
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,6 +66,8 @@ class question_essay_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);
|
||||
|
||||
$answers = &$question->options->answers;
|
||||
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
|
||||
|
||||
|
@ -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"/>
|
||||
|
|
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->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">
|
||||
|
|
|
@ -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 ;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -181,11 +175,9 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
}
|
||||
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));
|
||||
}
|
||||
if($this->qtype_change )
|
||||
{
|
||||
if($this->qtype_change ) {
|
||||
$mform->addElement('static', 'alert1', "<strong>".get_string('questiontypechanged','qtype_multianswer')."</strong>",get_string('questiontypechangedcomment','qtype_multianswer'));
|
||||
}
|
||||
echo '</div>';
|
||||
|
@ -359,12 +351,9 @@ 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) ;
|
||||
if (count($subquestions)) {
|
||||
$sub =1;
|
||||
|
@ -422,4 +411,3 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
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"/>
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
@ -104,9 +110,15 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
}
|
||||
$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 {
|
||||
|
@ -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,
|
||||
$questiontext = format_text($question->questiontext, $question->questiontextformat,
|
||||
$formatoptions, $cmoptions->course);
|
||||
$image = get_question_image($question);
|
||||
$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");
|
||||
|
@ -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
|
||||
|
@ -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"/>
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
@ -42,27 +58,33 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
$QTYPES['numerical']->add_units_elements($mform,$this);
|
||||
}
|
||||
|
||||
function set_data($question) {
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -404,18 +441,21 @@ 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
|
||||
|
@ -426,8 +466,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
// 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.
|
||||
$nameunit = "name=\"".$question->name_prefix."unit\"";
|
||||
$nameanswer = "name=\"".$question->name_prefix."answer\"";
|
||||
$nameunit = "name=\"".$question->name_prefix."unit\"";
|
||||
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'] );
|
||||
}
|
||||
|
@ -471,6 +511,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
$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 ;
|
||||
|
@ -511,16 +552,18 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}else if($response !== false && ($answer->min <= $response && $response <= $answer->max) ) {
|
||||
} 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 ;
|
||||
|
@ -540,7 +583,6 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
$state->options->raw_unitpenalty = $raw_unitpenalty ;
|
||||
}
|
||||
|
||||
|
||||
/// Removed correct answer, to be displayed later MDL-7496
|
||||
include("$CFG->dirroot/question/type/numerical/display.html");
|
||||
}
|
||||
|
@ -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');
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1006,11 +1049,13 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
|
||||
/**
|
||||
* function used in in function setdata ()
|
||||
* of edit_..._form.php for
|
||||
* function used in in function data_preprocessing() of edit_numerical_form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
*/
|
||||
function set_numerical_unit_data(&$question,&$default_values){
|
||||
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 ;
|
||||
|
@ -1028,9 +1073,24 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
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,7 +1102,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* function use in in function validation()
|
||||
* of edit_..._form.php for
|
||||
* numerical, calculated, calculatedsimple
|
||||
|
@ -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,7 +31,7 @@ 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");
|
||||
}
|
||||
|
@ -41,7 +39,7 @@ class question_edit_randomsamatch_form extends question_edit_form {
|
|||
if (empty($question->questiontext)) {
|
||||
$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;
|
||||
$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;
|
||||
|
@ -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') ?>:
|
||||
|
|
|
@ -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