diff --git a/lib/db/install.xml b/lib/db/install.xml
index 04d4fb9024b..a3a969749d1 100644
--- a/lib/db/install.xml
+++ b/lib/db/install.xml
@@ -1,5 +1,5 @@
- '.quiz_feedback_for_grade($mygrade, $quiz->id)." '.quiz_feedback_for_grade($mygrade, $quiz, $context, $cm)." '.get_string('modulename', 'quiz') . ': ';
p(format_string($quiz->name));
@@ -219,7 +219,7 @@
}
$number = 1;
echo ' question ".optional_param('multichoice', '', PARAM_RAW)." optional
+
";
}else{
- $text .=get_string('nosharedwildcard', 'qtype_calculated');
+ $text .=get_string('nosharedwildcard', 'qtype_calculated');
}
return $text ;
}
/**
- * This function build a table showing the available category shareable
- * wild cards, their name, their definition (Min, Max, Decimal) , the item count
- * and the name of the question where they are used.
- * This table is intended to be add before the question text to help the user use
- * these wild cards
- */
+ * This function build a table showing the available category shareable
+ * wild cards, their name, their definition (Min, Max, Decimal) , the item count
+ * and the name of the question where they are used.
+ * This table is intended to be add before the question text to help the user use
+ * these wild cards
+ */
function print_dataset_definitions_category_shared($question,$datasetdefsq) {
global $CFG, $DB;
@@ -1942,19 +1930,17 @@ class question_calculated_qtype extends default_questiontype {
$rangeofvaluestr=get_string('minmax','qtype_calculated');
$questionusingstr = get_string('usedinquestion','qtype_calculated');
$itemscountstr = get_string('itemscount','qtype_calculated');
- $text ='';
+ $text ='';
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.*
- FROM {question} q
- WHERE q.id = ?";
+ FROM {question} q
+ WHERE q.id = ?";
if ( !isset ($datasetdefs["$r->type-$r->category-$r->name"])){
$datasetdefs["$r->type-$r->category-$r->name"]= $r;
}
@@ -1982,7 +1968,7 @@ class question_calculated_qtype extends default_questiontype {
//limit the name length displayed
if (!empty($qu->name)) {
$qu->name = (strlen($qu->name) > $lnamemax) ?
- substr($qu->name, 0, $lnamemax).'...' : $qu->name;
+ substr($qu->name, 0, $lnamemax).'...' : $qu->name;
} else {
$qu->name = '';
}
@@ -1991,42 +1977,42 @@ class question_calculated_qtype extends default_questiontype {
}
$line++;
$text .="
-
\ No newline at end of file
+
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 0881eeaf8d8..a7b8d79b839 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -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 .= ' ';
+ // 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 .= '
';
+ // 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;
}
diff --git a/lib/questionlib.php b/lib/questionlib.php
index fbecc814fc8..c05efd2f44a 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -851,18 +851,31 @@ function question_delete_activity($cm, $feedback=true) {
*
* @global object
* @param string $questionids a comma-separated list of question ids.
- * @param integer $newcategory the id of the category to move to.
+ * @param integer $newcategoryid the id of the category to move to.
*/
-function question_move_questions_to_category($questionids, $newcategory) {
- global $DB;
-
+function question_move_questions_to_category($questionids, $newcategoryid) {
+ global $DB, $QTYPES;
$result = true;
+ $ids = explode(',', $questionids);
+ foreach ($ids as $questionid) {
+ $questionid = (int)$questionid;
+ $params = array();
+ $params[] = $questionid;
+ $sql = 'SELECT q.*, c.id AS contextid, c.contextlevel, c.instanceid, c.path, c.depth
+ FROM {question} q, {question_categories} qc, {context} c
+ WHERE q.category=qc.id AND q.id=? AND qc.contextid=c.id';
+ $question = $DB->get_record_sql($sql, $params);
+ $category = $DB->get_record('question_categories', array('id'=>$newcategoryid));
+ // process files
+ $QTYPES[$question->qtype]->move_files($question, $category);
+ }
+
// Move the questions themselves.
- $result = $result && $DB->set_field_select('question', 'category', $newcategory, "id IN ($questionids)");
+ $result = $result && $DB->set_field_select('question', 'category', $newcategoryid, "id IN ($questionids)");
// Move any subquestions belonging to them.
- $result = $result && $DB->set_field_select('question', 'category', $newcategory, "parent IN ($questionids)");
+ $result = $result && $DB->set_field_select('question', 'category', $newcategoryid, "parent IN ($questionids)");
// TODO Deal with datasets.
@@ -1080,6 +1093,7 @@ function question_load_states(&$questions, &$states, $cmoptions, $attempt, $last
$states[$qid]->last_graded = clone($states[$qid]);
}
} else {
+
if ($lastattemptid) {
// If the new attempt is to be based on this previous attempt.
// Find the responses from the previous attempt and save them to the new session
@@ -2091,7 +2105,7 @@ function question_init_qengine_js() {
$module = array(
'name' => 'core_question_flags',
'fullpath' => '/question/flags.js',
- 'requires' => array('base', 'dom', 'event-delegate', 'io-base'),
+ 'requires' => array('base', 'dom', 'event-delegate', 'io-base'),
);
$actionurl = $CFG->wwwroot . '/question/toggleflag.php';
$flagattributes = array(
@@ -2162,9 +2176,9 @@ function question_get_editing_head_contributions($question) {
* @param object $cmoptions The options specified by the course module
* @param object $options An object specifying the rendering options.
*/
-function print_question(&$question, &$state, $number, $cmoptions, $options=null) {
+function print_question(&$question, &$state, $number, $cmoptions, $options=null, $context=null) {
global $QTYPES;
- $QTYPES[$question->qtype]->print_question($question, $state, $number, $cmoptions, $options);
+ $QTYPES[$question->qtype]->print_question($question, $state, $number, $cmoptions, $options, $context);
}
/**
* Saves question options
@@ -3191,4 +3205,124 @@ class question_edit_contexts {
print_error('nopermissions', '', '', 'access question edit tab '.$tabname);
}
}
-}
\ No newline at end of file
+}
+
+/**
+ * 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);
+}
diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php
index 3d4fae40596..51ce60a775a 100644
--- a/mod/quiz/attemptlib.php
+++ b/mod/quiz/attemptlib.php
@@ -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.
*/
diff --git a/mod/quiz/db/install.xml b/mod/quiz/db/install.xml
index d85a3fec5b8..2196e070142 100755
--- a/mod/quiz/db/install.xml
+++ b/mod/quiz/db/install.xml
@@ -1,5 +1,5 @@
-
';
diff --git a/mod/quiz/version.php b/mod/quiz/version.php
index 42c59baa3ac..9cc23d75bea 100644
--- a/mod/quiz/version.php
+++ b/mod/quiz/version.php
@@ -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)?
diff --git a/mod/quiz/view.php b/mod/quiz/view.php
index e5579164a5b..f402cbe9af9 100644
--- a/mod/quiz/view.php
+++ b/mod/quiz/view.php
@@ -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 .= '' . get_string('feedback', 'quiz') .
' ' . $feedback . ' $qu->name ";
- $nb_of_quiz = 0;
- $nb_of_attempts=0;
- $used_in_quiz = false ;
- if ($list = $DB->get_records('quiz_question_instances', array( 'question'=> $qu->id))){
- $used_in_quiz = true;
- foreach($list as $key => $li){
- $nb_of_quiz ++;
- if($att = $DB->get_records('quiz_attempts',array( 'quiz'=> $li->quiz, 'preview'=> '0'))){
- $nb_of_attempts+= count($att);
+ $nb_of_quiz = 0;
+ $nb_of_attempts=0;
+ $used_in_quiz = false ;
+ if ($list = $DB->get_records('quiz_question_instances', array( 'question'=> $qu->id))){
+ $used_in_quiz = true;
+ foreach($list as $key => $li){
+ $nb_of_quiz ++;
+ if($att = $DB->get_records('quiz_attempts',array( 'quiz'=> $li->quiz, 'preview'=> '0'))){
+ $nb_of_attempts+= count($att);
+ }
}
}
- }
- if($used_in_quiz){
- $text .="$nb_of_quiz ";
- }else {
- $text .="0 ";
- }
- if($used_in_quiz){
- $text .="$nb_of_attempts";
- }else {
- $text .="
";
- }
+ if($used_in_quiz){
+ $text .="$nb_of_quiz ";
+ }else {
+ $text .="0 ";
+ }
+ if($used_in_quiz){
+ $text .="$nb_of_attempts";
+ }else {
+ $text .=" ";
+ $text .="";
}
}
$text .="";
}else{
- $text .=get_string('nosharedwildcard', 'qtype_calculated');
+ $text .=get_string('nosharedwildcard', 'qtype_calculated');
}
return $text ;
}
function find_math_equations($text) {
- /// Returns the possible dataset names found in the text as an array
- /// The array has the dataset name for both key and value
+ /// Returns the possible dataset names found in the text as an array
+ /// The array has the dataset name for both key and value
$equations = array();
/* $qtext = "";
$qtextremaining = $numericalquestion->questiontext ;
@@ -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);
@@ -2048,12 +2034,12 @@ class question_calculated_qtype extends default_questiontype {
function get_virtual_qtype() {
global $QTYPES;
- $this->virtualqtype =& $QTYPES['numerical'];
+ $this->virtualqtype =& $QTYPES['numerical'];
return $this->virtualqtype;
}
-/// 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
@@ -2154,43 +2140,43 @@ class question_calculated_qtype extends default_questiontype {
}
backup_flush(300);
}
- //Get the calculated_options array
- // need to check as old questions don't have calculated_options record
- if(isset($info['#']['CALCULATED_OPTIONS'])){
- $calculatedoptions = $info['#']['CALCULATED_OPTIONS'];
+ //Get the calculated_options array
+ // need to check as old questions don't have calculated_options record
+ if(isset($info['#']['CALCULATED_OPTIONS'])){
+ $calculatedoptions = $info['#']['CALCULATED_OPTIONS'];
- //Iterate over calculated_options
- for($i = 0; $i < sizeof($calculatedoptions); $i++){
- $cal_info = $calculatedoptions[$i];
- //traverse_xmlize($cal_info); //Debug
- //print_object ($GLOBALS['traverse_array']); //Debug
- //$GLOBALS['traverse_array']=""; //Debug
+ //Iterate over calculated_options
+ for($i = 0; $i < sizeof($calculatedoptions); $i++){
+ $cal_info = $calculatedoptions[$i];
+ //traverse_xmlize($cal_info); //Debug
+ //print_object ($GLOBALS['traverse_array']); //Debug
+ //$GLOBALS['traverse_array']=""; //Debug
- //Now, build the question_calculated_options record structure
- $calculated_options->questionid = $new_question_id;
- $calculated_options->synchronize = backup_todb($cal_info['#']['SYNCHRONIZE']['0']['#']);
- $calculated_options->single = backup_todb($cal_info['#']['SINGLE']['0']['#']);
- $calculated_options->shuffleanswers = isset($cal_info['#']['SHUFFLEANSWERS']['0']['#'])?backup_todb($mul_info['#']['SHUFFLEANSWERS']['0']['#']):'';
- $calculated_options->correctfeedback = backup_todb($cal_info['#']['CORRECTFEEDBACK']['0']['#']);
- $calculated_options->partiallycorrectfeedback = backup_todb($cal_info['#']['PARTIALLYCORRECTFEEDBACK']['0']['#']);
- $calculated_options->incorrectfeedback = backup_todb($cal_info['#']['INCORRECTFEEDBACK']['0']['#']);
- $calculated_options->answernumbering = backup_todb($cal_info['#']['ANSWERNUMBERING']['0']['#']);
+ //Now, build the question_calculated_options record structure
+ $calculated_options->questionid = $new_question_id;
+ $calculated_options->synchronize = backup_todb($cal_info['#']['SYNCHRONIZE']['0']['#']);
+ $calculated_options->single = backup_todb($cal_info['#']['SINGLE']['0']['#']);
+ $calculated_options->shuffleanswers = isset($cal_info['#']['SHUFFLEANSWERS']['0']['#'])?backup_todb($mul_info['#']['SHUFFLEANSWERS']['0']['#']):'';
+ $calculated_options->correctfeedback = backup_todb($cal_info['#']['CORRECTFEEDBACK']['0']['#']);
+ $calculated_options->partiallycorrectfeedback = backup_todb($cal_info['#']['PARTIALLYCORRECTFEEDBACK']['0']['#']);
+ $calculated_options->incorrectfeedback = backup_todb($cal_info['#']['INCORRECTFEEDBACK']['0']['#']);
+ $calculated_options->answernumbering = backup_todb($cal_info['#']['ANSWERNUMBERING']['0']['#']);
- //The structure is equal to the db, so insert the question_calculated_options
- $newid = $DB->insert_record ("question_calculated_options",$calculated_options);
+ //The structure is equal to the db, so insert the question_calculated_options
+ $newid = $DB->insert_record ("question_calculated_options",$calculated_options);
- //Do some output
- if (($i+1) % 50 == 0) {
- if (!defined('RESTORE_SILENTLY')) {
- echo ".";
- if (($i+1) % 1000 == 0) {
- echo "
";
+ }
- $text .="
";
+ //Do some output
+ if (($i+1) % 50 == 0) {
+ if (!defined('RESTORE_SILENTLY')) {
+ echo ".";
+ if (($i+1) % 1000 == 0) {
+ echo "
";
+ }
}
+ backup_flush(300);
}
- backup_flush(300);
}
}
- }
//Now restore numerical_units
$status = question_restore_numerical_units ($old_question_id,$new_question_id,$cal_info,$restore);
$status = question_restore_numerical_options($old_question_id,$new_question_id,$info,$restore);
@@ -2207,53 +2193,125 @@ class question_calculated_qtype extends default_questiontype {
return $status;
}
- /**
- * Runs all the code required to set up and save an essay question for testing purposes.
- * Alternate DB table prefix may be used to facilitate data deletion.
- */
- function generate_test($name, $courseid = null) {
- global $DB;
- list($form, $question) = parent::generate_test($name, $courseid);
- $form->feedback = 1;
- $form->multiplier = array(1, 1);
- $form->shuffleanswers = 1;
- $form->noanswers = 1;
- $form->qtype ='calculated';
- $question->qtype ='calculated';
- $form->answers = array('{a} + {b}');
- $form->fraction = array(1);
- $form->tolerance = array(0.01);
- $form->tolerancetype = array(1);
- $form->correctanswerlength = array(2);
- $form->correctanswerformat = array(1);
- $form->questiontext = "What is {a} + {b}?";
+ /**
+ * Runs all the code required to set up and save an essay question for testing purposes.
+ * Alternate DB table prefix may be used to facilitate data deletion.
+ */
+ function generate_test($name, $courseid = null) {
+ global $DB;
+ list($form, $question) = parent::generate_test($name, $courseid);
+ $form->feedback = 1;
+ $form->multiplier = array(1, 1);
+ $form->shuffleanswers = 1;
+ $form->noanswers = 1;
+ $form->qtype ='calculated';
+ $question->qtype ='calculated';
+ $form->answers = array('{a} + {b}');
+ $form->fraction = array(1);
+ $form->tolerance = array(0.01);
+ $form->tolerancetype = array(1);
+ $form->correctanswerlength = array(2);
+ $form->correctanswerformat = array(1);
+ $form->questiontext = "What is {a} + {b}?";
- if ($courseid) {
- $course = $DB->get_record('course', array('id'=> $courseid));
- }
+ if ($courseid) {
+ $course = $DB->get_record('course', array('id'=> $courseid));
+ }
- $new_question = $this->save_question($question, $form, $course);
+ $new_question = $this->save_question($question, $form, $course);
- $dataset_form = new stdClass();
- $dataset_form->nextpageparam["forceregeneration"]= 1;
- $dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
- $dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
- $dataset_form->calclength = array(1 => 1, 2 => 1);
- $dataset_form->number = array(1 => 5.4 , 2 => 4.9);
- $dataset_form->itemid = array(1 => '' , 2 => '');
- $dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
- $dataset_form->definition = array(1 => "1-0-a",
- 2 => "1-0-b");
- $dataset_form->nextpageparam = array('forceregeneration' => false);
- $dataset_form->addbutton = 1;
- $dataset_form->selectadd = 1;
- $dataset_form->courseid = $courseid;
- $dataset_form->cmid = 0;
- $dataset_form->id = $new_question->id;
- $this->save_dataset_items($new_question, $dataset_form);
+ $dataset_form = new stdClass();
+ $dataset_form->nextpageparam["forceregeneration"]= 1;
+ $dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
+ $dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
+ $dataset_form->calclength = array(1 => 1, 2 => 1);
+ $dataset_form->number = array(1 => 5.4 , 2 => 4.9);
+ $dataset_form->itemid = array(1 => '' , 2 => '');
+ $dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
+ $dataset_form->definition = array(1 => "1-0-a",
+ 2 => "1-0-b");
+ $dataset_form->nextpageparam = array('forceregeneration' => false);
+ $dataset_form->addbutton = 1;
+ $dataset_form->selectadd = 1;
+ $dataset_form->courseid = $courseid;
+ $dataset_form->cmid = 0;
+ $dataset_form->id = $new_question->id;
+ $this->save_dataset_items($new_question, $dataset_form);
- return $new_question;
- }
+ return $new_question;
+ }
+
+ /**
+ * When move the category of questions, the belonging files should be moved as well
+ * @param object $question, question information
+ * @param object $newcategory, target category information
+ */
+ function move_files($question, $newcategory) {
+ global $DB;
+ parent::move_files($question, $newcategory);
+
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+ $component = 'question';
+ $filearea = '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 ////
@@ -2267,11 +2325,11 @@ 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
+ $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
/// Exchange formula variables with the correct values...
global $QTYPES;
@@ -2290,12 +2348,12 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
if (preg_match('~^(.*\\.)(.*)$~', $calculated->answer, $regs)) {
$calculated->answer = $regs[1] . substr(
- $regs[2] . '00000000000000000000000000000000000000000x',
- 0, $answerlength)
- . $unit;
+ $regs[2] . '00000000000000000000000000000000000000000x',
+ 0, $answerlength)
+ . $unit;
} else {
$calculated->answer .=
- substr('.00000000000000000000000000000000000000000x',
+ substr('.00000000000000000000000000000000000000000x',
0, $answerlength + 1) . $unit;
}
} else {
@@ -2337,9 +2395,9 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
} else {
// Attach additional zeros at the end of $answer,
$answer .= (1==strlen($answer) ? '.' : '')
- . '00000000000000000000000000000000000000000x';
+ . '00000000000000000000000000000000000000000x';
$calculated->answer = $sign
- .substr($answer, 0, $answerlength +1).$eX.$unit;
+ .substr($answer, 0, $answerlength +1).$eX.$unit;
}
} else {
// Stick to plain numeric format
@@ -2349,7 +2407,7 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
} else {
// Could be an idea to add some zeros here
$answer .= (preg_match('~^[0-9]*$~', $answer) ? '.' : '')
- . '00000000000000000000000000000000000000000x';
+ . '00000000000000000000000000000000000000000x';
$oklen = $answerlength + ($p10 < 1 ? 2-$p10 : 1);
$calculated->answer = $sign.substr($answer, 0, $oklen).$unit;
}
@@ -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);
@@ -2380,59 +2438,58 @@ function qtype_calculated_find_formula_errors($formula) {
$operatorornumber = "[$safeoperatorchar.0-9eE]";
while ( preg_match("~(^|[$safeoperatorchar,(])([a-z0-9_]*)\\(($operatorornumber+(,$operatorornumber+((,$operatorornumber+)+)?)?)?\\)~",
- $formula, $regs)) {
-
+ $formula, $regs)) {
switch ($regs[2]) {
// Simple parenthesis
- case '':
- if ($regs[4] || strlen($regs[3])==0) {
- return get_string('illegalformulasyntax', 'quiz', $regs[0]);
- }
- break;
+ case '':
+ if ($regs[4] || strlen($regs[3])==0) {
+ return get_string('illegalformulasyntax', 'quiz', $regs[0]);
+ }
+ break;
// Zero argument functions
- case 'pi':
- if ($regs[3]) {
- return get_string('functiontakesnoargs', 'quiz', $regs[2]);
- }
- break;
+ case 'pi':
+ if ($regs[3]) {
+ return get_string('functiontakesnoargs', 'quiz', $regs[2]);
+ }
+ break;
// Single argument functions (the most common case)
- case 'abs': case 'acos': case 'acosh': case 'asin': case 'asinh':
- case 'atan': case 'atanh': case 'bindec': case 'ceil': case 'cos':
- case 'cosh': case 'decbin': case 'decoct': case 'deg2rad':
- case 'exp': case 'expm1': case 'floor': case 'is_finite':
- case 'is_infinite': case 'is_nan': case 'log10': case 'log1p':
- case 'octdec': case 'rad2deg': case 'sin': case 'sinh': case 'sqrt':
- case 'tan': case 'tanh':
- if (!empty($regs[4]) || empty($regs[3])) {
- return get_string('functiontakesonearg','quiz',$regs[2]);
- }
- break;
+ case 'abs': case 'acos': case 'acosh': case 'asin': case 'asinh':
+ case 'atan': case 'atanh': case 'bindec': case 'ceil': case 'cos':
+ case 'cosh': case 'decbin': case 'decoct': case 'deg2rad':
+ case 'exp': case 'expm1': case 'floor': case 'is_finite':
+ case 'is_infinite': case 'is_nan': case 'log10': case 'log1p':
+ case 'octdec': case 'rad2deg': case 'sin': case 'sinh': case 'sqrt':
+ case 'tan': case 'tanh':
+ if (!empty($regs[4]) || empty($regs[3])) {
+ return get_string('functiontakesonearg','quiz',$regs[2]);
+ }
+ break;
// Functions that take one or two arguments
- case 'log': case 'round':
- if (!empty($regs[5]) || empty($regs[3])) {
- return get_string('functiontakesoneortwoargs','quiz',$regs[2]);
- }
- break;
+ case 'log': case 'round':
+ if (!empty($regs[5]) || empty($regs[3])) {
+ return get_string('functiontakesoneortwoargs','quiz',$regs[2]);
+ }
+ break;
// Functions that must have two arguments
- case 'atan2': case 'fmod': case 'pow':
- if (!empty($regs[5]) || empty($regs[4])) {
- return get_string('functiontakestwoargs', 'quiz', $regs[2]);
- }
- break;
+ case 'atan2': case 'fmod': case 'pow':
+ if (!empty($regs[5]) || empty($regs[4])) {
+ return get_string('functiontakestwoargs', 'quiz', $regs[2]);
+ }
+ break;
// Functions that take two or more arguments
- case 'min': case 'max':
- if (empty($regs[4])) {
- return get_string('functiontakesatleasttwo','quiz',$regs[2]);
- }
- break;
+ case 'min': case 'max':
+ if (empty($regs[4])) {
+ return get_string('functiontakesatleasttwo','quiz',$regs[2]);
+ }
+ break;
- default:
- return get_string('unsupportedformulafunction','quiz',$regs[2]);
+ default:
+ return get_string('unsupportedformulafunction','quiz',$regs[2]);
}
// Exchange the function call with '1' and then chack for
@@ -2452,13 +2509,4 @@ function qtype_calculated_find_formula_errors($formula) {
// Formula just might be valid
return false;
}
-
}
-
-function dump($obj) {
- echo "\n";
- var_dump($obj);
- echo "
\n";
-}
-
-
diff --git a/question/type/calculated/version.php b/question/type/calculated/version.php
index aa56eb9470c..6b690e75cf3 100644
--- a/question/type/calculated/version.php
+++ b/question/type/calculated/version.php
@@ -1,5 +1,5 @@
version = 2010020800;
+$plugin->version = 2010020801;
$plugin->requires = 2007101000;
diff --git a/question/type/calculatedmulti/edit_calculatedmulti_form.php b/question/type/calculatedmulti/edit_calculatedmulti_form.php
index 3b81121d8cb..a2e736f21ae 100644
--- a/question/type/calculatedmulti/edit_calculatedmulti_form.php
+++ b/question/type/calculatedmulti/edit_calculatedmulti_form.php
@@ -18,11 +18,11 @@ class question_edit_calculatedmulti_form extends question_edit_form {
*
* @var question_calculatedmulti_qtype
*/
- var $qtypeobj;
+ public $qtypeobj;
public $questiondisplay ;
public $initialname = '';
public $reload = false ;
- function question_edit_calculatedmulti_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
+ function question_edit_calculatedmulti_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true) {
global $QTYPES, $SESSION, $CFG, $DB;
$this->question = $question;
$this->qtypeobj =& $QTYPES[$this->question->qtype];
@@ -38,22 +38,21 @@ class question_edit_calculatedmulti_form extends question_edit_form {
$regs= array();
if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
$question->name = str_replace($regs[0], '', $question->name);
- };
+ };
}
}else {
- }
+ }
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
}
function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
- // $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
- $repeated = array();
+ // $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
+ $repeated = array();
$repeated[] =& $mform->createElement('header', 'answerhdr', $label);
- // if ($this->editasmultichoice == 1){
+ // if ($this->editasmultichoice == 1){
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
- $repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
- array('course' => $this->coursefilesid));
+ $repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
$repeatedoptions['answer']['type'] = PARAM_RAW;
$repeatedoptions['fraction']['default'] = 0;
$answersoption = 'answers';
@@ -61,8 +60,8 @@ class question_edit_calculatedmulti_form extends question_edit_form {
$mform->setType('answer', PARAM_NOTAGS);
$addrepeated = array();
- $addrepeated[] =& $mform->createElement('hidden', 'tolerance');
- $addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
+ $addrepeated[] =& $mform->createElement('hidden', 'tolerance');
+ $addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
$repeatedoptions['tolerance']['default'] = 0.01;
@@ -72,7 +71,7 @@ class question_edit_calculatedmulti_form extends question_edit_form {
$answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
$addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
array_splice($repeated, 3, 0, $addrepeated);
- $repeated[1]->setLabel('...{={x}+..}...');
+ $repeated[1]->setLabel('...{={x}+..}...');
return $repeated;
}
@@ -85,79 +84,78 @@ class question_edit_calculatedmulti_form extends question_edit_form {
function definition_inner(&$mform) {
global $QTYPES;
$this->qtypeobj =& $QTYPES[$this->qtype()];
- // echo code left for testing period
- // echo "";print_r($this->question);echo "
question ".optional_param('multichoice', '', PARAM_RAW)." optional
";print_r($this->question);echo ""; $label = get_string("sharedwildcards", "qtype_calculated"); $mform->addElement('hidden', 'initialcategory', 1); $mform->addElement('hidden', 'reload', 1); $mform->setType('initialcategory', PARAM_INT); - // $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question); - $html2 =""; + // $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question); + $html2 =""; $mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name'); if(isset($this->question->id )){ $mform->insertElementBefore($mform->createElement('static','initialname',get_string('questionstoredname','qtype_calculated'),$this->initialname),'name'); }; $addfieldsname='updatecategory'; $addstring=get_string("updatecategory", "qtype_calculated"); - $mform->registerNoSubmitButton($addfieldsname); + $mform->registerNoSubmitButton($addfieldsname); $this->editasmultichoice = 1 ; - + $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory'); $mform->registerNoSubmitButton('createoptionbutton'); - $mform->addElement('hidden', 'multichoice',$this->editasmultichoice); - $mform->setType('multichoice', PARAM_INT); - + $mform->addElement('hidden', 'multichoice',$this->editasmultichoice); + $mform->setType('multichoice', PARAM_INT); -// $mform->addElement('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated')); - $menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice')); - $mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu); - $mform->setDefault('single', 1); - - $mform->addElement('advcheckbox', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'), null, null, array(0,1)); - $mform->addHelpButton('shuffleanswers', 'shuffleanswers', 'qtype_multichoice'); - $mform->setDefault('shuffleanswers', 1); - - $numberingoptions = $QTYPES['multichoice']->get_numbering_styles(); - $menu = array(); - foreach ($numberingoptions as $numberingoption) { - $menu[$numberingoption] = get_string('answernumbering' . $numberingoption, 'qtype_multichoice'); - } - $mform->addElement('select', 'answernumbering', get_string('answernumbering', 'qtype_multichoice'), $menu); - $mform->setDefault('answernumbering', 'abc'); + + // $mform->addElement('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated')); + $menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice')); + $mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu); + $mform->setDefault('single', 1); + + $mform->addElement('advcheckbox', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'), null, null, array(0,1)); + $mform->setHelpButton('shuffleanswers', array('multichoiceshuffle', get_string('shuffleanswers','qtype_multichoice'), 'qtype_multichoice')); + $mform->setDefault('shuffleanswers', 1); + + $numberingoptions = $QTYPES['multichoice']->get_numbering_styles(); + $menu = array(); + foreach ($numberingoptions as $numberingoption) { + $menu[$numberingoption] = get_string('answernumbering' . $numberingoption, 'qtype_multichoice'); + } + $mform->addElement('select', 'answernumbering', get_string('answernumbering', 'qtype_multichoice'), $menu); + $mform->setDefault('answernumbering', 'abc'); $creategrades = get_grade_options(); - $this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'), - $creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START)); - + $this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'), + $creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START)); + $repeated = array(); - // if ($this->editasmultichoice == 1){ - $nounits = optional_param('nounits', 1, PARAM_INT); - $mform->addElement('hidden', 'nounits', $nounits); - $mform->setType('nounits', PARAM_INT); - $mform->setConstants(array('nounits'=>$nounits)); - for ($i=0; $i< $nounits; $i++) { - $mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS)); - $mform->setType('unit'."[$i]", PARAM_NOTAGS); - $mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER)); - $mform->setType('multiplier'."[$i]", PARAM_NUMBER); - } - $mform->addElement('hidden','unitgradingtype',optional_param('unitgradingtype', '', PARAM_INT)) ; - $mform->addElement('hidden','unitpenalty',optional_param('unitpenalty', '', PARAM_NUMBER)) ; - $mform->addElement('hidden','showunits',optional_param('showunits', '', PARAM_INT)) ; - $mform->addElement('hidden','unitsleft',optional_param('unitsleft', '', PARAM_INT)) ; - $mform->addElement('hidden','instructions',optional_param('instructions', '', PARAM_RAW)) ; + // if ($this->editasmultichoice == 1){ + $nounits = optional_param('nounits', 1, PARAM_INT); + $mform->addElement('hidden', 'nounits', $nounits); + $mform->setType('nounits', PARAM_INT); + $mform->setConstants(array('nounits'=>$nounits)); + for ($i=0; $i< $nounits; $i++) { + $mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS)); + $mform->setType('unit'."[$i]", PARAM_NOTAGS); + $mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER)); + $mform->setType('multiplier'."[$i]", PARAM_NUMBER); + } + $mform->addElement('hidden','unitgradingtype',optional_param('unitgradingtype', '', PARAM_INT)) ; + $mform->addElement('hidden','unitpenalty',optional_param('unitpenalty', '', PARAM_NUMBER)) ; + $mform->addElement('hidden','showunits',optional_param('showunits', '', PARAM_INT)) ; + $mform->addElement('hidden','unitsleft',optional_param('unitsleft', '', PARAM_INT)) ; + $mform->addElement('hidden','instructions',optional_param('instructions', '', PARAM_RAW)) ; - $mform->setType('addunits','hidden'); - $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice')); + $mform->setType('addunits','hidden'); + $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice')); - foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) { - $mform->addElement('htmleditor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'), - array('course' => $this->coursefilesid)); - $mform->setType($feedbackname, PARAM_RAW); - } + foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) { + $mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'), null, $this->editoroptions); + $mform->setType($feedbackname, PARAM_RAW); + } //hidden elements $mform->addElement('hidden', 'synchronize', ''); $mform->setType('synchronize', PARAM_INT); @@ -168,40 +166,43 @@ class question_edit_calculatedmulti_form extends question_edit_form { } $mform->addElement('hidden', 'wizard', 'datasetdefinitions'); $mform->setType('wizard', PARAM_ALPHA); - - } - function set_data($question) { - $default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ; + function data_preprocessing($question) { + $default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ; if (isset($question->options)){ $answers = $question->options->answers; if (count($answers)) { $key = 0; foreach ($answers as $answer){ + $draftid = file_get_submitted_draft_itemid('feedback['.$key.']'); $default_values['answer['.$key.']'] = $answer->answer; $default_values['fraction['.$key.']'] = $answer->fraction; $default_values['tolerance['.$key.']'] = $answer->tolerance; $default_values['tolerancetype['.$key.']'] = $answer->tolerancetype; $default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength; $default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat; - $default_values['feedback['.$key.']'] = $answer->feedback; + $default_values['feedback['.$key.']'] = array(); + // prepare draftarea + $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area($draftid, $this->context->id, 'question', 'answerfeedback', empty($answer->id)?null:(int)$answer->id, null, $answer->feedback); + $default_values['feedback['.$key.']']['format'] = $answer->feedbackformat; + $default_values['feedback['.$key.']']['itemid'] = $draftid; $key++; } } - // $default_values['unitgradingtype'] = $question->options->unitgradingtype ; - // $default_values['unitpenalty'] = $question->options->unitpenalty ; - // $default_values['showunits'] = $question->options->showunits ; - // $default_values['unitsleft'] = $question->options->unitsleft ; - // $default_values['instructions'] = $question->options->instructions ; - $default_values['synchronize'] = $question->options->synchronize ; + // $default_values['unitgradingtype'] = $question->options->unitgradingtype ; + // $default_values['unitpenalty'] = $question->options->unitpenalty ; + // $default_values['showunits'] = $question->options->showunits ; + // $default_values['unitsleft'] = $question->options->unitsleft ; + // $default_values['instructions'] = $question->options->instructions ; + $default_values['synchronize'] = $question->options->synchronize ; if (isset($question->options->units)){ $units = array_values($question->options->units); // make sure the default unit is at index 0 usort($units, create_function('$a, $b', - 'if (1.0 === (float)$a->multiplier) { return -1; } else '. - 'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }')); + 'if (1.0 === (float)$a->multiplier) { return -1; } else '. + 'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }')); if (count($units)) { $key = 0; foreach ($units as $unit){ @@ -213,30 +214,51 @@ class question_edit_calculatedmulti_form extends question_edit_form { } } if (isset($question->options->single)){ - $default_values['single'] = $question->options->single; - $default_values['answernumbering'] = $question->options->answernumbering; - $default_values['shuffleanswers'] = $question->options->shuffleanswers; - $default_values['correctfeedback'] = $question->options->correctfeedback; - $default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback; - $default_values['incorrectfeedback'] = $question->options->incorrectfeedback; - } + $default_values['single'] = $question->options->single; + $default_values['answernumbering'] = $question->options->answernumbering; + $default_values['shuffleanswers'] = $question->options->shuffleanswers; + } $default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated'); $default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated'); - /* set the wild cards category display given that on loading the category element is - unselected when processing this function but have a valid value when processing the - update category button. The value can be obtain by - $qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0]; - but is coded using existing functions - */ - $qu = new stdClass; - $el = new stdClass; - /* no need to call elementExists() here */ - if ($this->_form->elementExists('category')){ + + // prepare draft files + foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) { + if (!isset($question->options->$feedbackname)) { + continue; + } + $text = $question->options->$feedbackname; + $draftid = file_get_submitted_draft_itemid($feedbackname); + $feedbackformat = $feedbackname . 'format'; + $format = $question->options->$feedbackformat; + $default_values[$feedbackname] = array(); + $default_values[$feedbackname]['text'] = file_prepare_draft_area( + $draftid, // draftid + $this->context->id, // context + 'qtype_calculatedmulti', // component + $feedbackname, // filarea + !empty($question->id)?(int)$question->id:null, // itemid + $this->fileoptions, // options + $text // text + ); + $default_values[$feedbackname]['format'] = $format; + $default_values[$feedbackname]['itemid'] = $draftid; + } + /** + * set the wild cards category display given that on loading the category element is + * unselected when processing this function but have a valid value when processing the + * update category button. The value can be obtain by + * $qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0]; + * but is coded using existing functions + */ + $qu = new stdClass; + $el = new stdClass; + /* no need to call elementExists() here */ + if ($this->_form->elementExists('category')){ $el=$this->_form->getElement('category'); - } else { + } else { $el=$this->_form->getElement('categorymoveto'); - } - if($value =$el->getSelected()) { + } + if($value =$el->getSelected()) { $qu->category =$value[0]; }else { $qu->category=$question->category;// on load $question->category is set by question.php @@ -244,8 +266,7 @@ class question_edit_calculatedmulti_form extends question_edit_form { $html2 = $this->qtypeobj->print_dataset_definitions_category($qu); $this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ; $question = (object)((array)$question + $default_values); - - parent::set_data($question); + return $question; } function qtype() { @@ -253,21 +274,20 @@ class question_edit_calculatedmulti_form extends question_edit_form { } function validation($data, $files) { - // echo code left for testing period - - // echo "
question
";print_r($this->question);echo ""; - // echo "
data
";print_r($data);echo ""; + // echo code left for testing period + // echo "
question
";print_r($this->question);echo ""; + // echo "
data
";print_r($data);echo ""; $errors = parent::validation($data, $files); //verifying for errors in {=...} in question text; $qtext = ""; - $qtextremaining = $data['questiontext'] ; - $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']); - foreach ($possibledatasets as $name => $value) { + $qtextremaining = $data['questiontext']['text']; + $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']); + foreach ($possibledatasets as $name => $value) { $qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining); } - // echo "numericalquestion qtextremaining
";print_r($possibledatasets);
- while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
+ // echo "numericalquestion qtextremaining ";print_r($possibledatasets);
+ while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
$qtextsplits = explode($regs1[0], $qtextremaining, 2);
$qtext =$qtext.$qtextsplits[0];
$qtextremaining = $qtextsplits[1];
@@ -282,13 +302,13 @@ class question_edit_calculatedmulti_form extends question_edit_form {
$answers = $data['answer'];
$answercount = 0;
$maxgrade = false;
- $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
+ $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
$mandatorydatasets = array();
foreach ($answers as $key => $answer){
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
}
if ( count($mandatorydatasets )==0){
- // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
+ // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
foreach ($answers as $key => $answer){
$errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
}
@@ -296,15 +316,15 @@ class question_edit_calculatedmulti_form extends question_edit_form {
if ($data['multichoice']== 1 ){
foreach ($answers as $key => $answer){
$trimmedanswer = trim($answer);
- if (($trimmedanswer!='')||$answercount==0){
+ if (($trimmedanswer!='')||$answercount==0){
//verifying for errors in {=...} in answer text;
$qanswer = "";
$qanswerremaining = $trimmedanswer ;
$possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer);
- foreach ($possibledatasets as $name => $value) {
+ foreach ($possibledatasets as $name => $value) {
$qanswerremaining = str_replace('{'.$name.'}', '1', $qanswerremaining);
}
- // echo "numericalquestion qanswerremaining ";print_r($possibledatasets);
+ // echo "numericalquestion qanswerremaining ";print_r($possibledatasets);
while (preg_match('~\{=([^[:space:]}]*)}~', $qanswerremaining, $regs1)) {
$qanswersplits = explode($regs1[0], $qanswerremaining, 2);
$qanswer =$qanswer.$qanswersplits[0];
@@ -320,16 +340,16 @@ class question_edit_calculatedmulti_form extends question_edit_form {
}
if ($trimmedanswer!=''){
if ('2' == $data['correctanswerformat'][$key]
- && '0' == $data['correctanswerlength'][$key]) {
- $errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
- }
+ && '0' == $data['correctanswerlength'][$key]) {
+ $errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
+ }
if (!is_numeric($data['tolerance'][$key])){
$errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
}
if ($data['fraction'][$key] == 1) {
- $maxgrade = true;
+ $maxgrade = true;
}
-
+
$answercount++;
}
//check grades
@@ -342,14 +362,14 @@ class question_edit_calculatedmulti_form extends question_edit_form {
if ($data['fraction'][$key] > $maxfraction) {
$maxfraction = $data['fraction'][$key];
}
- }
+ }
}
if ($answercount==0){
$errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
} elseif ($answercount==1){
$errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
-
+
}
/// Perform sanity checks on fractional grades
@@ -365,17 +385,15 @@ class question_edit_calculatedmulti_form extends question_edit_form {
$errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
}
}
-
-
+
if ($answercount==0){
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
}
if ($maxgrade == false) {
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
}
-
+
}
return $errors;
}
}
-
diff --git a/question/type/calculatedmulti/lib.php b/question/type/calculatedmulti/lib.php
new file mode 100644
index 00000000000..220f828fa01
--- /dev/null
+++ b/question/type/calculatedmulti/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * Serve question type files
+ *
+ * @since 2.0
+ * @package questionbank
+ * @subpackage questiontypes
+ * @author Dongsheng Cai
+ * @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);
+}
diff --git a/question/type/calculatedmulti/questiontype.php b/question/type/calculatedmulti/questiontype.php
index 0d878988a06..c648899e3ab 100644
--- a/question/type/calculatedmulti/questiontype.php
+++ b/question/type/calculatedmulti/questiontype.php
@@ -1,17 +1,30 @@
.
+
/////////////////
// CALCULATED ///
/////////////////
/// QUESTION TYPE CLASS //////////////////
-
-
class question_calculatedmulti_qtype extends question_calculated_qtype {
// Used by the function custom_generator_tools:
- var $calcgenerateidhasbeenadded = false;
+ public $calcgenerateidhasbeenadded = false;
public $virtualqtype = false;
function name() {
@@ -28,14 +41,13 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
function save_question_options($question) {
- //$options = $question->subtypeoptions;
- // Get old answers:
global $CFG, $DB, $QTYPES ;
+ $context = $question->context;
if (isset($question->answer) && !isset($question->answers)) {
$question->answers = $question->answer;
}
// calculated options
- $update = true ;
+ $update = true ;
$options = $DB->get_record("question_calculated_options", array("question" => $question->id));
if (!$options) {
$update = false;
@@ -46,19 +58,20 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
$options->single = $question->single;
$options->answernumbering = $question->answernumbering;
$options->shuffleanswers = $question->shuffleanswers;
- $options->correctfeedback = trim($question->correctfeedback);
- $options->partiallycorrectfeedback = trim($question->partiallycorrectfeedback);
- $options->incorrectfeedback = trim($question->incorrectfeedback);
+
+ // save question feedback files
+ foreach (array('correct', 'partiallycorrect', 'incorrect') as $feedbacktype) {
+ $feedbackname = $feedbacktype . 'feedback';
+ $feedbackformat = $feedbackname . 'format';
+ $feedback = $question->$feedbackname;
+ $options->$feedbackformat = $feedback['format'];
+ $options->$feedbackname = file_save_draft_area_files($feedback['itemid'], $context->id, 'qtype_calculatedmulti', $feedbackname, $question->id, self::$fileoptions, trim($feedback['text']));
+ }
+
if ($update) {
- if (!$DB->update_record("question_calculated_options", $options)) {
- $result->error = "Could not update calculated question options! (id=$options->id)";
- return $result;
- }
+ $DB->update_record("question_calculated_options", $options);
} else {
- if (!$DB->insert_record("question_calculated_options", $options)) {
- $result->error = "Could not insert calculated question options!";
- return $result;
- }
+ $DB->insert_record("question_calculated_options", $options);
}
// Get old versions of the objects
@@ -71,8 +84,9 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
}
// Save the units.
- $virtualqtype = $this->get_virtual_qtype( $question);
- // $result = $virtualqtype->save_numerical_units($question);
+ $virtualqtype = $this->get_virtual_qtype($question);
+ // TODO: What is this?
+ // $result = $virtualqtype->save_numerical_units($question);
if (isset($result->error)) {
return $result;
} else {
@@ -80,21 +94,25 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
}
// Insert all the new answers
if (isset($question->answer) && !isset($question->answers)) {
- $question->answers=$question->answer;
+ $question->answers = $question->answer;
}
foreach ($question->answers as $key => $dataanswer) {
- if ( trim($dataanswer) != '' ) {
+ if ( trim($dataanswer) != '' ) {
$answer = new stdClass;
$answer->question = $question->id;
$answer->answer = trim($dataanswer);
$answer->fraction = $question->fraction[$key];
- $answer->feedback = trim($question->feedback[$key]);
+ $answer->feedback = trim($question->feedback[$key]['text']);
+ $answer->feedbackformat = $question->feedback[$key]['format'];
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
$answer->id = $oldanswer->id;
+ $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $answer->feedback);
$DB->update_record("question_answers", $answer);
} else { // This is a completely new answer
$answer->id = $DB->insert_record("question_answers", $answer);
+ $feedbacktext = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $answer->feedback);
+ $DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$answer->id));
}
// Set up the options object
@@ -129,15 +147,15 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
$DB->delete_records('question_calculated', array('id' => $oo->id));
}
}
- // $result = $QTYPES['numerical']->save_numerical_options($question);
- // if (isset($result->error)) {
- // return $result;
- // }
+ // $result = $QTYPES['numerical']->save_numerical_options($question);
+ // if (isset($result->error)) {
+ // return $result;
+ // }
if( isset($question->import_process)&&$question->import_process){
$this->import_datasets($question);
- }
+ }
// Report any problems.
if (!empty($result->notice)) {
return $result;
@@ -148,30 +166,25 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
// Find out how many datasets are available
global $CFG, $DB, $QTYPES, $OUTPUT ;
- if(!$maxnumber = (int)$DB->get_field_sql(
- "SELECT MIN(a.itemcount)
- FROM {question_dataset_definitions} a,
- {question_datasets} b
- WHERE b.question = ?
- AND a.id = b.datasetdefinition", array($question->id))) {
+ $maxnumber = (int)$DB->get_field_sql(
+ "SELECT MIN(a.itemcount)
+ FROM {question_dataset_definitions} a, {question_datasets} b
+ WHERE b.question = ? AND a.id = b.datasetdefinition", array($question->id));
+ if (!$maxnumber) {
print_error('cannotgetdsforquestion', 'question', '', $question->id);
}
- $sql = "SELECT i.*
- FROM {question_datasets} d,
- {question_dataset_definitions} i
- WHERE d.question = ?
- AND d.datasetdefinition = i.id
- AND i.category != 0
- ";
+ $sql = "SELECT i.*
+ FROM {question_datasets} d, {question_dataset_definitions} i
+ WHERE d.question = ? AND d.datasetdefinition = i.id AND i.category != 0";
if (!$question->options->synchronize || !$records = $DB->get_records_sql($sql, array($question->id))) {
- $synchronize_calculated = false ;
- }else {
- // i.e records is true so test coherence
- $coherence = true ;
- $a = new stdClass ;
- $a->qid = $question->id ;
- $a->qcat = $question->category ;
- foreach($records as $def ){
+ $synchronize_calculated = false ;
+ } else {
+ // i.e records is true so test coherence
+ $coherence = true ;
+ $a = new stdClass ;
+ $a->qid = $question->id ;
+ $a->qcat = $question->category ;
+ foreach($records as $def ){
if ($def->category != $question->category){
$a->name = $def->name;
$a->sharedcat = $def->category ;
@@ -180,11 +193,11 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
}
}
if(!$coherence){
- echo $OUTPUT->notification(get_string('nocoherencequestionsdatyasetcategory','qtype_calculated',$a));
- }
-
- $synchronize_calculated = true ;
- }
+ echo $OUTPUT->notification(get_string('nocoherencequestionsdatyasetcategory','qtype_calculated',$a));
+ }
+
+ $synchronize_calculated = true ;
+ }
// Choose a random dataset
// maxnumber sould not be breater than 100
@@ -194,41 +207,40 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
if ( $synchronize_calculated === false ) {
$state->options->datasetitem = rand(1, $maxnumber);
}else{
- $state->options->datasetitem = intval( $maxnumber * substr($attempt->timestart,-2) /100 ) ;
+ $state->options->datasetitem = intval( $maxnumber * substr($attempt->timestart,-2) /100 ) ;
if ($state->options->datasetitem < 1) {
$state->options->datasetitem =1 ;
} else if ($state->options->datasetitem > $maxnumber){
$state->options->datasetitem = $maxnumber ;
}
-
- };
+
+ };
$state->options->dataset =
- $this->pick_question_dataset($question,$state->options->datasetitem);
- // create an array of answerids ??? why so complicated ???
- $answerids = array_values(array_map(create_function('$val',
- 'return $val->id;'), $question->options->answers));
- // Shuffle the answers if required
- if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
- $answerids = swapshuffle($answerids);
- }
- $state->options->order = $answerids;
- // Create empty responses
- if ($question->options->single) {
- $state->responses = array('' => '');
- } else {
- $state->responses = array();
- }
- return true;
-
+ $this->pick_question_dataset($question,$state->options->datasetitem);
+ // create an array of answerids ??? why so complicated ???
+ $answerids = array_values(array_map(create_function('$val',
+ 'return $val->id;'), $question->options->answers));
+ // Shuffle the answers if required
+ if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
+ $answerids = swapshuffle($answerids);
+ }
+ $state->options->order = $answerids;
+ // Create empty responses
+ if ($question->options->single) {
+ $state->responses = array('' => '');
+ } else {
+ $state->responses = array();
+ }
+ return true;
}
-
+
function save_session_and_responses(&$question, &$state) {
global $DB;
- $responses = 'dataset'.$state->options->datasetitem.'-' ;
+ $responses = 'dataset'.$state->options->datasetitem.'-' ;
$responses .= implode(',', $state->options->order) . ':';
$responses .= implode(',', $state->responses);
-
- // Set the legacy answer field
+
+ // Set the legacy answer field
if (!$DB->set_field('question_states', 'answer', $responses, array('id'=> $state->id))) {
return false;
}
@@ -241,7 +253,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
foreach ($form->answers as $key => $answer) {
$a->answer = trim($form->answer[$key]);
$a->fraction = $form->fraction[$key];//new
- $a->tolerance = $form->tolerance[$key];
+ $a->tolerance = $form->tolerance[$key];
$a->tolerancetype = $form->tolerancetype[$key];
$a->correctanswerlength = $form->correctanswerlength[$key];
$a->correctanswerformat = $form->correctanswerformat[$key];
@@ -251,57 +263,53 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
return $question;
}
-
-
-
-
function convert_answers (&$question, &$state){
- foreach ($question->options->answers as $key => $answer) {
- $answer->answer = $this->substitute_variables($answer->answer, $state->options->dataset);
- //evaluate the equations i.e {=5+4)
- $qtext = "";
- $qtextremaining = $answer->answer ;
- // while (preg_match('~\{(=)|%[[:digit]]\.=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
- while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
+ foreach ($question->options->answers as $key => $answer) {
+ $answer->answer = $this->substitute_variables($answer->answer, $state->options->dataset);
+ //evaluate the equations i.e {=5+4)
+ $qtext = "";
+ $qtextremaining = $answer->answer ;
+ // while (preg_match('~\{(=)|%[[:digit]]\.=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
+ while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
- $qtextsplits = explode($regs1[0], $qtextremaining, 2);
- $qtext =$qtext.$qtextsplits[0];
- $qtextremaining = $qtextsplits[1];
- if (empty($regs1[1])) {
- $str = '';
- } else {
- if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
- $str=$formulaerrors ;
- }else {
- eval('$str = '.$regs1[1].';');
- $texteval= qtype_calculated_calculate_answer(
- $str, $state->options->dataset, $answer->tolerance,
- $answer->tolerancetype, $answer->correctanswerlength,
- $answer->correctanswerformat, '');
+ $qtextsplits = explode($regs1[0], $qtextremaining, 2);
+ $qtext = $qtext.$qtextsplits[0];
+ $qtextremaining = $qtextsplits[1];
+ if (empty($regs1[1])) {
+ $str = '';
+ } else {
+ if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
+ $str=$formulaerrors ;
+ }else {
+ eval('$str = '.$regs1[1].';');
+ $texteval= qtype_calculated_calculate_answer(
+ $str, $state->options->dataset, $answer->tolerance,
+ $answer->tolerancetype, $answer->correctanswerlength,
+ $answer->correctanswerformat, '');
$str = $texteval->answer;
- }
- }
- $qtext = $qtext.$str ;
+ }
}
- $answer->answer = $qtext.$qtextremaining ; ;
+ $qtext = $qtext.$str ;
}
+ $answer->answer = $qtext.$qtextremaining ; ;
}
+ }
- function get_default_numerical_unit($question,$virtualqtype){
- $unit = '';
- return $unit ;
- }
+ function get_default_numerical_unit($question, $virtualqtype){
+ $unit = '';
+ return $unit ;
+ }
function grade_responses(&$question, &$state, $cmoptions) {
// Forward the grading to the virtual qtype
// We modify the question to look like a multichoice question
- // for grading nothing to do
+ // for grading nothing to do
/* $numericalquestion = fullclone($question);
foreach ($numericalquestion->options->answers as $key => $answer) {
$answer = $numericalquestion->options->answers[$key]->answer; // for PHP 4.x
$numericalquestion->options->answers[$key]->answer = $this->substitute_variables_and_eval($answer,
$state->options->dataset);
- }*/
- $virtualqtype = $this->get_virtual_qtype( $question);
+}*/
+ $virtualqtype = $this->get_virtual_qtype( $question);
return $virtualqtype->grade_responses($question, $state, $cmoptions) ;
}
@@ -319,7 +327,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
$this->convert_answers ($numericalquestion, $state);
$this->convert_questiontext ($numericalquestion, $state);
/* $numericalquestion->questiontext = $this->substitute_variables_and_eval(
- $numericalquestion->questiontext, $state->options->dataset);*/
+ $numericalquestion->questiontext, $state->options->dataset);*/
$responses = $virtualqtype->get_all_responses($numericalquestion, $state);
$response = reset($responses->responses);
$correct = $response->answer.' : ';
@@ -335,8 +343,8 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
function create_virtual_qtype() {
global $CFG;
- require_once("$CFG->dirroot/question/type/multichoice/questiontype.php");
- return new question_multichoice_qtype();
+ require_once("$CFG->dirroot/question/type/multichoice/questiontype.php");
+ return new question_multichoice_qtype();
}
@@ -353,7 +361,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
} else {
$strheader .= $delimiter.$answer->answer;
}
- $delimiter = '
';
+ $delimiter = '
';
}
return $strheader;
}
@@ -369,7 +377,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
$unit = $unit->unit;
} else {
$unit = '';
- }*/
+ }*/
$answers = fullclone($answers);
$strmin = get_string('min', 'quiz');
@@ -377,29 +385,29 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
$errors = '';
$delimiter = ': ';
foreach ($answers as $key => $answer) {
- $answer->answer = $this->substitute_variables($answer->answer, $data);
- //evaluate the equations i.e {=5+4)
- $qtext = "";
- $qtextremaining = $answer->answer ;
- while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
- $qtextsplits = explode($regs1[0], $qtextremaining, 2);
- $qtext =$qtext.$qtextsplits[0];
- $qtextremaining = $qtextsplits[1];
- if (empty($regs1[1])) {
- $str = '';
- } else {
- if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
- $str=$formulaerrors ;
- }else {
- eval('$str = '.$regs1[1].';');
- }
- }
- $qtext = $qtext.$str ;
+ $answer->answer = $this->substitute_variables($answer->answer, $data);
+ //evaluate the equations i.e {=5+4)
+ $qtext = "";
+ $qtextremaining = $answer->answer ;
+ while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
+ $qtextsplits = explode($regs1[0], $qtextremaining, 2);
+ $qtext =$qtext.$qtextsplits[0];
+ $qtextremaining = $qtextsplits[1];
+ if (empty($regs1[1])) {
+ $str = '';
+ } else {
+ if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
+ $str=$formulaerrors ;
+ }else {
+ eval('$str = '.$regs1[1].';');
+ }
}
- $answer->answer = $qtext.$qtextremaining ; ;
- $comment->stranswers[$key]= $answer->answer ;
-
-
+ $qtext = $qtext.$str ;
+ }
+ $answer->answer = $qtext.$qtextremaining;
+ $comment->stranswers[$key] = $answer->answer;
+
+
/* $formula = $this->substitute_variables($answer->answer,$data);
$formattedanswer = qtype_calculated_calculate_answer(
$answer->answer, $data, $answer->tolerance,
@@ -411,7 +419,7 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
}else {
eval('$answer->answer = '.$formula.';') ;
$virtualqtype->get_tolerance_interval($answer);
- }
+ }
if ($answer->min === '') {
// This should mean that something is wrong
$comment->stranswers[$key] = " $formattedanswer->answer".'
';
@@ -432,15 +440,11 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
$comment->stranswers[$key] .=get_string('trueanswerinsidelimits','qtype_calculated',$correcttrue);//' True answer :'.$calculated->trueanswer.' inside limits';
}
$comment->stranswers[$key] .='';
- }*/
+ }*/
}
return fullclone($comment);
}
-
-
-
-
function get_correct_responses1(&$question, &$state) {
$virtualqtype = $this->get_virtual_qtype( $question);
/* if ($question->options->multichoice != 1 ) {
@@ -464,71 +468,148 @@ class question_calculatedmulti_qtype extends question_calculated_qtype {
return $correct;
}
}
- }else{**/
- return $virtualqtype->get_correct_responses($question, $state) ;
- // }
+ }else{**/
+ return $virtualqtype->get_correct_responses($question, $state) ;
+ // }
return null;
}
function get_virtual_qtype() {
global $QTYPES;
- // if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){
- $this->virtualqtype =& $QTYPES['multichoice'];
- // }else {
- // $this->virtualqtype =& $QTYPES['numerical'];
- // }
+ // if ( isset($question->options->multichoice) && $question->options->multichoice == '1'){
+ $this->virtualqtype =& $QTYPES['multichoice'];
+ // }else {
+ // $this->virtualqtype =& $QTYPES['numerical'];
+ // }
return $this->virtualqtype;
}
- /**
- * Runs all the code required to set up and save an essay question for testing purposes.
- * Alternate DB table prefix may be used to facilitate data deletion.
- */
- function generate_test($name, $courseid = null) {
- global $DB;
- list($form, $question) = parent::generate_test($name, $courseid);
- $form->feedback = 1;
- $form->multiplier = array(1, 1);
- $form->shuffleanswers = 1;
- $form->noanswers = 1;
- $form->qtype ='calculatedmulti';
- $question->qtype ='calculatedmulti';
- $form->answers = array('{a} + {b}');
- $form->fraction = array(1);
- $form->tolerance = array(0.01);
- $form->tolerancetype = array(1);
- $form->correctanswerlength = array(2);
- $form->correctanswerformat = array(1);
- $form->questiontext = "What is {a} + {b}?";
+ /**
+ * Runs all the code required to set up and save an essay question for testing purposes.
+ * Alternate DB table prefix may be used to facilitate data deletion.
+ */
+ function generate_test($name, $courseid = null) {
+ global $DB;
+ list($form, $question) = parent::generate_test($name, $courseid);
+ $form->feedback = 1;
+ $form->multiplier = array(1, 1);
+ $form->shuffleanswers = 1;
+ $form->noanswers = 1;
+ $form->qtype ='calculatedmulti';
+ $question->qtype ='calculatedmulti';
+ $form->answers = array('{a} + {b}');
+ $form->fraction = array(1);
+ $form->tolerance = array(0.01);
+ $form->tolerancetype = array(1);
+ $form->correctanswerlength = array(2);
+ $form->correctanswerformat = array(1);
+ $form->questiontext = "What is {a} + {b}?";
- if ($courseid) {
- $course = $DB->get_record('course', array('id'=> $courseid));
- }
+ if ($courseid) {
+ $course = $DB->get_record('course', array('id'=> $courseid));
+ }
- $new_question = $this->save_question($question, $form, $course);
+ $new_question = $this->save_question($question, $form, $course);
- $dataset_form = new stdClass();
- $dataset_form->nextpageparam["forceregeneration"]= 1;
- $dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
- $dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
- $dataset_form->calclength = array(1 => 1, 2 => 1);
- $dataset_form->number = array(1 => 5.4 , 2 => 4.9);
- $dataset_form->itemid = array(1 => '' , 2 => '');
- $dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
- $dataset_form->definition = array(1 => "1-0-a",
- 2 => "1-0-b");
- $dataset_form->nextpageparam = array('forceregeneration' => false);
- $dataset_form->addbutton = 1;
- $dataset_form->selectadd = 1;
- $dataset_form->courseid = $courseid;
- $dataset_form->cmid = 0;
- $dataset_form->id = $new_question->id;
- $this->save_dataset_items($new_question, $dataset_form);
+ $dataset_form = new stdClass();
+ $dataset_form->nextpageparam["forceregeneration"]= 1;
+ $dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
+ $dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
+ $dataset_form->calclength = array(1 => 1, 2 => 1);
+ $dataset_form->number = array(1 => 5.4 , 2 => 4.9);
+ $dataset_form->itemid = array(1 => '' , 2 => '');
+ $dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
+ $dataset_form->definition = array(1 => "1-0-a",
+ 2 => "1-0-b");
+ $dataset_form->nextpageparam = array('forceregeneration' => false);
+ $dataset_form->addbutton = 1;
+ $dataset_form->selectadd = 1;
+ $dataset_form->courseid = $courseid;
+ $dataset_form->cmid = 0;
+ $dataset_form->id = $new_question->id;
+ $this->save_dataset_items($new_question, $dataset_form);
- return $new_question;
- }
+ return $new_question;
+ }
+
+ /**
+ * When move the category of questions, the belonging files should be moved as well
+ * @param object $question, question information
+ * @param object $newcategory, target category information
+ */
+ function move_files($question, $newcategory) {
+ global $DB;
+ // move files belonging to question component
+ parent::move_files($question, $newcategory);
+
+ // move files belonging to qtype_calculatedmulti
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+ $component = 'question';
+ $filearea = 'answerfeedback';
+ foreach ($oldanswers as $answer) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+
+ $component = 'qtype_calculatedmulti';
+ foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $filearea) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+ }
+
+ function check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args) {
+ $itemid = reset($args);
+
+ if (empty($question->maxgrade)) {
+ $question->maxgrade = $question->defaultgrade;
+ }
+
+ if (in_array($filearea, array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'))) {
+ $result = $options->feedback && ($itemid == $question->id);
+ if (!$result) {
+ return false;
+ }
+ if ($state->raw_grade >= $question->maxgrade/1.01) {
+ $feedbacktype = 'correctfeedback';
+ } else if ($state->raw_grade > 0) {
+ $feedbacktype = 'partiallycorrectfeedback';
+ } else {
+ $feedbacktype = 'incorrectfeedback';
+ }
+ if ($feedbacktype != $filearea) {
+ return false;
+ }
+ return true;
+ } else if ($component == 'question' && $filearea == 'answerfeedback') {
+ return $options->feedback && (array_key_exists($itemid, $question->options->answers));
+ } else {
+ return parent::check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args);
+ }
+ }
}
+
//// END OF CLASS ////
//////////////////////////////////////////////////////////////////////////
diff --git a/question/type/calculatedsimple/edit_calculatedsimple_form.php b/question/type/calculatedsimple/edit_calculatedsimple_form.php
index f63b72cdc9d..8c84517e4b7 100644
--- a/question/type/calculatedsimple/edit_calculatedsimple_form.php
+++ b/question/type/calculatedsimple/edit_calculatedsimple_form.php
@@ -1,4 +1,20 @@
.
+
/**
* Defines the editing form for the calculated simplequestion type.
*
@@ -8,21 +24,17 @@
* @package questionbank
* @subpackage questiontypes
*/
-
-/**
- * calculatedsimple editing form definition.
- */
class question_edit_calculatedsimple_form extends question_edit_form {
/**
* Handle to the question type for this question.
*
* @var question_calculatedsimple_qtype
*/
- var $qtypeobj;
+ public $qtypeobj;
- var $wildcarddisplay ;
+ public $wildcarddisplay ;
- var $questiondisplay ;
+ public $questiondisplay ;
public $datasetdefs;
@@ -46,8 +58,6 @@ class question_edit_calculatedsimple_form extends question_edit_form {
public $formdata = array();
-
-
function question_edit_calculatedsimple_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
global $QTYPES, $SESSION, $CFG, $DB;
$this->regenerate = true;
@@ -60,17 +70,17 @@ class question_edit_calculatedsimple_form extends question_edit_form {
//so this should be removed from here
// get priority to paramdatasets
- if ( "1" == optional_param('reload','', PARAM_INT )) {
- $this->reload = true ;
+ if ("1" == optional_param('reload','', PARAM_INT )) {
+ $this->reload = true;
}else {
- $this->reload = false ;
+ $this->reload = false;
}
- if(!$this->reload ){ // use database data as this is first pass
+ if (!$this->reload) { // use database data as this is first pass
// question->id == 0 so no stored datasets
// else get datasets
// echo "question
";print_r($question);echo "
";
- if ( !empty($question->id)) {
-
+ if (!empty($question->id)) {
+
/* if (empty($question->options)) {
$this->get_question_options($question);
}*/
@@ -127,7 +137,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
$mandatorydatasets = array();
// should not test on adding a new answer
// should test if there are already olddatasets or if the 'analyzequestion' submit button has been clicked
- if ('' != optional_param('datasetdef', '', PARAM_RAW) || '' != optional_param('analyzequestion', '', PARAM_RAW)){
+ if ('' != optional_param('datasetdef', '', PARAM_RAW) || '' != optional_param('analyzequestion', '', PARAM_RAW)){
if ( $dummyform->answer = optional_param('answer', '', PARAM_NOTAGS)) { // there is always at least one answer...
$fraction = optional_param('fraction', '', PARAM_NUMBER);
@@ -297,12 +307,12 @@ class question_edit_calculatedsimple_form extends question_edit_form {
$addfieldsname='updatequestion value';
$addstring=get_string("updatecategory", "qtype_calculated");
$mform->registerNoSubmitButton($addfieldsname);
-//put a submit button to stop supplementary answers on update answers parameters
-// $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
+ // put a submit button to stop supplementary answers on update answers parameters
+ // $mform->insertElementBefore($mform->createElement('submit', $addfieldsname, $addstring), 'listcategory');
$creategrades = get_grade_options();
$this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
- $creategrades->gradeoptions, 1, 1);
+ $creategrades->gradeoptions, 1, 1);
$QTYPES['numerical']->add_units_options($mform,$this);
@@ -327,7 +337,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
$this->noofitems = 0;
}
if(!empty($this->datasetdefs)){//So there are some datadefs
- // we put them on the page
+ // we put them on the page
$key = 0;
$mform->addElement('header', 'additemhdr', get_string('wildcardparam', 'qtype_calculatedsimple'));
$idx = 1;
@@ -347,180 +357,183 @@ class question_edit_calculatedsimple_form extends question_edit_form {
}
//this should be done before the elements are created and stored as $this->formdata ;
//fill out all data sets and also the fields for the next item to add.
- /*Here we do already the values error analysis so that
- * we could force all wild cards values display if there is an error in values.
- * as using a , in a number */
- $this->numbererrors = array();
+ /*Here we do already the values error analysis so that
+ * we could force all wild cards values display if there is an error in values.
+ * as using a , in a number */
+ $this->numbererrors = array();
if(!empty($this->datasetdefs)){
- $j = $this->noofitems * count($this->datasetdefs);
- for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
- $data = array();
- $numbererrors = array() ;
- $comment = new stdClass;
- $comment->stranswers = array();
- $comment->outsidelimit = false ;
- $comment->answers = array();
+ $j = $this->noofitems * count($this->datasetdefs);
+ for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
+ $data = array();
+ $numbererrors = array() ;
+ $comment = new stdClass;
+ $comment->stranswers = array();
+ $comment->outsidelimit = false ;
+ $comment->answers = array();
- foreach ($this->datasetdefs as $defid => $datasetdef){
- if (isset($datasetdef->items[$itemnumber])){
- $this->formdata["definition[$j]"] = $defid;
- $this->formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
- $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
- $this->formdata["number[$j]"] = $number = $datasetdef->items[$itemnumber]->value;
- if(! is_numeric($number)){
- $a = new stdClass;
- $a->name = '{'.$datasetdef->name.'}' ;
- $a->value = $datasetdef->items[$itemnumber]->value ;
- if (stristr($number,',')){
+ foreach ($this->datasetdefs as $defid => $datasetdef){
+ if (isset($datasetdef->items[$itemnumber])){
+ $this->formdata["definition[$j]"] = $defid;
+ $this->formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
+ $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
+ $this->formdata["number[$j]"] = $number = $datasetdef->items[$itemnumber]->value;
+ if(! is_numeric($number)){
+ $a = new stdClass;
+ $a->name = '{'.$datasetdef->name.'}' ;
+ $a->value = $datasetdef->items[$itemnumber]->value ;
+ if (stristr($number,',')){
$this->numbererrors["number[$j]"]=get_string('nocommaallowed', 'qtype_calculated');
- $numbererrors .= $this->numbererrors['number['.$j.']']."
";
+ $numbererrors .= $this->numbererrors['number['.$j.']']."
";
- }else {
+ }else {
$this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
$numbererrors .= $this->numbererrors['number['.$j.']']."
";
//$comment->outsidelimit = false ;
- }
- }else if( stristr($number,'x')){ // hexa will pass the test
- $a = new stdClass;
- $a->name = '{'.$datasetdef->name.'}' ;
- $a->value = $datasetdef->items[$itemnumber]->value ;
- $this->numbererrors['number['.$j.']']= get_string('hexanotallowed','qtype_calculated',$a);
- $numbererrors .= $this->numbererrors['number['.$j.']']."
";
- } else if( is_nan($number)){
- $a = new stdClass;
- $a->name = '{'.$datasetdef->name.'}' ;
- $a->value = $datasetdef->items[$itemnumber]->value ;
- $this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
- $numbererrors .= $this->numbererrors['number['.$j.']']."
";
- // $val = 1.0 ;
- }
- }
- $j--;
- }
- if($this->noofitems != 0 ) {
- if (empty($numbererrors )){
- if(!isset($this->question->id)) $this->question->id = 0 ;
- $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj,$this->question->id,$this->question->questiontext,$this->nonemptyanswer, $data, $itemnumber);//$this->
- if ($comment->outsidelimit) {
- $this->outsidelimit=$comment->outsidelimit ;
- }
- $totalcomment='';
-
- foreach ($this->nonemptyanswer as $key => $answer) {
- $totalcomment .= $comment->stranswers[$key].'
';
- }
-
- $this->formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
}
+ }else if( stristr($number,'x')){ // hexa will pass the test
+ $a = new stdClass;
+ $a->name = '{'.$datasetdef->name.'}' ;
+ $a->value = $datasetdef->items[$itemnumber]->value ;
+ $this->numbererrors['number['.$j.']']= get_string('hexanotallowed','qtype_calculated',$a);
+ $numbererrors .= $this->numbererrors['number['.$j.']']."
";
+ } else if( is_nan($number)){
+ $a = new stdClass;
+ $a->name = '{'.$datasetdef->name.'}' ;
+ $a->value = $datasetdef->items[$itemnumber]->value ;
+ $this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
+ $numbererrors .= $this->numbererrors['number['.$j.']']."
";
+ // $val = 1.0 ;
}
+ }
+ $j--;
}
- $this->formdata['selectdelete'] = '1';
- $this->formdata['selectadd'] = '1';
- $j = $this->noofitems * count($this->datasetdefs)+1;
- $data = array(); // data for comment_on_datasetitems later
+ if($this->noofitems != 0 ) {
+ if (empty($numbererrors)) {
+ if (!isset($this->question->id)) {
+ $this->question->id = 0 ;
+ }
+ $this->question->questiontext = !empty($this->question->questiontext)?$this->question->questiontext:'';
+ $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $this->question->id, $this->question->questiontext, $this->nonemptyanswer, $data, $itemnumber);
+ if ($comment->outsidelimit) {
+ $this->outsidelimit=$comment->outsidelimit ;
+ }
+ $totalcomment='';
+
+ foreach ($this->nonemptyanswer as $key => $answer) {
+ $totalcomment .= $comment->stranswers[$key].'
';
+ }
+
+ $this->formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
+ }
+ }
+ }
+ $this->formdata['selectdelete'] = '1';
+ $this->formdata['selectadd'] = '1';
+ $j = $this->noofitems * count($this->datasetdefs)+1;
+ $data = array(); // data for comment_on_datasetitems later
$idx =1 ;
foreach ($this->datasetdefs as $defid => $datasetdef){
$this->formdata["datasetdef[$idx]"] = $defid;
$idx++;
}
- $this->formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $this->formdata);
+ $this->formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $this->formdata);
+ }
+
+
+ $addoptions = Array();
+ $addoptions['1']='1';
+ for ($i=10; $i<=100 ; $i+=10){
+ $addoptions["$i"]="$i";
+ }
+ $showoptions = Array();
+ $showoptions['1']='1';
+ $showoptions['2']='2';
+ $showoptions['5']='5';
+ for ($i=10; $i<=100 ; $i+=10){
+ $showoptions["$i"]="$i";
+ }
+ $mform->closeHeaderBefore('additemhdr');
+ $addgrp = array();
+ $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('generatenewitemsset', 'qtype_calculatedsimple'));
+ $addgrp[] =& $mform->createElement('select', "selectadd", '', $addoptions);
+ $addgrp[] = & $mform->createElement('static',"stat",'',get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
+ $mform->addGroup($addgrp, 'addgrp', '', ' ', false);
+ $mform->registerNoSubmitButton('addbutton');
+ $mform->closeHeaderBefore('addgrp');
+ $addgrp1 = array();
+ $addgrp1[] =& $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculatedsimple'));
+ $addgrp1[] =& $mform->createElement('select', "selectshow",'' , $showoptions);
+ $addgrp1[] = & $mform->createElement('static',"stat",'',get_string('setwildcardvalues', 'qtype_calculatedsimple'));
+ $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
+ $mform->registerNoSubmitButton('showbutton');
+ $mform->closeHeaderBefore('addgrp1');
+ $mform->addElement('static', "divideradd", '', '');
+ if ($this->noofitems == 0) {
+ $mform->addElement('static','warningnoitems','',''.get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple').'');
+ $mform->closeHeaderBefore('warningnoitems');
+ }else {
+ $mform->addElement('header', 'additemhdr1', get_string('wildcardvalues', 'qtype_calculatedsimple'));
+ $mform->closeHeaderBefore('additemhdr1');
+ // $mform->addElement('header', '', get_string('itemno', 'qtype_calculated', ""));
+ if( !empty($this->numbererrors) || $this->outsidelimit) {
+ $mform->addElement('static', "alert", '', ''.get_string('useadvance', 'qtype_calculatedsimple').'');
}
+ $mform->addElement('submit', 'updatedatasets', get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
+ $mform->registerNoSubmitButton('updatedatasets');
+ $mform->setAdvanced("updatedatasets",true);
- $addoptions = Array();
- $addoptions['1']='1';
- for ($i=10; $i<=100 ; $i+=10){
- $addoptions["$i"]="$i";
- }
- $showoptions = Array();
- $showoptions['1']='1';
- $showoptions['2']='2';
- $showoptions['5']='5';
- for ($i=10; $i<=100 ; $i+=10){
- $showoptions["$i"]="$i";
- }
- $mform->closeHeaderBefore('additemhdr');
- $addgrp = array();
- $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('generatenewitemsset', 'qtype_calculatedsimple'));
- $addgrp[] =& $mform->createElement('select', "selectadd", '', $addoptions);
- $addgrp[] = & $mform->createElement('static',"stat",'',get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
- $mform->addGroup($addgrp, 'addgrp', '', ' ', false);
- $mform->registerNoSubmitButton('addbutton');
- $mform->closeHeaderBefore('addgrp');
- $addgrp1 = array();
- $addgrp1[] =& $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculatedsimple'));
- $addgrp1[] =& $mform->createElement('select', "selectshow",'' , $showoptions);
- $addgrp1[] = & $mform->createElement('static',"stat",'',get_string('setwildcardvalues', 'qtype_calculatedsimple'));
- $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
- $mform->registerNoSubmitButton('showbutton');
- $mform->closeHeaderBefore('addgrp1');
- $mform->addElement('static', "divideradd", '', '');
- if ($this->noofitems == 0) {
- $mform->addElement('static','warningnoitems','',''.get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple').'');
- $mform->closeHeaderBefore('warningnoitems');
+ //------------------------------------------------------------------------------------------------------------------------------
+ $j = $this->noofitems * count($this->datasetdefs);
+ $k = 1 ;
+ if ("" != optional_param('selectshow')){
+ $k = optional_param('selectshow', '', PARAM_INT);
+ }
+
+ for ($i = $this->noofitems; $i >= 1 ; $i--){
+ foreach ($this->datasetdefs as $defkey => $datasetdef){
+ if($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ){
+ $mform->addElement('text',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
+ $mform->setAdvanced("number[$j]",true);
+ if(!empty($this->numbererrors['number['.$j.']']) ){
+ $mform->addElement('static', "numbercomment[$j]",'',''.$this->numbererrors['number['.$j.']'].'');
+ $mform->setAdvanced("numbercomment[$j]",true);
+ }
+ }else {
+ $mform->addElement('hidden',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
+ }
+ $mform->setType("number[$j]", PARAM_NUMBER);
+
+ $mform->addElement('hidden', "itemid[$j]");
+ $mform->setType("itemid[$j]", PARAM_INT);
+
+ $mform->addElement('hidden', "definition[$j]");
+ $mform->setType("definition[$j]", PARAM_NOTAGS);
+
+ $j--;
+ }
+ if (!empty( $strquestionlabel) && ($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ) ){
+ // $repeated[] =& $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
+ $mform->addElement('static', "answercomment[$i]", "".get_string('setno', 'qtype_calculatedsimple', $i)." ".$strquestionlabel);
+
+ }
+ if($k > 0 || $this->outsidelimit || !empty($this->numbererrors )){
+ $mform->addElement('static', "divider1[$j]", '', '
');
+
+ }
+ $k-- ;
+ }
+ }
+ // if ($this->outsidelimit){
+ // $mform->addElement('static','outsidelimit','','');
+ // }
}else {
- $mform->addElement('header', 'additemhdr1', get_string('wildcardvalues', 'qtype_calculatedsimple'));
- $mform->closeHeaderBefore('additemhdr1');
- // $mform->addElement('header', '', get_string('itemno', 'qtype_calculated', ""));
- if( !empty($this->numbererrors) || $this->outsidelimit) {
- $mform->addElement('static', "alert", '', ''.get_string('useadvance', 'qtype_calculatedsimple').'');
+ $mform->addElement('static','warningnowildcards','',''.get_string('atleastonewildcard', 'qtype_calculatedsimple').'');
+ $mform->closeHeaderBefore('warningnowildcards');
}
- $mform->addElement('submit', 'updatedatasets', get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
- $mform->registerNoSubmitButton('updatedatasets');
- $mform->setAdvanced("updatedatasets",true);
-//------------------------------------------------------------------------------------------------------------------------------
- $j = $this->noofitems * count($this->datasetdefs);
- $k = 1 ;
- if ("" != optional_param('selectshow')){
- $k = optional_param('selectshow', '', PARAM_INT);
- }
-
- for ($i = $this->noofitems; $i >= 1 ; $i--){
- foreach ($this->datasetdefs as $defkey => $datasetdef){
- if($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ){
- $mform->addElement('text',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
- $mform->setAdvanced("number[$j]",true);
- if(!empty($this->numbererrors['number['.$j.']']) ){
- $mform->addElement('static', "numbercomment[$j]",'',''.$this->numbererrors['number['.$j.']'].'');
- $mform->setAdvanced("numbercomment[$j]",true);
- }
- }else {
- $mform->addElement('hidden',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
- }
- $mform->setType("number[$j]", PARAM_NUMBER);
-
- $mform->addElement('hidden', "itemid[$j]");
- $mform->setType("itemid[$j]", PARAM_INT);
-
- $mform->addElement('hidden', "definition[$j]");
- $mform->setType("definition[$j]", PARAM_NOTAGS);
-
- $j--;
- }
- if (!empty( $strquestionlabel) && ($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ) ){
- // $repeated[] =& $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
- $mform->addElement('static', "answercomment[$i]", "".get_string('setno', 'qtype_calculatedsimple', $i)." ".$strquestionlabel);
-
- }
- if($k > 0 || $this->outsidelimit || !empty($this->numbererrors )){
- $mform->addElement('static', "divider1[$j]", '', '
');
-
- }
- $k-- ;
- }
- }
- // if ($this->outsidelimit){
- // $mform->addElement('static','outsidelimit','','');
- // }
- }else {
- $mform->addElement('static','warningnowildcards','',''.get_string('atleastonewildcard', 'qtype_calculatedsimple').'');
- $mform->closeHeaderBefore('warningnowildcards');
- }
-
-
-//------------------------------------------------------------------------------------------------------------------------------
+ //------------------------------------------------------------------------------------------------------------------------------
//non standard name for button element needed so not using add_action_buttons
//hidden elements
@@ -536,50 +549,64 @@ class question_edit_calculatedsimple_form extends question_edit_form {
$mform->setDefault('cmid', 0);
if (!empty($this->question->id)){
if ($this->question->formoptions->cansaveasnew){
- $mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
- $mform->closeHeaderBefore('additemhdr');
+ $mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
+ $mform->closeHeaderBefore('additemhdr');
$mform->addElement('checkbox', 'convert','' ,get_string('willconverttocalculated', 'qtype_calculatedsimple'));
- $mform->setDefault('convert', 0);
+ $mform->setDefault('convert', 0);
- }
}
+ }
}
- function set_data($question) {
+ function data_preprocessing($question) {
global $QTYPES;
+ $answer = $this->answer;
+ $default_values = array();
+ if (count($answer)) {
+ $key = 0;
+ foreach ($answer as $answer){
+ $default_values['answer['.$key.']'] = $answer->answer; // is necessary ? to-do test it
+ $default_values['fraction['.$key.']'] = $answer->fraction;
+ $default_values['tolerance['.$key.']'] = $answer->tolerance;
+ $default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
+ $default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
+ $default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
- $answer = $this->answer;
- $default_values = array();
- if (count($answer)) {
- $key = 0;
- foreach ($answer as $answer){
- $default_values['answer['.$key.']'] = $answer->answer; // is necessary ? to-do test it
- $default_values['fraction['.$key.']'] = $answer->fraction;
- $default_values['tolerance['.$key.']'] = $answer->tolerance;
- $default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
- $default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
- $default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
- $key++;
- }
+ // prepare draft files
+ $draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
+ $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
+ $draftid, // draftid
+ $this->context->id, // context
+ 'question', // component
+ 'answerfeedback', // filarea
+ !empty($answer->id)?(int)$answer->id:null, // itemid
+ $this->fileoptions, // options
+ !empty($answer->feedback)?$answer->feedback:'' // text
+ );
+ $default_values['feedback['.$key.']']['format'] = !empty($answer->feedbackformat)?$answer->feedbackformat:editors_get_preferred_format();
+ $default_values['feedback['.$key.']']['itemid'] = $draftid;
+
+ $key++;
}
- $default_values['synchronize'] = 0 ;
- $QTYPES['numerical']->set_numerical_unit_data($question,$default_values);
- /* if (isset($question->options)){
+ }
+ $default_values['synchronize'] = 0 ;
+ $QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
+ /* if (isset($question->options)){
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
$default_values['unitpenalty'] = $question->options->unitpenalty ;
switch ($question->options->showunits){
case 'O' :
- case '1' :
+ case '1' :
$default_values['showunits0'] = $question->options->showunits ;
$default_values['unitrole'] = 0 ;
break;
case '2' :
- case '3' :
+ case '3' :
$default_values['showunits1'] = $question->options->showunits ;
$default_values['unitrole'] = 1 ;
break;
- }
+ }
$default_values['unitsleft'] = $question->options->unitsleft ;
$default_values['instructions'] = $question->options->instructions ;
@@ -593,16 +620,16 @@ class question_edit_calculatedsimple_form extends question_edit_form {
}
}
}
- */
- $key = 0 ;
+ */
+ $key = 0 ;
$formdata = array();
$fromform = new stdClass();
//this should be done before the elements are created and stored as $this->formdata ;
//fill out all data sets and also the fields for the next item to add.
- /* if(!empty($this->datasetdefs)){
+ /* if(!empty($this->datasetdefs)){
$j = $this->noofitems * count($this->datasetdefs);
- for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
+ for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
$data = array();
foreach ($this->datasetdefs as $defid => $datasetdef){
if (isset($datasetdef->items[$itemnumber])){
@@ -613,27 +640,27 @@ class question_edit_calculatedsimple_form extends question_edit_form {
}
$j--;
}
- // echo "answers avant comment
";print_r($answer);echo"
";
- // echo "data avant comment
";print_r($data);echo"
";
+ // echo "answers avant comment
";print_r($answer);echo"
";
+ // echo "data avant comment
";print_r($data);echo"
";
if($this->noofitems != 0 ) {
if(!isset($question->id)) $question->id = 0 ;
- $comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this->
- if ($comment->outsidelimit) {
- $this->outsidelimit=$comment->outsidelimit ;
- }
- $totalcomment='';
- // echo " comment
";print_r($comment);echo"
";
+ $comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this->
+ if ($comment->outsidelimit) {
+ $this->outsidelimit=$comment->outsidelimit ;
+ }
+ $totalcomment='';
+ // echo " comment
";print_r($comment);echo"
";
- foreach ($this->nonemptyanswer as $key => $answer) {
- $totalcomment .= $comment->stranswers[$key].'
';
- }
+ foreach ($this->nonemptyanswer as $key => $answer) {
+ $totalcomment .= $comment->stranswers[$key].'
';
+ }
- $formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
+ $formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
+ }
}
- }
- // $formdata['reload'] = '1';
- // $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
+ // $formdata['reload'] = '1';
+ // $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
$formdata['selectdelete'] = '1';
$formdata['selectadd'] = '1';
$j = $this->noofitems * count($this->datasetdefs)+1;
@@ -644,10 +671,10 @@ class question_edit_calculatedsimple_form extends question_edit_form {
$idx++;
}
$formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
- }*/
+ }*/
$question = (object)((array)$question + $default_values+$this->formdata );
- parent::set_data($question);
+ return $question;
}
function qtype() {
@@ -659,8 +686,8 @@ class question_edit_calculatedsimple_form extends question_edit_form {
$errors = parent::validation($data, $files);
//verifying for errors in {=...} in question text;
$qtext = "";
- $qtextremaining = $data['questiontext'] ;
- $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
+ $qtextremaining = $data['questiontext']['text'];
+ $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
foreach ($possibledatasets as $name => $value) {
$qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
}
@@ -679,7 +706,7 @@ class question_edit_calculatedsimple_form extends question_edit_form {
$answers = $data['answer'];
$answercount = 0;
$maxgrade = false;
- $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
+ $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
$mandatorydatasets = array();
foreach ($answers as $key => $answer){
$mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
@@ -797,4 +824,3 @@ class question_edit_calculatedsimple_form extends question_edit_form {
return $errors;
}
}
-
diff --git a/question/type/calculatedsimple/lib.php b/question/type/calculatedsimple/lib.php
new file mode 100644
index 00000000000..23a1770a583
--- /dev/null
+++ b/question/type/calculatedsimple/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * Serve question type files
+ *
+ * @since 2.0
+ * @package questionbank
+ * @subpackage questiontypes
+ * @author Dongsheng Cai
+ * @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);
+}
diff --git a/question/type/calculatedsimple/questiontype.php b/question/type/calculatedsimple/questiontype.php
index 91bcd9a40bf..bb6845e8ebb 100644
--- a/question/type/calculatedsimple/questiontype.php
+++ b/question/type/calculatedsimple/questiontype.php
@@ -1,30 +1,41 @@
.
+
/////////////////
// CALCULATED ///
/////////////////
/// QUESTION TYPE CLASS //////////////////
-
-
class question_calculatedsimple_qtype extends question_calculated_qtype {
// Used by the function custom_generator_tools:
- var $calcgenerateidhasbeenadded = false;
+ public $calcgenerateidhasbeenadded = false;
public $virtualqtype = false;
function name() {
return 'calculatedsimple';
}
-
-
-
function save_question_options($question) {
+ global $CFG, $DB , $QTYPES;
+ $context = $question->context;
//$options = $question->subtypeoptions;
// Get old answers:
- global $CFG, $DB , $QTYPES;
if (isset($question->answer) && !isset($question->answers)) {
$question->answers = $question->answer;
@@ -52,18 +63,22 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
$question->answers=$question->answer;
}
foreach ($question->answers as $key => $dataanswer) {
- if ( trim($dataanswer) != '' ) {
+ if ( trim($dataanswer) != '' ) {
$answer = new stdClass;
$answer->question = $question->id;
$answer->answer = trim($dataanswer);
$answer->fraction = $question->fraction[$key];
- $answer->feedback = trim($question->feedback[$key]);
+ $answer->feedbackformat = $question->feedback[$key]['format'];
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
$answer->id = $oldanswer->id;
+ $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback[$key]['text']));
$DB->update_record("question_answers", $answer);
} else { // This is a completely new answer
+ $answer->feedback = '';
$answer->id = $DB->insert_record("question_answers", $answer);
+ $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback[$key]['text']));
+ $DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id));
}
// Set up the options object
@@ -99,82 +114,82 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
}
}
-
- if( isset($question->import_process)&&$question->import_process){
+ if(isset($question->import_process)&&$question->import_process) {
$this->import_datasets($question);
- }else {
+ } else {
//save datasets and datatitems from form i.e in question
- // $datasetdefs = $this->get_dataset_definitions($question->id, array());
- $question->dataset = $question->datasetdef ;
- // $this->save_dataset_definitions($question);
- // Save datasets
- $datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
- $tmpdatasets = array_flip($question->dataset);
- $defids = array_keys($datasetdefinitions);
- $datasetdefs = array();
- foreach ($defids as $defid) {
- $datasetdef = &$datasetdefinitions[$defid];
- if (isset($datasetdef->id)) {
- if (!isset($tmpdatasets[$defid])) {
- // This dataset is not used any more, delete it
- $DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $datasetdef->id));
- // if ($datasetdef->category == 0) { // Question local dataset
+ // $datasetdefs = $this->get_dataset_definitions($question->id, array());
+ $question->dataset = $question->datasetdef ;
+ // $this->save_dataset_definitions($question);
+ // Save datasets
+ $datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
+ $tmpdatasets = array_flip($question->dataset);
+ $defids = array_keys($datasetdefinitions);
+ $datasetdefs = array();
+ foreach ($defids as $defid) {
+ $datasetdef = &$datasetdefinitions[$defid];
+ if (isset($datasetdef->id)) {
+ if (!isset($tmpdatasets[$defid])) {
+ // This dataset is not used any more, delete it
+ $DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $datasetdef->id));
+ // if ($datasetdef->category == 0) { // Question local dataset
$DB->delete_records('question_dataset_definitions', array('id' => $datasetdef->id));
$DB->delete_records('question_dataset_items', array('definition' => $datasetdef->id));
- // }
- }
- // This has already been saved or just got deleted
+ // }
+ }
+ // This has already been saved or just got deleted
+ unset($datasetdefinitions[$defid]);
+ continue;
+ }
+ $datasetdef->id = $DB->insert_record('question_dataset_definitions', $datasetdef);
+ $datasetdefs[]= clone($datasetdef);
+ $questiondataset = new stdClass;
+ $questiondataset->question = $question->id;
+ $questiondataset->datasetdefinition = $datasetdef->id;
+ $DB->insert_record('question_datasets', $questiondataset);
unset($datasetdefinitions[$defid]);
- continue;
}
- $datasetdef->id = $DB->insert_record('question_dataset_definitions', $datasetdef);
- $datasetdefs[]= clone($datasetdef);
- $questiondataset = new stdClass;
- $questiondataset->question = $question->id;
- $questiondataset->datasetdefinition = $datasetdef->id;
- $DB->insert_record('question_datasets', $questiondataset);
- unset($datasetdefinitions[$defid]);
- }
- // Remove local obsolete datasets as well as relations
- // to datasets in other categories:
- if (!empty($datasetdefinitions)) {
- foreach ($datasetdefinitions as $def) {
- $DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $def->id));
- if ($def->category == 0) { // Question local dataset
- $DB->delete_records('question_dataset_definitions', array('id' => $def->id));
- $DB->delete_records('question_dataset_items', array('definition' => $def->id));
+ // Remove local obsolete datasets as well as relations
+ // to datasets in other categories:
+ if (!empty($datasetdefinitions)) {
+ foreach ($datasetdefinitions as $def) {
+ $DB->delete_records('question_datasets', array('question' => $question->id, 'datasetdefinition' => $def->id));
+ if ($def->category == 0) { // Question local dataset
+ $DB->delete_records('question_dataset_definitions', array('id' => $def->id));
+ $DB->delete_records('question_dataset_items', array('definition' => $def->id));
+ }
+ }
+ }
+ $datasetdefs = $this->get_dataset_definitions($question->id, $question->dataset);
+ // Handle adding and removing of dataset items
+ $i = 1;
+ ksort($question->definition);
+ foreach ($question->definition as $key => $defid) {
+ $addeditem = new stdClass();
+ $addeditem->definition = $datasetdefs[$defid]->id;
+ $addeditem->value = $question->number[$i];
+ $addeditem->itemnumber = ceil($i / count($datasetdefs));
+ if (empty($question->makecopy) && $question->itemid[$i]) {
+ // Reuse any previously used record
+ $addeditem->id = $question->itemid[$i];
+ $DB->update_record('question_dataset_items', $addeditem);
+ } else {
+ $DB->insert_record('question_dataset_items', $addeditem);
+ }
+ $i++;
+ }
+ $maxnumber = -1;
+ if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber){
+ $maxnumber = $addeditem->itemnumber;
+ foreach ($datasetdefs as $key => $newdef) {
+ if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) {
+ $newdef->itemcount = $maxnumber;
+ // Save the new value for options
+ $DB->update_record('question_dataset_definitions', $newdef);
+ }
}
}
}
- $datasetdefs = $this->get_dataset_definitions($question->id, $question->dataset);
- // Handle adding and removing of dataset items
- $i = 1;
- ksort($question->definition);
- foreach ($question->definition as $key => $defid) {
- $addeditem = new stdClass();
- $addeditem->definition = $datasetdefs[$defid]->id;
- $addeditem->value = $question->number[$i];
- $addeditem->itemnumber = ceil($i / count($datasetdefs));
- if (empty($question->makecopy) && $question->itemid[$i]) {
- // Reuse any previously used record
- $addeditem->id = $question->itemid[$i];
- $DB->update_record('question_dataset_items', $addeditem);
- } else {
- $DB->insert_record('question_dataset_items', $addeditem);
- }
- $i++;
- }
- if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber){
- $maxnumber = $addeditem->itemnumber;
- foreach ($datasetdefs as $key => $newdef) {
- if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) {
- $newdef->itemcount = $maxnumber;
- // Save the new value for options
- $DB->update_record('question_dataset_definitions', $newdef);
- }
- }
- }
- }
// Report any problems.
//convert to calculated
if(!empty($question->makecopy) && !empty($question->convert)) {
@@ -190,39 +205,34 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
}
return true;
}
- function finished_edit_wizard(&$form) {
+ function finished_edit_wizard(&$form) {
return true ; //isset($form->backtoquiz);
}
-
-
-
/**
- * this version save the available data at the different steps of the question editing process
- * without using global $SESSION as storage between steps
- * at the first step $wizardnow = 'question'
- * when creating a new question
- * when modifying a question
- * when copying as a new question
- * the general parameters and answers are saved using parent::save_question
- * then the datasets are prepared and saved
- * at the second step $wizardnow = 'datasetdefinitions'
- * the datadefs final type are defined as private, category or not a datadef
- * at the third step $wizardnow = 'datasetitems'
- * the datadefs parameters and the data items are created or defined
- *
- * @param object question
- * @param object $form
- * @param int $course
- * @param PARAM_ALPHA $wizardnow should be added as we are coming from question2.php
- */
+ * this version save the available data at the different steps of the question editing process
+ * without using global $SESSION as storage between steps
+ * at the first step $wizardnow = 'question'
+ * when creating a new question
+ * when modifying a question
+ * when copying as a new question
+ * the general parameters and answers are saved using parent::save_question
+ * then the datasets are prepared and saved
+ * at the second step $wizardnow = 'datasetdefinitions'
+ * the datadefs final type are defined as private, category or not a datadef
+ * at the third step $wizardnow = 'datasetitems'
+ * the datadefs parameters and the data items are created or defined
+ *
+ * @param object question
+ * @param object $form
+ * @param int $course
+ * @param PARAM_ALPHA $wizardnow should be added as we are coming from question2.php
+ */
function save_question($question, $form, $course) {
$question = default_questiontype::save_question($question, $form, $course);
return $question;
}
-
-
function custom_generator_tools_part(&$mform, $idx, $j){
$minmaxgrp = array();
@@ -247,14 +257,14 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
$strheader = "";
$delimiter = '';
- // $answers = $question->options->answers;
+ // $answers = $question->options->answers;
foreach ($answers as $key => $answer) {
/* if (is_string($answer)) {
$strheader .= $delimiter.$answer;
- } else {*/
- $strheader .= $delimiter.$answer->answer;
- // }
+ } else {*/
+ $strheader .= $delimiter.$answer->answer;
+ // }
$delimiter = '
';
}
return $strheader;
@@ -262,18 +272,18 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
function tolerance_types() {
return array('1' => get_string('relative', 'quiz'),
- '2' => get_string('nominal', 'quiz'),
- // '3' => get_string('geometric', 'quiz')
- );
+ '2' => get_string('nominal', 'quiz'),
+ // '3' => get_string('geometric', 'quiz')
+ );
}
function dataset_options($form, $name, $mandatory=true,$renameabledatasets=false) {
- // Takes datasets from the parent implementation but
- // filters options that are currently not accepted by calculated
- // It also determines a default selection...
- //$renameabledatasets not implemented anmywhere
+ // Takes datasets from the parent implementation but
+ // filters options that are currently not accepted by calculated
+ // It also determines a default selection...
+ //$renameabledatasets not implemented anmywhere
list($options, $selected) = $this->dataset_options_from_database($form, $name,'','qtype_calculated');
- // list($options, $selected) = $this->dataset_optionsa($form, $name);
+ // list($options, $selected) = $this->dataset_optionsa($form, $name);
foreach ($options as $key => $whatever) {
if (!preg_match('~^1-~', $key) && $key != '0') {
@@ -282,7 +292,7 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
}
if (!$selected) {
if ($mandatory){
- $selected = "1-0-$name"; // Default
+ $selected = "1-0-$name"; // Default
}else {
$selected = "0"; // Default
}
@@ -291,53 +301,123 @@ class question_calculatedsimple_qtype extends question_calculated_qtype {
}
-/**
- * Runs all the code required to set up and save an essay question for testing purposes.
- * Alternate DB table prefix may be used to facilitate data deletion.
- */
- function generate_test($name, $courseid = null) {
- global $DB;
- list($form, $question) = parent::generate_test($name, $courseid);
- $form->feedback = 1;
- $form->multiplier = array(1, 1);
- $form->shuffleanswers = 1;
- $form->noanswers = 1;
- $form->qtype ='calculatedsimple';
- $question->qtype ='calculatedsimple';
- $form->answers = array('{a} + {b}');
- $form->fraction = array(1);
- $form->tolerance = array(0.01);
- $form->tolerancetype = array(1);
- $form->correctanswerlength = array(2);
- $form->correctanswerformat = array(1);
- $form->questiontext = "What is {a} + {b}?";
+ /**
+ * Runs all the code required to set up and save an essay question for testing purposes.
+ * Alternate DB table prefix may be used to facilitate data deletion.
+ */
+ function generate_test($name, $courseid = null) {
+ global $DB;
+ list($form, $question) = parent::generate_test($name, $courseid);
+ $form->feedback = 1;
+ $form->multiplier = array(1, 1);
+ $form->shuffleanswers = 1;
+ $form->noanswers = 1;
+ $form->qtype ='calculatedsimple';
+ $question->qtype ='calculatedsimple';
+ $form->answers = array('{a} + {b}');
+ $form->fraction = array(1);
+ $form->tolerance = array(0.01);
+ $form->tolerancetype = array(1);
+ $form->correctanswerlength = array(2);
+ $form->correctanswerformat = array(1);
+ $form->questiontext = "What is {a} + {b}?";
- if ($courseid) {
- $course = $DB->get_record('course', array('id'=> $courseid));
- }
+ if ($courseid) {
+ $course = $DB->get_record('course', array('id'=> $courseid));
+ }
- $new_question = $this->save_question($question, $form, $course);
+ $new_question = $this->save_question($question, $form, $course);
- $dataset_form = new stdClass();
- $dataset_form->nextpageparam["forceregeneration"]= 1;
- $dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
- $dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
- $dataset_form->calclength = array(1 => 1, 2 => 1);
- $dataset_form->number = array(1 => 5.4 , 2 => 4.9);
- $dataset_form->itemid = array(1 => '' , 2 => '');
- $dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
- $dataset_form->definition = array(1 => "1-0-a",
- 2 => "1-0-b");
- $dataset_form->nextpageparam = array('forceregeneration' => false);
- $dataset_form->addbutton = 1;
- $dataset_form->selectadd = 1;
- $dataset_form->courseid = $courseid;
- $dataset_form->cmid = 0;
- $dataset_form->id = $new_question->id;
- $this->save_dataset_items($new_question, $dataset_form);
+ $dataset_form = new stdClass();
+ $dataset_form->nextpageparam["forceregeneration"]= 1;
+ $dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
+ $dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
+ $dataset_form->calclength = array(1 => 1, 2 => 1);
+ $dataset_form->number = array(1 => 5.4 , 2 => 4.9);
+ $dataset_form->itemid = array(1 => '' , 2 => '');
+ $dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
+ $dataset_form->definition = array(1 => "1-0-a",
+ 2 => "1-0-b");
+ $dataset_form->nextpageparam = array('forceregeneration' => false);
+ $dataset_form->addbutton = 1;
+ $dataset_form->selectadd = 1;
+ $dataset_form->courseid = $courseid;
+ $dataset_form->cmid = 0;
+ $dataset_form->id = $new_question->id;
+ $this->save_dataset_items($new_question, $dataset_form);
- return $new_question;
- }
+ return $new_question;
+ }
+ /**
+ * When move the category of questions, the belonging files should be moved as well
+ * @param object $question, question information
+ * @param object $newcategory, target category information
+ */
+ function move_files($question, $newcategory) {
+ global $DB;
+ parent::move_files($question, $newcategory);
+
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+ $component = 'question';
+ $filearea = 'feedback';
+ foreach ($oldanswers as $answer) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+ $component = 'qtype_calculatedsimple';
+ $filearea = 'feedback';
+ $filearea = 'instruction';
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+
+ function check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args) {
+ $itemid = reset($args);
+ if ($component == 'question' && $filearea == 'answerfeedback') {
+
+ // check if answer id exists
+ $result = $options->feedback && array_key_exists($itemid, $question->options->answers);
+ if (!$result) {
+ return false;
+ }
+ // check response
+ if (!$this->check_response($question, $state)) {
+ return false;
+ }
+ return true;
+ } else if ($filearea == 'instruction') {
+ // TODO: should it be display all the time like questiontext?
+ // check if question id exists
+ if ($itemid != $question->id) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return parent::check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args);
+ }
+ return true;
+ }
}
//// END OF CLASS ////
@@ -349,5 +429,3 @@ question_register_questiontype(new question_calculatedsimple_qtype());
if ( ! defined ("CALCULATEDSIMPLE")) {
define("CALCULATEDSIMPLE", "calculatedsimple");
}
-
-
diff --git a/question/type/description/edit_description_form.php b/question/type/description/edit_description_form.php
index 3170740f00f..b13858f8059 100644
--- a/question/type/description/edit_description_form.php
+++ b/question/type/description/edit_description_form.php
@@ -1,4 +1,20 @@
.
+
/**
* Defines the editing form for the description question type.
*
diff --git a/question/type/description/question.html b/question/type/description/question.html
index c55db3daf6e..78f525e8ba2 100644
--- a/question/type/description/question.html
+++ b/question/type/description/question.html
@@ -6,10 +6,6 @@
-
-
-
-
diff --git a/question/type/description/questiontype.php b/question/type/description/questiontype.php
index 2d4221e70ee..c3e8fb812c0 100644
--- a/question/type/description/questiontype.php
+++ b/question/type/description/questiontype.php
@@ -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());
-
diff --git a/question/type/edit_question_form.php b/question/type/edit_question_form.php
index 21b0ed26034..a0a59770704 100644
--- a/question/type/edit_question_form.php
+++ b/question/type/edit_question_form.php
@@ -1,4 +1,20 @@
.
+
/**
* 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 '';
}
}
-
-
diff --git a/question/type/essay/display.html b/question/type/essay/display.html
index 2acb0a2f5b0..89c91d8014c 100644
--- a/question/type/essay/display.html
+++ b/question/type/essay/display.html
@@ -2,10 +2,6 @@
-
-
-
-
diff --git a/question/type/essay/edit_essay_form.php b/question/type/essay/edit_essay_form.php
index 5b90371d72d..b2388428927 100644
--- a/question/type/essay/edit_essay_form.php
+++ b/question/type/essay/edit_essay_form.php
@@ -1,4 +1,20 @@
.
+
/**
* 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';
}
}
-
diff --git a/question/type/essay/lib.php b/question/type/essay/lib.php
new file mode 100644
index 00000000000..dc1fe09d5ca
--- /dev/null
+++ b/question/type/essay/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * Serve question type files
+ *
+ * @since 2.0
+ * @package questionbank
+ * @subpackage questiontypes
+ * @author Dongsheng Cai
+ * @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);
+}
diff --git a/question/type/essay/questiontype.php b/question/type/essay/questiontype.php
index 12acc8d629e..67bafcd99f1 100644
--- a/question/type/essay/questiontype.php
+++ b/question/type/essay/questiontype.php
@@ -1,5 +1,20 @@
.
+
//////////////////
/// ESSAY ///
/////////////////
@@ -21,6 +36,7 @@ class question_essay_qtype extends default_questiontype {
function save_question_options($question) {
global $DB;
+ $context = $question->context;
$result = true;
$update = true;
$answer = $DB->get_record("question_answers", array("question" => $question->id));
@@ -29,13 +45,20 @@ class question_essay_qtype extends default_questiontype {
$answer->question = $question->id;
$update = false;
}
- $answer->answer = $question->feedback;
- $answer->feedback = $question->feedback;
+ $answer->feedbackformat = $question->feedback['format'];
+ $answer->answerformat = $question->feedback['format'];
$answer->fraction = $question->fraction;
if ($update) {
+ $answer->feedback = file_save_draft_area_files($question->feedback['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback['text']));
+ $answer->answer = $answer->feedback;
$DB->update_record("question_answers", $answer);
} else {
- $answer->id = $DB->insert_record("question_answers", $answer);
+ $answer->feedback = $question->feedback['text'];
+ $answer->answer = $answer->feedback;
+ $answer->id = $DB->insert_record('question_answers', $answer);
+ $answer->feedback = file_save_draft_area_files($question->feedback['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback['text']));
+ $answer->answer = $answer->feedback;
+ $DB->update_record('question_answers', $answer);
}
return $result;
}
@@ -43,12 +66,14 @@ class question_essay_qtype extends default_questiontype {
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
global $CFG;
- $answers = &$question->options->answers;
- $readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
+ $context = $this->get_context_by_category_id($question->category);
+
+ $answers = &$question->options->answers;
+ $readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
// Only use the rich text editor for the first essay question on a page.
- $formatoptions = new stdClass;
+ $formatoptions = new stdClass;
$formatoptions->noclean = true;
$formatoptions->para = false;
@@ -60,13 +85,12 @@ class question_essay_qtype extends default_questiontype {
$question->questiontextformat,
$formatoptions, $cmoptions->course);
- $image = get_question_image($question);
-
// feedback handling
$feedback = '';
if ($options->feedback && !empty($answers)) {
foreach ($answers as $answer) {
- $feedback = format_text($answer->feedback, '', $formatoptions, $cmoptions->course);
+ $feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'qtype_essay', 'feedback', array($state->attempt, $state->question), $answer->id);
+ $feedback = format_text($feedback, $answer->feedbackformat, $formatoptions, $cmoptions->course);
}
}
@@ -139,6 +163,54 @@ class question_essay_qtype extends default_questiontype {
return $this->save_question($question, $form, $course);
}
+ /**
+ * When move the category of questions, the belonging files should be moved as well
+ * @param object $question, question information
+ * @param object $newcategory, target category information
+ */
+ function move_files($question, $newcategory) {
+ global $DB;
+ parent::move_files($question, $newcategory);
+
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+ $component = 'question';
+ $filearea = 'answerfeedback';
+ foreach ($oldanswers as $answer) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+ }
+
+ function check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args) {
+ if ($component == 'question' && $filearea == 'answerfeedback') {
+
+ $answerid = reset($args); // itemid is answer id.
+ $answers = &$question->options->answers;
+ if (isset($state->responses[''])) {
+ $response = $state->responses[''];
+ } else {
+ $response = '';
+ }
+
+ return $options->feedback && !empty($response);
+
+ } else {
+ return parent::check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args);
+ }
+ }
// Restore method not needed.
}
//// END OF CLASS ////
@@ -147,4 +219,3 @@ class question_essay_qtype extends default_questiontype {
//// INITIATION - Without this line the question type is not in use... ///
//////////////////////////////////////////////////////////////////////////
question_register_questiontype(new question_essay_qtype());
-
diff --git a/question/type/match/db/install.xml b/question/type/match/db/install.xml
index 78cb64986a0..cb0ba92ac31 100644
--- a/question/type/match/db/install.xml
+++ b/question/type/match/db/install.xml
@@ -1,5 +1,8 @@
-
+
@@ -18,8 +21,9 @@
-
-
+
+
+
@@ -27,4 +31,4 @@
-
+
\ No newline at end of file
diff --git a/question/type/match/db/upgrade.php b/question/type/match/db/upgrade.php
new file mode 100644
index 00000000000..f634514b455
--- /dev/null
+++ b/question/type/match/db/upgrade.php
@@ -0,0 +1,58 @@
+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;
+}
diff --git a/question/type/match/display.html b/question/type/match/display.html
index 828262a7406..c55cfd60c8e 100644
--- a/question/type/match/display.html
+++ b/question/type/match/display.html
@@ -2,10 +2,6 @@
-
-
-
-
diff --git a/question/type/match/edit_match_form.php b/question/type/match/edit_match_form.php
index 880bc5966d6..75f27739dbd 100644
--- a/question/type/match/edit_match_form.php
+++ b/question/type/match/edit_match_form.php
@@ -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++;
diff --git a/question/type/match/lib.php b/question/type/match/lib.php
new file mode 100644
index 00000000000..e51349e159c
--- /dev/null
+++ b/question/type/match/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * Serve question type files
+ *
+ * @since 2.0
+ * @package questionbank
+ * @subpackage questiontypes
+ * @author Dongsheng Cai
+ * @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);
+}
diff --git a/question/type/match/questiontype.php b/question/type/match/questiontype.php
index f1bbe5ed385..be01f1c539e 100644
--- a/question/type/match/questiontype.php
+++ b/question/type/match/questiontype.php
@@ -1,5 +1,20 @@
.
+
/////////////
/// MATCH ///
/////////////
@@ -24,6 +39,7 @@ class question_match_qtype extends default_questiontype {
function save_question_options($question) {
global $DB;
+ $context = $question->context;
$result = new stdClass;
if (!$oldsubquestions = $DB->get_records("question_match_sub", array("question" => $question->id), "id ASC")) {
@@ -35,24 +51,30 @@ class question_match_qtype extends default_questiontype {
// Insert all the new question+answer pairs
foreach ($question->subquestions as $key => $questiontext) {
- $questiontext = trim($questiontext);
+ $itemid = $questiontext['itemid'];
+ $format = $questiontext['format'];
+ $questiontext = trim($questiontext['text']);
$answertext = trim($question->subanswers[$key]);
if ($questiontext != '' || $answertext != '') {
if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it
- $subquestion->questiontext = $questiontext;
$subquestion->answertext = $answertext;
+ $subquestion->questiontext = file_save_draft_area_files($itemid, $context->id, 'qtype_match', 'subquestion', $subquestion->id, self::$fileoptions, $questiontext);
+ $subquestion->questiontextformat = $format;
$DB->update_record("question_match_sub", $subquestion);
} else {
$subquestion = new stdClass;
// Determine a unique random code
- $subquestion->code = rand(1,999999999);
+ $subquestion->code = rand(1, 999999999);
while ($DB->record_exists('question_match_sub', array('code' => $subquestion->code, 'question' => $question->id))) {
$subquestion->code = rand();
}
$subquestion->question = $question->id;
$subquestion->questiontext = $questiontext;
- $subquestion->answertext = $answertext;
+ $subquestion->questiontextformat = $format;
+ $subquestion->answertext = $answertext;
$subquestion->id = $DB->insert_record("question_match_sub", $subquestion);
+ $questiontext = file_save_draft_area_files($itemid, $context->id, 'qtype_match', 'subquestion', $subquestion->id, self::$fileoptions, $questiontext);
+ $DB->set_field('question_match_sub', 'questiontext', $questiontext, array('id'=>$subquestion->id));
}
$subquestions[] = $subquestion->id;
}
@@ -228,6 +250,7 @@ class question_match_qtype extends default_questiontype {
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
global $CFG, $OUTPUT;
+ $context = $this->get_context_by_category_id($question->category);
$subquestions = $state->options->subquestions;
$correctanswers = $this->get_correct_responses($question, $state);
$nameprefix = $question->name_prefix;
@@ -263,15 +286,14 @@ class question_match_qtype extends default_questiontype {
// Print formulation
$questiontext = $this->format_text($question->questiontext,
$question->questiontextformat, $cmoptions);
- $image = get_question_image($question);
// Print the input controls
foreach ($subquestions as $key => $subquestion) {
if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) {
// Subquestion text:
$a = new stdClass;
- $a->text = $this->format_text($subquestion->questiontext,
- $question->questiontextformat, $cmoptions);
+ $text = quiz_rewrite_question_urls($subquestion->questiontext, 'pluginfile.php', $context->id, 'qtype_match', 'subquestion', array($state->attempt, $state->question), $subquestion->id);
+ $a->text = $this->format_text($text, $subquestion->questiontextformat, $cmoptions);
// Drop-down list:
$menuname = $nameprefix.$subquestion->id;
@@ -757,6 +779,53 @@ class question_match_qtype extends default_questiontype {
return $this->save_question($question, $form, $course);
}
+
+ function move_files($question, $newcategory) {
+ global $DB;
+ // move files belonging to question component
+ parent::move_files($question, $newcategory);
+
+ // move files belonging to qtype_multichoice
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+
+ // process files in sub questions
+ if (!$subquestions = $DB->get_records('question_match_sub', array('question' => $question->id), 'id ASC')) {
+ $subquestions = array();
+ }
+ $component = 'qtype_match';
+ $filearea = 'subquestion';
+ foreach ($subquestions as $sub) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $sub->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+ }
+ function check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args) {
+
+ $itemid = reset($args);
+ if ($filearea == 'subquestion') {
+ // always display quetion images
+ // itemid is sub question id
+ if ($itemid != $question->id) {
+ return false;
+ }
+ return true;
+ } else {
+ return parent::check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args);
+ }
+ }
}
//// END OF CLASS ////
@@ -764,4 +833,3 @@ class question_match_qtype extends default_questiontype {
//// INITIATION - Without this line the question type is not in use... ///
//////////////////////////////////////////////////////////////////////////
question_register_questiontype(new question_match_qtype());
-
diff --git a/question/type/match/version.php b/question/type/match/version.php
index 1950094efc8..5b5cd5e0437 100644
--- a/question/type/match/version.php
+++ b/question/type/match/version.php
@@ -1,6 +1,6 @@
version = 2006032200;
+$plugin->version = 2009072100;
$plugin->requires = 2007101000;
diff --git a/question/type/missingtype/display.html b/question/type/missingtype/display.html
index e4ebf658935..01d65085e2e 100644
--- a/question/type/missingtype/display.html
+++ b/question/type/missingtype/display.html
@@ -2,10 +2,6 @@
-
-
-
-
@@ -21,4 +17,4 @@
-
\ No newline at end of file
+
diff --git a/question/type/missingtype/questiontype.php b/question/type/missingtype/questiontype.php
index e0422d474ba..d0d450a1538 100644
--- a/question/type/missingtype/questiontype.php
+++ b/question/type/missingtype/questiontype.php
@@ -42,7 +42,6 @@ class question_missingtype_qtype extends default_questiontype {
$questiontext = format_text($question->questiontext,
$question->questiontextformat,
$formatoptions, $cmoptions->course);
- $image = get_question_image($question);
// Print each answer in a separate row if there are any
$anss = array();
diff --git a/question/type/multianswer/edit_multianswer_form.php b/question/type/multianswer/edit_multianswer_form.php
index 151f745dc4d..fd88cb74c16 100644
--- a/question/type/multianswer/edit_multianswer_form.php
+++ b/question/type/multianswer/edit_multianswer_form.php
@@ -15,15 +15,15 @@
class question_edit_multianswer_form extends question_edit_form {
// $questiondisplay will contain the qtype_multianswer_extract_question from the questiontext
- var $questiondisplay ;
+ public $questiondisplay ;
// $savedquestiondisplay will contain the qtype_multianswer_extract_question from the questiontext in database
- var $savedquestion ;
- var $savedquestiondisplay ;
- var $used_in_quiz = false ;
- var $qtype_change = false ;
- var $negative_diff = 0 ;
- var $nb_of_quiz = 0;
- var $nb_of_attempts = 0;
+ public $savedquestion ;
+ public $savedquestiondisplay ;
+ public $used_in_quiz = false ;
+ public $qtype_change = false ;
+ public $negative_diff = 0 ;
+ public $nb_of_quiz = 0;
+ public $nb_of_attempts = 0;
public $confirm = 0 ;
public $reload = false ;
@@ -35,9 +35,9 @@ class question_edit_multianswer_form extends question_edit_form {
}else {
$this->reload = false ;
}
- // $this->question = $question;
- $this->used_in_quiz =false;
- // echo " question
";print_r($question);echo "
";
+ // $this->question = $question;
+ $this->used_in_quiz =false;
+ // echo " question
";print_r($question);echo "
";
if(isset($question->id) && $question->id != 0 ){
$this->savedquestiondisplay =fullclone($question ) ;
if ($list = $DB->get_records('quiz_question_instances', array( 'question'=> $question->id))){
@@ -51,15 +51,9 @@ class question_edit_multianswer_form extends question_edit_form {
}
}
-
-
-
-
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
}
-
-
function definition_inner(&$mform) {
$mform->addElement('hidden', 'reload', 1);
$mform->setType('reload', PARAM_INT);
@@ -69,7 +63,7 @@ class question_edit_multianswer_form extends question_edit_form {
$mform->removeElement('defaultgrade');
$this->confirm = optional_param('confirm','0', PARAM_RAW);
- // display the questions from questiontext;
+ // display the questions from questiontext;
if ( "" != optional_param('questiontext','', PARAM_RAW)) {
$this->questiondisplay = fullclone(qtype_multianswer_extract_question(optional_param('questiontext','', PARAM_RAW))) ;
@@ -80,14 +74,14 @@ class question_edit_multianswer_form extends question_edit_form {
// question->id == 0 so no stored datasets
$this->questiondisplay = fullclone($this->savedquestiondisplay);
foreach($this->questiondisplay->options->questions as $subquestion){
- if (!empty($subquestion)){
- $subquestion->answer = array('');
- foreach($subquestion->options->answers as $ans){
- $subquestion->answer[]=$ans->answer ;
+ if (!empty($subquestion)){
+ $subquestion->answer = array('');
+ foreach($subquestion->options->answers as $ans){
+ $subquestion->answer[]=$ans->answer ;
+ }
+ // $subquestion->answer = fullclone($subquestion->options->answers);
}
- // $subquestion->answer = fullclone($subquestion->options->answers);
}
- }
}else {
$this->questiondisplay = "";
}
@@ -97,7 +91,7 @@ class question_edit_multianswer_form extends question_edit_form {
$countsavedsubquestions =0;
foreach($this->savedquestiondisplay->options->questions as $subquestion){
if (!empty($subquestion)){
- $countsavedsubquestions++;
+ $countsavedsubquestions++;
}
}
} else {
@@ -108,24 +102,24 @@ class question_edit_multianswer_form extends question_edit_form {
$countsubquestions =0;
foreach($this->questiondisplay->options->questions as $subquestion){
if (!empty($subquestion)){
- $countsubquestions++;
+ $countsubquestions++;
}
}
- } else {
- $countsubquestions =0;
- }
- }else{
- $countsubquestions =$countsavedsubquestions ;
+ } else {
+ $countsubquestions =0;
}
- // echo " saved question $countsavedsubquestions
";print_r($this->savedquestiondisplay);echo "
";
- // echo " saved question $countsubquestions
";print_r($this->questiondisplay);echo "
";
+ }else{
+ $countsubquestions =$countsavedsubquestions ;
+ }
+ // echo " saved question $countsavedsubquestions
";print_r($this->savedquestiondisplay);echo "
";
+ // echo " saved question $countsubquestions
";print_r($this->questiondisplay);echo "
";
- $mform->addElement('submit', 'analyzequestion', get_string('decodeverifyquestiontext','qtype_multianswer'));
- $mform->registerNoSubmitButton('analyzequestion');
- echo '';
- echo '';
- if ( $this->reload ){
+ $mform->addElement('submit', 'analyzequestion', get_string('decodeverifyquestiontext','qtype_multianswer'));
+ $mform->registerNoSubmitButton('analyzequestion');
+ echo '';
+ echo '';
+ if ( $this->reload ){
for ($sub =1;$sub <=$countsubquestions ;$sub++) {
$this->editas[$sub] = 'unknown type';
@@ -135,14 +129,14 @@ class question_edit_multianswer_form extends question_edit_form {
$this->editas[$sub] = optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW);
}
$storemess = '';
- if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
- $this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
- $this->qtype_change = true ;
- $storemess = " STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype]."";
- }
+ if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
+ $this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
+ $this->qtype_change = true ;
+ $storemess = " STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype]."";
+ }
$mform->addElement('header', 'subhdr'.$sub, get_string('questionno', 'quiz',
- '{#'.$sub.'}').' '.$question_type_names[$this->questiondisplay->options->questions[$sub]->qtype].$storemess);
+ '{#'.$sub.'}').' '.$question_type_names[$this->questiondisplay->options->questions[$sub]->qtype].$storemess);
$mform->addElement('static', 'sub_'.$sub."_".'questiontext', get_string('questiondefinition','qtype_multianswer'),array('cols'=>60, 'rows'=>3));
@@ -153,16 +147,16 @@ class question_edit_multianswer_form extends question_edit_form {
$mform->addElement('static', 'sub_'.$sub."_".'defaultgrade', get_string('defaultgrade', 'quiz'));
$mform->setDefault('sub_'.$sub."_".'defaultgrade',$this->questiondisplay->options->questions[$sub]->defaultgrade);
- if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
- $mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'quiz'));
- }
+ if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
+ $mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'quiz'));
+ }
- if ($this->questiondisplay->options->questions[$sub]->qtype =='multichoice' ) {
- $mform->addElement('static', 'sub_'.$sub."_".'layout', get_string('layout', 'qtype_multianswer'),array('cols'=>60, 'rows'=>1)) ;//, $gradeoptions);
- }
+ if ($this->questiondisplay->options->questions[$sub]->qtype =='multichoice' ) {
+ $mform->addElement('static', 'sub_'.$sub."_".'layout', get_string('layout', 'qtype_multianswer'),array('cols'=>60, 'rows'=>1)) ;//, $gradeoptions);
+ }
foreach ($this->questiondisplay->options->questions[$sub]->answer as $key =>$ans) {
- $mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']', get_string('answer', 'quiz'), array('cols'=>60, 'rows'=>1));
+ $mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']', get_string('answer', 'quiz'), array('cols'=>60, 'rows'=>1));
if ($this->questiondisplay->options->questions[$sub]->qtype =='numerical' && $key == 0 ) {
$mform->addElement('static', 'sub_'.$sub."_".'tolerance['.$key.']', get_string('acceptederror', 'quiz')) ;//, $gradeoptions);
@@ -177,16 +171,14 @@ class question_edit_multianswer_form extends question_edit_form {
echo '';
$this->negative_diff =$countsavedsubquestions - $countsubquestions ;
if ( ($this->negative_diff > 0 ) ||$this->qtype_change || ($this->used_in_quiz && $this->negative_diff != 0)){
- $mform->addElement('header', 'additemhdr', get_string('warningquestionmodified','qtype_multianswer'));
- }
+ $mform->addElement('header', 'additemhdr', get_string('warningquestionmodified','qtype_multianswer'));
+ }
if($this->negative_diff > 0) {
//$this->used_in_quiz
-
- $mform->addElement('static', 'alert1', "".get_string('questiondeleted','qtype_multianswer')."",get_string('questionsless','qtype_multianswer',$this->negative_diff));
+ $mform->addElement('static', 'alert1', "".get_string('questiondeleted','qtype_multianswer')."",get_string('questionsless','qtype_multianswer',$this->negative_diff));
}
- if($this->qtype_change )
- {
- $mform->addElement('static', 'alert1', "".get_string('questiontypechanged','qtype_multianswer')."",get_string('questiontypechangedcomment','qtype_multianswer'));
+ if($this->qtype_change ) {
+ $mform->addElement('static', 'alert1', "".get_string('questiontypechanged','qtype_multianswer')."",get_string('questiontypechangedcomment','qtype_multianswer'));
}
echo '';
}
@@ -219,11 +211,11 @@ class question_edit_multianswer_form extends question_edit_form {
foreach ($question->options->questions as $key => $wrapped) {
if(!empty($wrapped)){
- // The old way of restoring the definitions is kept to gradually
- // update all multianswer questions
- if (empty($wrapped->questiontext)) {
- $parsableanswerdef = '{' . $wrapped->defaultgrade . ':';
- switch ($wrapped->qtype) {
+ // The old way of restoring the definitions is kept to gradually
+ // update all multianswer questions
+ if (empty($wrapped->questiontext)) {
+ $parsableanswerdef = '{' . $wrapped->defaultgrade . ':';
+ switch ($wrapped->qtype) {
case 'multichoice':
$parsableanswerdef .= 'MULTICHOICE:';
break;
@@ -235,62 +227,62 @@ class question_edit_multianswer_form extends question_edit_form {
break;
default:
print_error('unknownquestiontype', 'question', '', $wrapped->qtype);
- }
- $separator= '';
- foreach ($wrapped->options->answers as $subanswer) {
- $parsableanswerdef .= $separator
+ }
+ $separator= '';
+ foreach ($wrapped->options->answers as $subanswer) {
+ $parsableanswerdef .= $separator
. '%' . round(100*$subanswer->fraction) . '%';
- $parsableanswerdef .= $subanswer->answer;
- if (!empty($wrapped->options->tolerance)) {
- // Special for numerical answers:
- $parsableanswerdef .= ":{$wrapped->options->tolerance}";
- // We only want tolerance for the first alternative, it will
- // be applied to all of the alternatives.
- unset($wrapped->options->tolerance);
+ $parsableanswerdef .= $subanswer->answer;
+ if (!empty($wrapped->options->tolerance)) {
+ // Special for numerical answers:
+ $parsableanswerdef .= ":{$wrapped->options->tolerance}";
+ // We only want tolerance for the first alternative, it will
+ // be applied to all of the alternatives.
+ unset($wrapped->options->tolerance);
+ }
+ if ($subanswer->feedback) {
+ $parsableanswerdef .= "#$subanswer->feedback";
+ }
+ $separator = '~';
}
- if ($subanswer->feedback) {
- $parsableanswerdef .= "#$subanswer->feedback";
- }
- $separator = '~';
+ $parsableanswerdef .= '}';
+ // Fix the questiontext fields of old questions
+ $DB->set_field('question', 'questiontext', $parsableanswerdef, array('id' => $wrapped->id));
+ } else {
+ $parsableanswerdef = str_replace('', '&\#', $wrapped->questiontext);
}
- $parsableanswerdef .= '}';
- // Fix the questiontext fields of old questions
- $DB->set_field('question', 'questiontext', $parsableanswerdef, array('id' => $wrapped->id));
- } else {
- $parsableanswerdef = str_replace('', '&\#', $wrapped->questiontext);
+ $question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
}
- $question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
}
}
- }
// set default to $questiondisplay questions elements
if ( $this->reload ){
- if (isset($this->questiondisplay->options->questions)) {
- $subquestions = fullclone($this->questiondisplay->options->questions) ;
- if (count($subquestions)) {
- $sub =1;
- foreach ($subquestions as $subquestion) {
- $prefix = 'sub_'.$sub.'_' ;
+ if (isset($this->questiondisplay->options->questions)) {
+ $subquestions = fullclone($this->questiondisplay->options->questions) ;
+ if (count($subquestions)) {
+ $sub =1;
+ foreach ($subquestions as $subquestion) {
+ $prefix = 'sub_'.$sub.'_' ;
- // validate parameters
- $answercount = 0;
- $maxgrade = false;
- $maxfraction = -1;
- if ($subquestion->qtype =='shortanswer' ) {
- switch ($subquestion->usecase) {
+ // validate parameters
+ $answercount = 0;
+ $maxgrade = false;
+ $maxfraction = -1;
+ if ($subquestion->qtype =='shortanswer' ) {
+ switch ($subquestion->usecase) {
case '1':
$default_values[$prefix.'usecase']= get_string('caseyes', 'quiz');
break;
case '0':
default :
$default_values[$prefix.'usecase']= get_string('caseno', 'quiz');
+ }
}
- }
- if ($subquestion->qtype == 'multichoice' ) {
- $default_values[$prefix.'layout'] = $subquestion->layout ;
- switch ($subquestion->layout) {
+ if ($subquestion->qtype == 'multichoice' ) {
+ $default_values[$prefix.'layout'] = $subquestion->layout ;
+ switch ($subquestion->layout) {
case '0':
$default_values[$prefix.'layout']= get_string('layoutselectinline', 'qtype_multianswer');
break;
@@ -302,53 +294,53 @@ class question_edit_multianswer_form extends question_edit_form {
break;
default:
$default_values[$prefix.'layout']= get_string('layoutundefined', 'qtype_multianswer');
- }
- }
- foreach ($subquestion->answer as $key=>$answer) {
- if ( $subquestion->qtype == 'numerical' && $key == 0 ) {
- $default_values[$prefix.'tolerance['.$key.']'] = $subquestion->tolerance[0] ;
- }
- $trimmedanswer = trim($answer);
- if ($trimmedanswer !== '') {
- $answercount++;
- if ($subquestion->qtype == 'numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
- $this->_form->setElementError($prefix.'answer['.$key.']' , get_string('answermustbenumberorstar', 'qtype_numerical'));
- }
- if ($subquestion->fraction[$key] == 1) {
- $maxgrade = true;
- }
- if ($subquestion->fraction[$key] > $maxfraction) {
- $maxfraction = $subquestion->fraction[$key] ;
}
}
+ foreach ($subquestion->answer as $key=>$answer) {
+ if ( $subquestion->qtype == 'numerical' && $key == 0 ) {
+ $default_values[$prefix.'tolerance['.$key.']'] = $subquestion->tolerance[0] ;
+ }
+ $trimmedanswer = trim($answer);
+ if ($trimmedanswer !== '') {
+ $answercount++;
+ if ($subquestion->qtype == 'numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
+ $this->_form->setElementError($prefix.'answer['.$key.']' , get_string('answermustbenumberorstar', 'qtype_numerical'));
+ }
+ if ($subquestion->fraction[$key] == 1) {
+ $maxgrade = true;
+ }
+ if ($subquestion->fraction[$key] > $maxfraction) {
+ $maxfraction = $subquestion->fraction[$key] ;
+ }
+ }
- $default_values[$prefix.'answer['.$key.']'] = htmlspecialchars ($answer);
- }
- if ($answercount == 0) {
- if ($subquestion->qtype == 'multichoice' ) {
- $this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'qtype_multichoice', 2));
- } else {
- $this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'quiz', 1));
+ $default_values[$prefix.'answer['.$key.']'] = htmlspecialchars ($answer);
}
- }
- if ($maxgrade == false) {
- $this->_form->setElementError($prefix.'fraction[0]' ,get_string('fractionsnomax', 'question'));
- }
- foreach ($subquestion->feedback as $key=>$answer) {
+ if ($answercount == 0) {
+ if ($subquestion->qtype == 'multichoice' ) {
+ $this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'qtype_multichoice', 2));
+ } else {
+ $this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'quiz', 1));
+ }
+ }
+ if ($maxgrade == false) {
+ $this->_form->setElementError($prefix.'fraction[0]' ,get_string('fractionsnomax', 'question'));
+ }
+ foreach ($subquestion->feedback as $key=>$answer) {
- $default_values[$prefix.'feedback['.$key.']'] = htmlspecialchars ($answer);
- }
- foreach ( $subquestion->fraction as $key=>$answer) {
- $default_values[$prefix.'fraction['.$key.']'] = $answer;
- }
+ $default_values[$prefix.'feedback['.$key.']'] = htmlspecialchars ($answer);
+ }
+ foreach ( $subquestion->fraction as $key=>$answer) {
+ $default_values[$prefix.'fraction['.$key.']'] = $answer;
+ }
- $sub++;
+ $sub++;
+ }
}
}
}
- }
- $default_values['alertas']= "".get_string('questioninquiz','qtype_multianswer')."";
+ $default_values['alertas']= "".get_string('questioninquiz','qtype_multianswer')."";
if( $default_values != "") {
$question = (object)((array)$question + $default_values);
@@ -358,14 +350,11 @@ class question_edit_multianswer_form extends question_edit_form {
function validation($data, $files) {
$errors = parent::validation($data, $files);
-
- $questiondisplay = qtype_multianswer_extract_question($data['questiontext']) ;
-
+ $questiondisplay = qtype_multianswer_extract_question($data['questiontext']['text']);
if (isset($questiondisplay->options->questions)) {
-
- $subquestions = fullclone($questiondisplay->options->questions) ;
+ $subquestions = fullclone($questiondisplay->options->questions) ;
if (count($subquestions)) {
$sub =1;
foreach ($subquestions as $subquestion) {
@@ -373,17 +362,17 @@ class question_edit_multianswer_form extends question_edit_form {
$answercount = 0;
$maxgrade = false;
$maxfraction = -1;
- if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
- $this->savedquestiondisplay->options->questions[$sub]->qtype != $questiondisplay->options->questions[$sub]->qtype ){
- $storemess = " STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype];
- }
+ if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
+ $this->savedquestiondisplay->options->questions[$sub]->qtype != $questiondisplay->options->questions[$sub]->qtype ){
+ $storemess = " STORED QTYPE ".$question_type_names[$this->savedquestiondisplay->options->questions[$sub]->qtype];
+ }
foreach ( $subquestion->answer as $key=>$answer) {
$trimmedanswer = trim($answer);
if ($trimmedanswer !== '') {
$answercount++;
if ($subquestion->qtype =='numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
$errors[$prefix.'answer['.$key.']']= get_string('answermustbenumberorstar', 'qtype_numerical');
- }
+ }
if ($subquestion->fraction[$key] == 1) {
$maxgrade = true;
}
@@ -408,18 +397,17 @@ class question_edit_multianswer_form extends question_edit_form {
$errors['questiontext']=get_string('questionsmissing', 'qtype_multianswer');
}
}
- // $question = qtype_multianswer_extract_question($data['questiontext']);
- // if (isset $question->options->questions
+ // $question = qtype_multianswer_extract_question($data['questiontext']);
+ // if (isset $question->options->questions
if (( $this->negative_diff > 0 || $this->used_in_quiz && ($this->negative_diff > 0 ||$this->negative_diff < 0 || $this->qtype_change ))&& $this->confirm == 0 ){
- $errors['confirm']=get_string('confirmsave', 'qtype_multianswer',$this->negative_diff);
+ $errors['confirm']=get_string('confirmsave', 'qtype_multianswer',$this->negative_diff);
}
-
- return $errors;
+
+ return $errors;
}
function qtype() {
return 'multianswer';
}
}
-
diff --git a/question/type/multianswer/questiontype.php b/question/type/multianswer/questiontype.php
index e2786b4f39f..35f51e88d09 100644
--- a/question/type/multianswer/questiontype.php
+++ b/question/type/multianswer/questiontype.php
@@ -307,10 +307,6 @@ class embedded_cloze_qtype extends default_questiontype {
}
echo '';
- // For this question type, we better print the image on top:
- if ($image = get_question_image($question)) {
- echo('
');
- }
$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;
}
-?>
diff --git a/question/type/multichoice/db/install.xml b/question/type/multichoice/db/install.xml
index 8a50ff9d036..da93831b65c 100644
--- a/question/type/multichoice/db/install.xml
+++ b/question/type/multichoice/db/install.xml
@@ -1,5 +1,5 @@
-
@@ -12,10 +12,13 @@
-
-
-
-
+
+
+
+
+
+
+
@@ -23,4 +26,4 @@
-
+
\ No newline at end of file
diff --git a/question/type/multichoice/db/upgrade.php b/question/type/multichoice/db/upgrade.php
index bbd4dcfea63..04e31965c86 100644
--- a/question/type/multichoice/db/upgrade.php
+++ b/question/type/multichoice/db/upgrade.php
@@ -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;
}
diff --git a/question/type/multichoice/display.html b/question/type/multichoice/display.html
index 5e4f66d6cd9..9acf11fd914 100644
--- a/question/type/multichoice/display.html
+++ b/question/type/multichoice/display.html
@@ -2,10 +2,6 @@
-
-
-
-
diff --git a/question/type/multichoice/edit_multichoice_form.php b/question/type/multichoice/edit_multichoice_form.php
index f25a4eeec9e..e062fc68126 100644
--- a/question/type/multichoice/edit_multichoice_form.php
+++ b/question/type/multichoice/edit_multichoice_form.php
@@ -1,4 +1,22 @@
.
+
+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() {
diff --git a/question/type/multichoice/lib.php b/question/type/multichoice/lib.php
new file mode 100644
index 00000000000..5852ecaeef8
--- /dev/null
+++ b/question/type/multichoice/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * Serve question type files
+ *
+ * @since 2.0
+ * @package questionbank
+ * @subpackage questiontypes
+ * @author Dongsheng Cai
+ * @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);
+}
diff --git a/question/type/multichoice/questiontype.php b/question/type/multichoice/questiontype.php
index 856b59af9a8..c3843776987 100644
--- a/question/type/multichoice/questiontype.php
+++ b/question/type/multichoice/questiontype.php
@@ -29,8 +29,8 @@ class question_multichoice_qtype extends default_questiontype {
list ($usql, $params) = $DB->get_in_or_equal(explode(',', $question->options->answers));
if (!$question->options->answers = $DB->get_records_select('question_answers', "id $usql", $params, 'id')) {
- echo $OUTPUT->notification('Error: Missing question answers for multichoice question'.$question->id.'!');
- return false;
+ echo $OUTPUT->notification('Error: Missing question answers for multichoice question'.$question->id.'!');
+ return false;
}
return true;
@@ -38,6 +38,7 @@ class question_multichoice_qtype extends default_questiontype {
function save_question_options($question) {
global $DB;
+ $context = $question->context;
$result = new stdClass;
if (!$oldanswers = $DB->get_records("question_answers", array("question" => $question->id), "id ASC")) {
$oldanswers = array();
@@ -65,18 +66,23 @@ class question_multichoice_qtype extends default_questiontype {
foreach ($question->answer as $key => $dataanswer) {
if ($dataanswer != "") {
+ $feedbackformat = $question->feedback[$key]['format'];
if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it
$answer->answer = $dataanswer;
$answer->fraction = $question->fraction[$key];
- $answer->feedback = $question->feedback[$key];
+ $answer->feedbackformat = $feedbackformat;
+ $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']);
$DB->update_record("question_answers", $answer);
} else {
unset($answer);
$answer->answer = $dataanswer;
$answer->question = $question->id;
$answer->fraction = $question->fraction[$key];
- $answer->feedback = $question->feedback[$key];
+ $answer->feedback = '';
+ $answer->feedbackformat = $feedbackformat;
$answer->id = $DB->insert_record("question_answers", $answer);
+ $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']);
+ $DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id));
}
$answers[] = $answer->id;
@@ -100,13 +106,19 @@ class question_multichoice_qtype extends default_questiontype {
$options->answers = implode(",",$answers);
$options->single = $question->single;
if(isset($question->layout)){
- $options->layout = $question->layout;
+ $options->layout = $question->layout;
}
$options->answernumbering = $question->answernumbering;
$options->shuffleanswers = $question->shuffleanswers;
- $options->correctfeedback = trim($question->correctfeedback);
- $options->partiallycorrectfeedback = trim($question->partiallycorrectfeedback);
- $options->incorrectfeedback = trim($question->incorrectfeedback);
+
+ foreach (array('correct', 'partiallycorrect', 'incorrect') as $feedbacktype) {
+ $feedbackname = $feedbacktype . 'feedback';
+ $feedbackformat = $feedbackname . 'format';
+ $feedback = $question->$feedbackname;
+ $options->$feedbackformat = trim($feedback['format']);
+ $options->$feedbackname = file_save_draft_area_files($feedback['itemid'], $context->id, 'qtype_multichoice', $feedbackname, $question->id, self::$fileoptions, trim($feedback['text']));
+ }
+
if ($update) {
$DB->update_record("question_multichoice", $options);
} else {
@@ -139,11 +151,11 @@ class question_multichoice_qtype extends default_questiontype {
}
/**
- * Deletes question from the question-type specific tables
- *
- * @return boolean Success/Failure
- * @param object $question The question being deleted
- */
+ * Deletes question from the question-type specific tables
+ *
+ * @return boolean Success/Failure
+ * @param object $question The question being deleted
+ */
function delete_question($questionid) {
global $DB;
$DB->delete_records("question_multichoice", array("question" => $questionid));
@@ -153,10 +165,10 @@ class question_multichoice_qtype extends default_questiontype {
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
// create an array of answerids ??? why so complicated ???
$answerids = array_values(array_map(create_function('$val',
- 'return $val->id;'), $question->options->answers));
+ 'return $val->id;'), $question->options->answers));
// Shuffle the answers if required
if (!empty($cmoptions->shuffleanswers) and !empty($question->options->shuffleanswers)) {
- $answerids = swapshuffle($answerids);
+ $answerids = swapshuffle($answerids);
}
$state->options->order = $answerids;
// Create empty responses
@@ -203,7 +215,7 @@ class question_multichoice_qtype extends default_questiontype {
$state->responses = array_flip($state->responses);
// Set the value of each element to be equal to the index
array_walk($state->responses, create_function('&$a, $b',
- '$a = $b;'));
+ '$a = $b;'));
}
}
return true;
@@ -252,6 +264,10 @@ class question_multichoice_qtype extends default_questiontype {
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
global $CFG;
+ // required by file api
+ $context = $this->get_context_by_category_id($question->category);
+ $component = 'qtype_' . $question->qtype;
+
$answers = &$question->options->answers;
$correctanswers = $this->get_correct_responses($question, $state);
$readonly = empty($options->readonly) ? '' : 'disabled="disabled"';
@@ -261,10 +277,8 @@ class question_multichoice_qtype extends default_questiontype {
$formatoptions->para = false;
// Print formulation
- $questiontext = format_text($question->questiontext,
- $question->questiontextformat,
- $formatoptions, $cmoptions->course);
- $image = get_question_image($question);
+ $questiontext = format_text($question->questiontext, $question->questiontextformat,
+ $formatoptions, $cmoptions->course);
$answerprompt = ($question->options->single) ? get_string('singleanswer', 'quiz') :
get_string('multipleanswers', 'quiz');
@@ -311,11 +325,13 @@ class question_multichoice_qtype extends default_questiontype {
// Print the answer text
$a->text = $this->number_in_style($key, $question->options->answernumbering) .
- format_text($answer->answer, FORMAT_MOODLE, $formatoptions, $cmoptions->course);
+ format_text($answer->answer, $answer->answerformat, $formatoptions, $cmoptions->course);
// Print feedback if feedback is on
if (($options->feedback || $options->correct_responses) && $checked) {
- $a->feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
+ // feedback for each answer
+ $a->feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'question', 'answerfeedback', array($state->attempt, $state->question), $answer->id);
+ $a->feedback = format_text($a->feedback, $answer->feedbackformat, $formatoptions, $cmoptions->course);
} else {
$a->feedback = '';
}
@@ -327,14 +343,18 @@ class question_multichoice_qtype extends default_questiontype {
if ($options->feedback) {
if ($state->raw_grade >= $question->maxgrade/1.01) {
$feedback = $question->options->correctfeedback;
+ $feedbacktype = 'correctfeedback';
} else if ($state->raw_grade > 0) {
$feedback = $question->options->partiallycorrectfeedback;
+ $feedbacktype = 'partiallycorrectfeedback';
} else {
$feedback = $question->options->incorrectfeedback;
+ $feedbacktype = 'incorrectfeedback';
}
- $feedback = format_text($feedback,
- $question->questiontextformat,
- $formatoptions, $cmoptions->course);
+
+ $feedback = quiz_rewrite_question_urls($feedback, 'pluginfile.php', $context->id, $component, $feedbacktype, array($state->attempt, $state->question), $question->id);
+ $feedbackformat = $feedbacktype . 'format';
+ $feedback = format_text($feedback, $question->options->$feedbackformat, $formatoptions, $cmoptions->course);
}
include("$CFG->dirroot/question/type/multichoice/display.html");
@@ -357,7 +377,7 @@ class question_multichoice_qtype extends default_questiontype {
// Make sure we don't assign negative or too high marks
$state->raw_grade = min(max((float) $state->raw_grade,
- 0.0), 1.0) * $question->maxgrade;
+ 0.0), 1.0) * $question->maxgrade;
// Apply the penalty for this attempt
$state->penalty = $question->penalty * $question->maxgrade;
@@ -401,7 +421,7 @@ class question_multichoice_qtype extends default_questiontype {
}
return $totalfraction / count($question->options->answers);
}
-/// BACKUP FUNCTIONS ////////////////////////////
+ /// BACKUP FUNCTIONS ////////////////////////////
/*
* Backup the data in the question
@@ -436,7 +456,7 @@ class question_multichoice_qtype extends default_questiontype {
return $status;
}
-/// RESTORE FUNCTIONS /////////////////
+ /// RESTORE FUNCTIONS /////////////////
/*
* Restores the data in the question
@@ -575,31 +595,31 @@ class question_multichoice_qtype extends default_questiontype {
// Decode links in the question_multichoice table.
if ($multichoices = $DB->get_records_list('question_multichoice', 'question',
- $questionids, '', 'id, correctfeedback, partiallycorrectfeedback, incorrectfeedback')) {
+ $questionids, '', 'id, correctfeedback, partiallycorrectfeedback, incorrectfeedback')) {
- foreach ($multichoices as $multichoice) {
- $correctfeedback = restore_decode_content_links_worker($multichoice->correctfeedback, $restore);
- $partiallycorrectfeedback = restore_decode_content_links_worker($multichoice->partiallycorrectfeedback, $restore);
- $incorrectfeedback = restore_decode_content_links_worker($multichoice->incorrectfeedback, $restore);
- if ($correctfeedback != $multichoice->correctfeedback ||
+ foreach ($multichoices as $multichoice) {
+ $correctfeedback = restore_decode_content_links_worker($multichoice->correctfeedback, $restore);
+ $partiallycorrectfeedback = restore_decode_content_links_worker($multichoice->partiallycorrectfeedback, $restore);
+ $incorrectfeedback = restore_decode_content_links_worker($multichoice->incorrectfeedback, $restore);
+ if ($correctfeedback != $multichoice->correctfeedback ||
$partiallycorrectfeedback != $multichoice->partiallycorrectfeedback ||
$incorrectfeedback != $multichoice->incorrectfeedback) {
- $subquestion->correctfeedback = $correctfeedback;
- $subquestion->partiallycorrectfeedback = $partiallycorrectfeedback;
- $subquestion->incorrectfeedback = $incorrectfeedback;
- $DB->update_record('question_multichoice', $multichoice);
- }
+ $subquestion->correctfeedback = $correctfeedback;
+ $subquestion->partiallycorrectfeedback = $partiallycorrectfeedback;
+ $subquestion->incorrectfeedback = $incorrectfeedback;
+ $DB->update_record('question_multichoice', $multichoice);
+ }
- // Do some output.
- if (++$i % 5 == 0 && !defined('RESTORE_SILENTLY')) {
- echo ".";
- if ($i % 100 == 0) {
- echo "
";
+ // Do some output.
+ if (++$i % 5 == 0 && !defined('RESTORE_SILENTLY')) {
+ echo ".";
+ if ($i % 100 == 0) {
+ echo "
";
+ }
+ backup_flush(300);
}
- backup_flush(300);
}
}
- }
return $status;
}
@@ -625,16 +645,16 @@ class question_multichoice_qtype extends default_questiontype {
*/
function number_in_style($num, $style) {
switch($style) {
- case 'abc':
- return $this->number_html(chr(ord('a') + $num));
- case 'ABCD':
- return $this->number_html(chr(ord('A') + $num));
- case '123':
- return $this->number_html(($num + 1));
- case 'none':
- return '';
- default:
- return 'ERR';
+ case 'abc':
+ return $this->number_html(chr(ord('a') + $num));
+ case 'ABCD':
+ return $this->number_html(chr(ord('A') + $num));
+ case '123':
+ return $this->number_html(($num + 1));
+ case 'none':
+ return '';
+ default:
+ return 'ERR';
}
}
@@ -708,8 +728,82 @@ class question_multichoice_qtype extends default_questiontype {
return $this->save_question($question, $form, $course);
}
+ /**
+ * When move the category of questions, the belonging files should be moved as well
+ * @param object $question, question information
+ * @param object $newcategory, target category information
+ */
+ function move_files($question, $newcategory) {
+ global $DB;
+ // move files belonging to question component
+ parent::move_files($question, $newcategory);
+
+ // move files belonging to qtype_multichoice
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+ $component = 'question';
+ $filearea = 'answerfeedback';
+ foreach ($oldanswers as $answer) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+
+ $component = 'qtype_multichoice';
+ foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $filearea) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+ }
+
+ function check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args) {
+ $itemid = reset($args);
+
+ if (empty($question->maxgrade)) {
+ $question->maxgrade = $question->defaultgrade;
+ }
+
+ if (in_array($filearea, array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'))) {
+ $result = $options->feedback && ($itemid == $question->id);
+ if (!$result) {
+ return false;
+ }
+ if ($state->raw_grade >= $question->maxgrade/1.01) {
+ $feedbacktype = 'correctfeedback';
+ } else if ($state->raw_grade > 0) {
+ $feedbacktype = 'partiallycorrectfeedback';
+ } else {
+ $feedbacktype = 'incorrectfeedback';
+ }
+ if ($feedbacktype != $filearea) {
+ return false;
+ }
+ return true;
+ } else if ($component == 'question' && $filearea == 'answerfeedback') {
+ return $options->feedback && (array_key_exists($itemid, $question->options->answers));
+ } else {
+ return parent::check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args);
+ }
+ }
}
// Register this question type with the question bank.
question_register_questiontype(new question_multichoice_qtype());
-
diff --git a/question/type/multichoice/version.php b/question/type/multichoice/version.php
index 0d354e821d2..c0b4d8672c8 100644
--- a/question/type/multichoice/version.php
+++ b/question/type/multichoice/version.php
@@ -1,6 +1,6 @@
version = 2009021800;
+$plugin->version = 2009021801;
$plugin->requires = 2007101000;
diff --git a/question/type/numerical/db/install.xml b/question/type/numerical/db/install.xml
index 735fc4b4660..c4f3ee44a05 100644
--- a/question/type/numerical/db/install.xml
+++ b/question/type/numerical/db/install.xml
@@ -1,5 +1,5 @@
-
@@ -23,8 +23,9 @@
-
-
+
+
+
@@ -50,4 +51,4 @@
-
+
\ No newline at end of file
diff --git a/question/type/numerical/db/upgrade.php b/question/type/numerical/db/upgrade.php
index d2ff825cbd5..96b547a5993 100644
--- a/question/type/numerical/db/upgrade.php
+++ b/question/type/numerical/db/upgrade.php
@@ -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;
}
diff --git a/question/type/numerical/display.html b/question/type/numerical/display.html
index 4262283926d..c81bd1e7a64 100644
--- a/question/type/numerical/display.html
+++ b/question/type/numerical/display.html
@@ -2,10 +2,6 @@
-
-
-
-
@@ -237,7 +233,7 @@
options->instructions)){?>
- options->instructions, true, $formatoptions, $cmoptions->course);?>
+ options->instructions, $question->options->instructionsformat, $formatoptions, $cmoptions->course);?>
@@ -250,5 +246,3 @@
print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
-
-
diff --git a/question/type/numerical/edit_numerical_form.php b/question/type/numerical/edit_numerical_form.php
index 598e0c79b01..8ed3aff89ea 100644
--- a/question/type/numerical/edit_numerical_form.php
+++ b/question/type/numerical/edit_numerical_form.php
@@ -1,4 +1,20 @@
.
+
/**
* Defines the editing form for the numerical question type.
*
@@ -39,30 +55,36 @@ class question_edit_numerical_form extends question_edit_form {
$creategrades->gradeoptions);
//------------------------------------------------------------------------------------------
$QTYPES['numerical']->add_units_options($mform,$this);
- $QTYPES['numerical']->add_units_elements($mform,$this);
+ $QTYPES['numerical']->add_units_elements($mform,$this);
}
- function set_data($question) {
- global $QTYPES ;
+ function data_preprocessing($question) {
+ global $QTYPES ;
if (isset($question->options)){
- /* $default_values['unitgradingtype'] = $question->options->unitgradingtype ;
- $default_values['unitpenalty'] = $question->options->unitpenalty ;
- $default_values['showunits'] = $question->options->showunits ;
- $default_values['unitsleft'] = $question->options->unitsleft ;
- $default_values['instructions'] = $question->options->instructions ;
-*/
$answers = $question->options->answers;
if (count($answers)) {
$key = 0;
foreach ($answers as $answer){
+ $draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
$default_values['answer['.$key.']'] = $answer->answer;
$default_values['fraction['.$key.']'] = $answer->fraction;
$default_values['tolerance['.$key.']'] = $answer->tolerance;
- $default_values['feedback['.$key.']'] = $answer->feedback;
+ $default_values['feedback['.$key.']'] = array();
+ $default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
+ $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
+ $draftid, // draftid
+ $this->context->id, // context
+ 'question', // component
+ 'answerfeedback', // filarea
+ !empty($answer->id)?(int)$answer->id:null, // itemid
+ $this->fileoptions, // options
+ $answer->feedback // text
+ );
+ $default_values['feedback['.$key.']']['itemid'] = $draftid;
$key++;
}
}
- $QTYPES['numerical']->set_numerical_unit_data($question,$default_values);
+ $QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
/* if (isset($question->options->units)){
$units = array_values($question->options->units);
@@ -75,8 +97,9 @@ class question_edit_numerical_form extends question_edit_form {
}*/
$question = (object)((array)$question + $default_values);
}
- parent::set_data($question);
+ return $question;
}
+
function validation($data, $files) {
global $QTYPES;
$errors = parent::validation($data, $files);
@@ -95,7 +118,7 @@ class question_edit_numerical_form extends question_edit_form {
if ($data['fraction'][$key] == 1) {
$maxgrade = true;
}
- } else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key])) {
+ } else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key]['text'])) {
$errors["answer[$key]"] = get_string('answermustbenumberorstar', 'qtype_numerical');
$answercount++;
}
@@ -110,6 +133,7 @@ class question_edit_numerical_form extends question_edit_form {
return $errors;
}
+
function qtype() {
return 'numerical';
}
diff --git a/question/type/numerical/lib.php b/question/type/numerical/lib.php
new file mode 100644
index 00000000000..0b83d90cba1
--- /dev/null
+++ b/question/type/numerical/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * Serve question type files
+ *
+ * @since 2.0
+ * @package questionbank
+ * @subpackage questiontypes
+ * @author Dongsheng Cai
+ * @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);
+}
diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php
index 33062593a56..acb91008030 100644
--- a/question/type/numerical/questiontype.php
+++ b/question/type/numerical/questiontype.php
@@ -1,10 +1,26 @@
.
+
/**
* @author Martin Dougiamas and many others. Tim Hunt.
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package questionbank
* @subpackage questiontypes
- *//** */
+ */
require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
@@ -19,6 +35,7 @@ require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
* @package questionbank
* @subpackage questiontypes
*/
+
class question_numerical_qtype extends question_shortanswer_qtype {
public $virtualqtype = false;
@@ -52,7 +69,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
$this->get_numerical_units($question);
//get_numerical_options() need to know if there are units
- // to set correctly default values
+ // to set correctly default values
$this->get_numerical_options($question);
// If units are defined we strip off the default unit from the answer, if
@@ -75,7 +92,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
if (!$options = $DB->get_record('question_numerical_options', array('question' => $question->id))) {
$question->options->unitgradingtype = 0; // total grade
$question->options->unitpenalty = 0;
- // the default
+ // the default
if ($defaultunit = $this->get_default_numerical_unit($question)) {
// so units can be graded
$question->options->showunits = NUMERICALQUESTIONUNITTEXTINPUTDISPLAY ;
@@ -85,18 +102,20 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$question->options->showunits = NUMERICALQUESTIONUNITNODISPLAY ;
}
$question->options->unitsleft = 0 ;
- $question->options->instructions = '' ;
+ $question->options->instructions = '';
+ $question->options->instructionsformat = editors_get_preferred_format();
} else {
$question->options->unitgradingtype = $options->unitgradingtype;
$question->options->unitpenalty = $options->unitpenalty;
- $question->options->showunits = $options->showunits ;
- $question->options->unitsleft = $options->unitsleft ;
- $question->options->instructions = $options->instructions ;
+ $question->options->showunits = $options->showunits;
+ $question->options->unitsleft = $options->unitsleft;
+ $question->options->instructions = $options->instructions;
+ $question->options->instructionsformat = $options->instructionsformat;
}
-
return true;
}
+
function get_numerical_units(&$question) {
global $DB;
if ($units = $DB->get_records('question_numerical_units', array('question' => $question->id), 'id ASC')) {
@@ -127,6 +146,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
*/
function save_question_options($question) {
global $DB;
+ $context = $question->context;
+
// Get old versions of the objects
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
$oldanswers = array();
@@ -148,7 +169,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
foreach ($question->answer as $key => $dataanswer) {
// Check for, and ingore, completely blank answer from the form.
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
- html_is_blank($question->feedback[$key])) {
+ html_is_blank($question->feedback[$key]['text'])) {
continue;
}
@@ -163,13 +184,23 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
}
$answer->fraction = $question->fraction[$key];
- $answer->feedback = trim($question->feedback[$key]);
+
+ $feedbacktext = trim($question->feedback[$key]['text']);
+ $draftid = $question->feedback[$key]['itemid'];
+
+
+ $answer->feedbackformat = $question->feedback[$key]['format'];
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
+ $feedbacktext = file_save_draft_area_files($draftid, $context->id, 'question', 'answerfeedback', $oldanswer->id, self::$fileoptions, $feedbacktext);
+ $answer->feedback = $feedbacktext;
$answer->id = $oldanswer->id;
$DB->update_record("question_answers", $answer);
} else { // This is a completely new answer
+ $answer->feedback = $feedbacktext;
$answer->id = $DB->insert_record("question_answers", $answer);
+ $feedbacktext = file_save_draft_area_files($draftid, $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $feedbacktext);
+ $DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$answer->id));
}
// Set up the options object
@@ -220,10 +251,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
function save_numerical_options(&$question) {
global $DB;
+
$result = new stdClass;
// numerical options
$update = true ;
- $options = $DB->get_record("question_numerical_options", array("question" => $question->id));
+ $options = $DB->get_record('question_numerical_options', array('question' => $question->id));
if (!$options) {
$update = false;
$options = new stdClass;
@@ -246,7 +278,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}else {
$options->showunits = $question->showunits1;
}
- }else {
+ }else {
if(isset($question->showunits)){
$options->showunits = $question->showunits;
}else {
@@ -264,22 +296,27 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}else {
$options->unitsleft = 0 ;
}
+ $options->instructionsformat = $question->instructions['format'];
if(isset($question->instructions)){
- $options->instructions = trim($question->instructions);
+ $options->instructions = trim($question->instructions['text']);
}else {
$options->instructions = '' ;
}
+ $component = 'qtype_' . $question->qtype;
+ $options->instructions = file_save_draft_area_files($question->instructions['itemid'],
+ $question->context->id, // context
+ $component, // component
+ 'instruction', // filearea
+ $question->id, // itemid
+ self::$fileoptions, // options
+ $question->instructions['text'] // text
+ );
if ($update) {
- if (!$DB->update_record("question_numerical_options", $options)) {
- $result->error = "Could not update numerical question options! (id=$options->id)";
- return $result;
- }
+ $DB->update_record("question_numerical_options", $options);
} else {
- if (!$DB->insert_record("question_numerical_options", $options)) {
- $result->error = "Could not insert numerical question options!";
- return $result;
- }
+ $id = $DB->insert_record("question_numerical_options", $options);
}
+
return $result;
}
@@ -320,7 +357,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$state->responses = array();
$state->responses['answer'] = '';
$state->responses['unit'] = '';
-
+
return true;
}
function restore_session_and_responses(&$question, &$state) {
@@ -356,10 +393,10 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$rawresponse = str_replace($search, $replace, trim($rawresponse));
if (preg_match('~^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$~',
$rawresponse, $responseparts)) {
- if(isset($responseparts[5]) ){
+ if(isset($responseparts[5]) ){
$unit = $responseparts[5] ;
}
- if(isset($responseparts[1]) ){
+ if(isset($responseparts[1]) ){
$answer = $responseparts[1] ;
}
}
@@ -404,30 +441,33 @@ class question_numerical_qtype extends question_shortanswer_qtype {
*/
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
global $CFG;
+ $context = $this->get_context_by_category_id($question->category);
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
$formatoptions = new stdClass;
$formatoptions->noclean = true;
$formatoptions->para = false;
$nameprefix = $question->name_prefix;
+ $component = 'qtype_' . $question->qtype;
+ // rewrite instructions text
+ $question->options->instructions = quiz_rewrite_question_urls($question->options->instructions, 'pluginfile.php', $context->id, $component, 'instruction', array($state->attempt, $state->question), $question->id);
/// Print question text and media
$questiontext = format_text($question->questiontext,
$question->questiontextformat,
$formatoptions, $cmoptions->course);
- $image = get_question_image($question);
/// Print input controls
// as the entry is controlled the question type here is numerical
// In all cases there is a text input for the number
- // If $question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY
+ // If $question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY
// there is an additional text input for the unit
// If $question->options->showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY"
// radio elements display the defined unit
// The code allows the input number elememt to be displayed
// before i.e. at left or after at rigth of the unit variants.
+ $nameanswer = "name=\"".$question->name_prefix."answer\"";
$nameunit = "name=\"".$question->name_prefix."unit\"";
- $nameanswer = "name=\"".$question->name_prefix."answer\"";
if (isset($state->responses['']) && $state->responses[''] != '' && !isset($state->responses['answer'])){
$this->split_old_answer($state->responses[''], $question->options->units, $state->responses['answer'] ,$state->responses['unit'] );
}
@@ -438,7 +478,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
if (isset($state->responses['unit']) && $state->responses['unit']!='') {
$valueunit = ' value="'.s($state->responses['unit']).'" ';
- } else {
+ } else {
$valueunit = ' value="" ';
if ($question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ){
$valueunit = ' value="'.s($question->options->units[0]->unit).'" ';
@@ -464,72 +504,75 @@ class question_numerical_qtype extends question_shortanswer_qtype {
//this is OK for the first answer with a good response
// having to test for * so response as long as not empty
$response = $this->extract_numerical_response($state->responses['answer']);
- $break = 0 ;
+ $break = 0 ;
foreach($question->options->answers as $answer) {
- // if * then everything has the $answer->fraction value
+ // if * then everything has the $answer->fraction value
if ($answer->answer !== '*' ) {
$this->get_tolerance_interval($answer);
}
-
+
+ $answer->feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'question', 'answerfeedback', array($state->attempt, $state->question), $answer->id);
if ($answer->answer === '*') {
$answerasterisk = true ;
- $rawgrade = $answer->fraction ;
+ $rawgrade = $answer->fraction ;
$class = question_get_feedback_class($answer->fraction);
$feedbackimg = question_get_feedback_image($answer->fraction);
$classunitvalue = $class ;
- $classunit = question_get_feedback_class($answer->fraction);
+ $classunit = question_get_feedback_class($answer->fraction);
$feedbackimgunit = question_get_feedback_image($answer->fraction, $options->feedback);
if ($answer->feedback) {
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
}
- if ( isset($question->options->units))
- {
+ if ( isset($question->options->units))
+ {
$valid_numerical_unit = true ;
}
$break = 1 ;
} else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
$hasunits = 1 ;
- foreach($question->options->units as $key => $unit){
+ foreach($question->options->units as $key => $unit){
// The student did type a number, so check it with tolerances.
- $testresponse = $response /$unit->multiplier ;
+ $testresponse = $response /$unit->multiplier ;
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
$unittested = $unit->unit ;
- $rawgrade = $answer->fraction ;
+ $rawgrade = $answer->fraction ;
$class = question_get_feedback_class($answer->fraction);
$feedbackimg = question_get_feedback_image($answer->fraction);
if ($answer->feedback) {
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
}
- if($state->responses['unit'] == $unit->unit){
+ if($state->responses['unit'] == $unit->unit){
$classunitvalue = $answer->fraction ;
- }else {
+ }else {
$classunitvalue == 0 ;
}
- $classunit = question_get_feedback_class($classunitvalue);
+ $classunit = question_get_feedback_class($classunitvalue);
$feedbackimgunit = question_get_feedback_image($classunitvalue, $options->feedback);
- $break = 1 ;
+ $break = 1 ;
break;
}
}
- }else if($response !== false && ($answer->min <= $response && $response <= $answer->max) ) {
- $rawgrade = $answer->fraction ;
+ } else if($response !== false && ($answer->min <= $response && $response <= $answer->max) ) {
+ $rawgrade = $answer->fraction ;
$class = question_get_feedback_class($answer->fraction);
$feedbackimg = question_get_feedback_image($answer->fraction);
if ($answer->feedback) {
- $feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
+ $feedback = format_text($answer->feedback, $answer->feedbackformat, $formatoptions, $cmoptions->course);
}
$break = 1 ;
}
- if ($break) break;
+ if ($break) {
+ break;
+ }
}
}
$state->options->raw_unitpenalty = 0 ;
$raw_unitpenalty = 0 ;
- if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
+ if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
$classunitvalue = 1 ;
}
-
+
if($classunitvalue == 0){
if($question->options->unitgradingtype == 1){
@@ -537,10 +580,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}else {
$raw_unitpenalty = $question->options->unitpenalty * $question->maxgrade;
}
- $state->options->raw_unitpenalty = $raw_unitpenalty ;
+ $state->options->raw_unitpenalty = $raw_unitpenalty ;
}
-
/// Removed correct answer, to be displayed later MDL-7496
include("$CFG->dirroot/question/type/numerical/display.html");
}
@@ -580,7 +622,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
* and but NOT the unit into account. Returns a true for if a response matches the
* answer or in one of the unit , false if it doesn't.
* the total grading will see if the unit match.
- * if unit != -1 then the test is done only on this unit
+ * if unit != -1 then the test is done only on this unit
*/
function test_response(&$question, &$state, $answer ) {
// Deal with the match anything answer.
@@ -589,17 +631,17 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
/* To be able to test (old) questions that do not have an unit
* input element the test is done using the $state->responses['']
- * which contains the response which is analyzed by extract_numerical_response()
+ * which contains the response which is analyzed by extract_numerical_response()
* If the data comes from the numerical or calculated display
- * the $state->responses['unit'] comes from either
+ * the $state->responses['unit'] comes from either
* a multichoice radio element NUMERICALQUESTIONUNITMULTICHOICEDISPLAY
* where the $state->responses['unit'] value is the key => unit object
* in the the $question->options->units array
* or an input text element NUMERICALUNITTEXTINPUTDISPLAY
* which contains the student response
* for NUMERICALQUESTIONUNITTEXTDISPLAY and NUMERICALQUESTIONUNITNODISPLAY
- *
- */
+ *
+ */
if (!isset($state->responses['answer']) && isset($state->responses[''])){
$state->responses['answer'] = $state->responses[''];
@@ -611,14 +653,14 @@ class question_numerical_qtype extends question_shortanswer_qtype {
// The student did type a number, so check it with tolerances.
$this->get_tolerance_interval($answer);
if ($answer->min <= $response && $response <= $answer->max){
- return true;
+ return true;
}
- // testing for other units
+ // testing for other units
if ( isset($question->options->units) && count($question->options->units) > 0) {
- foreach($question->options->units as $key =>$unit){
+ foreach($question->options->units as $key =>$unit){
$testresponse = $response /$unit->multiplier ;
if($answer->min <= $testresponse && $testresponse<= $answer->max) {
- return true;
+ return true;
}
}
}
@@ -626,11 +668,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
/**
- * Performs response processing and grading
+ * Performs response processing and grading
* The function was redefined for handling correctly the two parts
- * number and unit of numerical or calculated questions
- * The code handles also the case when there no unit defined by the user or
- * when used in a multianswer (Cloze) question.
+ * number and unit of numerical or calculated questions
+ * The code handles also the case when there no unit defined by the user or
+ * when used in a multianswer (Cloze) question.
* This function performs response processing and grading and updates
* the state accordingly.
* @return boolean Indicates success or failure.
@@ -652,7 +694,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
if (!isset($state->responses['answer']) && isset($state->responses[''])){
$state->responses['answer'] = $state->responses[''];
}
-
+
//to apply the unit penalty we need to analyse the response in a more complex way
//the apply_unit() function analysis could be used to obtain the infos
// however it is used to detect good or bad numbers but also
@@ -664,33 +706,33 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$hasunits = 0 ;
$response = $this->extract_numerical_response($state->responses['answer']);
$answerasterisk = false ;
-
- $break = 0 ;
+
+ $break = 0 ;
foreach($question->options->answers as $answer) {
if ($answer->answer !== '*' ) {
// The student did type a number, so check it with tolerances.
$this->get_tolerance_interval($answer);
}
- // if * then everything is OK even unit
+ // if * then everything is OK even unit
if ($answer->answer === '*') {
$state->raw_grade = $answer->fraction;
- if ( isset($question->options->units)){
+ if ( isset($question->options->units)){
$valid_numerical_unit = true ;
}
- $answerasterisk = true ;
+ $answerasterisk = true ;
$break = 1 ;
}else if ($response !== false && isset($question->options->units) && count($question->options->units) > 0) {
$hasunits = 1 ;
- foreach($question->options->units as $key => $unit){
- $testresponse = $response /$unit->multiplier ;
-
+ foreach($question->options->units as $key => $unit){
+ $testresponse = $response /$unit->multiplier ;
+
if($answer->min <= $testresponse && $testresponse <= $answer->max) {
$state->raw_grade = $answer->fraction;
$unittested = $unit->unit ;
- $break = 1 ;
+ $break = 1 ;
break;
- }
+ }
}
}else if ($response !== false) {
if($this->test_response($question, $state, $answer)) {
@@ -700,9 +742,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
if ($break) break;
} //foreach($question->options
-
+
// in all cases the unit should be tested
- if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
+ if( $question->options->showunits == NUMERICALQUESTIONUNITNODISPLAY ||
$question->options->showunits == NUMERICALQUESTIONUNITTEXTDISPLAY ) {
$valid_numerical_unit = true ;
}else {
@@ -714,7 +756,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$valid_numerical_unit = true ;
}
}
-
+
// apply unit penalty
$raw_unitpenalty = 0 ;
if(!empty($question->options->unitpenalty)&& $valid_numerical_unit != true ){
@@ -725,7 +767,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
$state->raw_grade -= $raw_unitpenalty ;
}
-
+
// Make sure we don't assign negative or too high marks.
$state->raw_grade = min(max((float) $state->raw_grade,
0.0), 1.0) * $question->maxgrade;
@@ -857,7 +899,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
// test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don't need spaces and ,
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
$replace = array('', '');
- }else { // remove spaces and normalise , to a . .
+ }else { // remove spaces and normalise , to a . .
$replace = array('', '.');
}
$rawresponse = str_replace($search, $replace, $rawresponse);
@@ -890,7 +932,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
// test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don't need spaces and ,
if ( strpos($rawresponse,'.' ) !== false || substr_count($rawresponse,',') > 1 ) {
$replace = array('', '');
- }else { // remove spaces and normalise , to a . .
+ }else { // remove spaces and normalise , to a . .
$replace = array('', '.');
}
$rawresponse = str_replace($search, $replace, $rawresponse);
@@ -920,10 +962,10 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
/**
- * function used in function definition_inner()
- * of edit_..._form.php for
- * numerical, calculated, calculatedsimple
- */
+ * function used in function definition_inner()
+ * of edit_..._form.php for
+ * numerical, calculated, calculatedsimple
+ */
function add_units_options(&$mform, &$that){
$mform->addElement('header', 'unithandling', get_string('unitshandling', 'qtype_numerical'));
// Units are graded
@@ -938,8 +980,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$showunits0grp[] =& $mform->createElement('radio', 'showunits0', get_string('unitedit', 'qtype_numerical'), get_string('editableunittext', 'qtype_numerical'),0);
$showunits0grp[] =& $mform->createElement('radio', 'showunits0', get_string('selectunits', 'qtype_numerical') , get_string('unitchoice', 'qtype_numerical'),1);
$mform->addGroup($showunits0grp, 'showunits0grp', get_string('studentunitanswer', 'qtype_numerical'),' OR ' , false);
- $mform->addElement('htmleditor', 'instructions', get_string('instructions', 'qtype_numerical'),
- array('rows' => 10, 'course' => $that->coursefilesid));
+ $mform->addElement('editor', 'instructions', get_string('instructions', 'qtype_numerical'), null, $that->editoroptions);
$mform->addElement('static', 'separator1', '
', '
');
// Units are not graded
$mform->addElement('radio', 'unitrole', get_string('unitnotgraded', 'qtype_numerical'), get_string('onlynumerical', 'qtype_numerical'),1);
@@ -967,6 +1008,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$mform->disabledIf('unitsleft', 'showunits1','eq','3');
$mform->disabledIf('showunits1','unitrole','eq','0');
$mform->disabledIf('showunits0','unitrole','eq','1');
+
+
}
/**
@@ -974,7 +1017,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
* of edit_..._form.php for
* numerical, calculated, calculatedsimple
*/
- function add_units_elements(& $mform,& $that) {
+ function add_units_elements(& $mform,& $that) {
$repeated = array();
$repeated[] =& $mform->createElement('header', 'unithdr', get_string('unithdr', 'qtype_numerical', '{no}'));
@@ -1006,31 +1049,48 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
/**
- * function used in in function setdata ()
- * of edit_..._form.php for
- * numerical, calculated, calculatedsimple
- */
- function set_numerical_unit_data(&$question,&$default_values){
+ * function used in in function data_preprocessing() of edit_numerical_form.php for
+ * numerical, calculated, calculatedsimple
+ */
+ function set_numerical_unit_data($mform, &$question, &$default_values){
+
+ list($categoryid) = explode(',', $question->category);
+ $context = $this->get_context_by_category_id($categoryid);
if (isset($question->options)){
$default_values['unitgradingtype'] = $question->options->unitgradingtype ;
$default_values['unitpenalty'] = $question->options->unitpenalty ;
switch ($question->options->showunits){
case 'O' :
- case '1' :
+ case '1' :
$default_values['showunits0'] = $question->options->showunits ;
$default_values['unitrole'] = 0 ;
break;
case '2' :
- case '3' :
+ case '3' :
$default_values['showunits1'] = $question->options->showunits ;
$default_values['unitrole'] = 1 ;
break;
- }
+ }
$default_values['unitsleft'] = $question->options->unitsleft ;
- $default_values['instructions'] = $question->options->instructions ;
-
- if (isset($question->options->units)){
+
+ // processing files
+ $component = 'qtype_' . $question->qtype;
+ $draftid = file_get_submitted_draft_itemid('instructions');
+ $default_values['instructions'] = array();
+ $default_values['instructions']['format'] = $question->options->instructionsformat;
+ $default_values['instructions']['text'] = file_prepare_draft_area(
+ $draftid, // draftid
+ $context->id, // context
+ $component, // component
+ 'instruction', // filarea
+ !empty($question->id)?(int)$question->id:null, // itemid
+ $mform->fileoptions, // options
+ $question->options->instructions // text
+ );
+ $default_values['instructions']['itemid'] = $draftid;
+
+ if (isset($question->options->units)) {
$units = array_values($question->options->units);
if (!empty($units)) {
foreach ($units as $key => $unit){
@@ -1042,11 +1102,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
}
-/**
- * function use in in function validation()
- * of edit_..._form.php for
- * numerical, calculated, calculatedsimple
- */
+ /**
+ * function use in in function validation()
+ * of edit_..._form.php for
+ * numerical, calculated, calculatedsimple
+ */
function validate_numerical_options(& $data, & $errors){
$units = $data['unit'];
@@ -1055,9 +1115,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}else {
$showunits = $data['showunits1'];
}
-
- if (($showunits == NUMERICALQUESTIONUNITTEXTINPUTDISPLAY) ||
- ($showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY ) ||
+
+ if (($showunits == NUMERICALQUESTIONUNITTEXTINPUTDISPLAY) ||
+ ($showunits == NUMERICALQUESTIONUNITMULTICHOICEDISPLAY ) ||
($showunits == NUMERICALQUESTIONUNITTEXTDISPLAY )){
if (trim($units[0]) == ''){
$errors['unit[0]'] = 'You must set a valid unit name' ;
@@ -1072,8 +1132,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
}
}
-
-
+
+
// Check double units.
$alreadyseenunits = array();
if (isset($data['unit'])) {
@@ -1106,7 +1166,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
}
}
- }
+ }
}
}
@@ -1284,6 +1344,71 @@ class question_numerical_qtype extends question_shortanswer_qtype {
return $this->save_question($question, $form, $course);
}
+ /**
+ * When move the category of questions, the belonging files should be moved as well
+ * @param object $question, question information
+ * @param object $newcategory, target category information
+ */
+ function move_files($question, $newcategory) {
+ global $DB;
+ parent::move_files($question, $newcategory);
+
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+ $component = 'question';
+ $filearea = 'answerfeedback';
+ foreach ($oldanswers as $answer) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+ $component = 'qtype_numerical';
+ $filearea = 'instruction';
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $question->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+
+ function check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args) {
+ $itemid = reset($args);
+ if ($component == 'question' && $filearea == 'answerfeedback') {
+ $result = $options->feedback && array_key_exists($itemid, $question->options->answers);
+ if (!$result) {
+ return false;
+ }
+ foreach($question->options->answers as $answer) {
+ if ($this->test_response($question, $state, $answer)) {
+ return true;
+ }
+ }
+ return false;
+ } else if ($filearea == 'instruction') {
+ if ($itemid != $question->id) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return parent::check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args);
+ }
+ }
}
// INITIATION - Without this line the question type is not in use.
diff --git a/question/type/numerical/version.php b/question/type/numerical/version.php
index 168f4ff99cc..ca04978a124 100644
--- a/question/type/numerical/version.php
+++ b/question/type/numerical/version.php
@@ -1,6 +1,6 @@
version = 2009100100;
+$plugin->version = 2009100101;
$plugin->requires = 2007101000;
diff --git a/question/type/questiontype.php b/question/type/questiontype.php
index 54e44956e42..e5767afa6b5 100644
--- a/question/type/questiontype.php
+++ b/question/type/questiontype.php
@@ -1,4 +1,20 @@
.
+
/**
* 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();
+ }
+ }
+ }
+ }
+}
diff --git a/question/type/random/edit_random_form.php b/question/type/random/edit_random_form.php
index 35eddb91b71..0572d14f1f9 100644
--- a/question/type/random/edit_random_form.php
+++ b/question/type/random/edit_random_form.php
@@ -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';
}
diff --git a/question/type/random/questiontype.php b/question/type/random/questiontype.php
index 958501fbcd4..f1acc34c2f8 100644
--- a/question/type/random/questiontype.php
+++ b/question/type/random/questiontype.php
@@ -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());
-
-
diff --git a/question/type/randomsamatch/edit_randomsamatch_form.php b/question/type/randomsamatch/edit_randomsamatch_form.php
index 24b9502e175..4cdf5768501 100644
--- a/question/type/randomsamatch/edit_randomsamatch_form.php
+++ b/question/type/randomsamatch/edit_randomsamatch_form.php
@@ -19,8 +19,6 @@ class question_edit_randomsamatch_form extends question_edit_form {
* @param MoodleQuickForm $mform the form being built.
*/
function definition_inner(&$mform) {
- $mform->removeElement('image');
-
$questionstoselect = array();
for ($i=2; $i<=QUESTION_NUMANS; $i++){
$questionstoselect[$i] = $i;
@@ -33,15 +31,15 @@ class question_edit_randomsamatch_form extends question_edit_form {
$mform->setType('fraction', PARAM_RAW);
}
- function set_data($question) {
+ function data_preprocessing($question) {
if (empty($question->name)) {
$question->name = get_string("randomsamatch", "quiz");
}
if (empty($question->questiontext)) {
- $question->questiontext = get_string("randomsamatchintro", "quiz");
+ $question->questiontext = get_string("randomsamatchintro", "quiz");
}
- parent::set_data($question);
+ return $question;
}
function qtype() {
@@ -70,7 +68,5 @@ class question_edit_randomsamatch_form extends question_edit_form {
$errors['choose'] = get_string('notenoughsaincategory', 'qtype_randomsamatch', $a);
}
return $errors;
-
}
}
-
diff --git a/question/type/shortanswer/display.html b/question/type/shortanswer/display.html
index ad263640a8b..d29fe5d97c4 100644
--- a/question/type/shortanswer/display.html
+++ b/question/type/shortanswer/display.html
@@ -2,10 +2,6 @@
-
-
-
-
diff --git a/question/type/shortanswer/edit_shortanswer_form.php b/question/type/shortanswer/edit_shortanswer_form.php
index fae996e4642..a43f3c2fac6 100644
--- a/question/type/shortanswer/edit_shortanswer_form.php
+++ b/question/type/shortanswer/edit_shortanswer_form.php
@@ -1,4 +1,22 @@
.
+
+defined('MOODLE_INTERNAL') || die();
+
/**
* Defines the editing form for the shortanswer question type.
*
@@ -30,22 +48,40 @@ class question_edit_shortanswer_form extends question_edit_form {
$creategrades->gradeoptions);
}
- function set_data($question) {
+ function data_preprocessing($question) {
if (isset($question->options)){
$answers = $question->options->answers;
+ $answers_ids = array();
if (count($answers)) {
$key = 0;
foreach ($answers as $answer){
+ $answers_ids[] = $answer->id;
$default_values['answer['.$key.']'] = $answer->answer;
$default_values['fraction['.$key.']'] = $answer->fraction;
- $default_values['feedback['.$key.']'] = $answer->feedback;
+ $default_values['feedback['.$key.']'] = array();
+
+ // prepare feedback editor to display files in draft area
+ $draftid_editor = file_get_submitted_draft_itemid('feedback['.$key.']');
+ $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
+ $draftid_editor, // draftid
+ $this->context->id, // context
+ 'question', // component
+ 'answerfeedback', // filarea
+ !empty($answer->id)?(int)$answer->id:null, // itemid
+ $this->fileoptions, // options
+ $answer->feedback // text
+ );
+ $default_values['feedback['.$key.']']['itemid'] = $draftid_editor;
+ // prepare files code block ends
+
+ $default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
$key++;
}
}
- $default_values['usecase'] = $question->options->usecase;
+ $default_values['usecase'] = $question->options->usecase;
$question = (object)((array)$question + $default_values);
}
- parent::set_data($question);
+ return $question;
}
function validation($data, $files) {
$errors = parent::validation($data, $files);
@@ -59,7 +95,7 @@ class question_edit_shortanswer_form extends question_edit_form {
if ($data['fraction'][$key] == 1) {
$maxgrade = true;
}
- } else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key])) {
+ } else if ($data['fraction'][$key] != 0 || !html_is_blank($data['feedback'][$key]['text'])) {
$errors["answer[$key]"] = get_string('answermustbegiven', 'qtype_shortanswer');
$answercount++;
}
diff --git a/question/type/shortanswer/lib.php b/question/type/shortanswer/lib.php
new file mode 100644
index 00000000000..82757e70d73
--- /dev/null
+++ b/question/type/shortanswer/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * Serve question type files
+ *
+ * @since 2.0
+ * @package questionbank
+ * @subpackage questiontypes
+ * @author Dongsheng Cai
+ * @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);
+}
diff --git a/question/type/shortanswer/questiontype.php b/question/type/shortanswer/questiontype.php
index a9a0d22eb4d..d285f45e93e 100644
--- a/question/type/shortanswer/questiontype.php
+++ b/question/type/shortanswer/questiontype.php
@@ -1,5 +1,20 @@
.
+
///////////////////
/// SHORTANSWER ///
///////////////////
@@ -27,17 +42,48 @@ class question_shortanswer_qtype extends default_questiontype {
}
function extra_question_fields() {
- return array('question_shortanswer','answers','usecase');
+ return array('question_shortanswer', 'answers', 'usecase');
}
function questionid_column_name() {
return 'question';
}
+ /**
+ * When move the category of questions, the belonging files should be moved as well
+ * @param object $question, question information
+ * @param object $newcategory, target category information
+ */
+ function move_files($question, $newcategory) {
+ global $DB;
+ parent::move_files($question, $newcategory);
+
+ $fs = get_file_storage();
+ // process files in answer
+ if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
+ $oldanswers = array();
+ }
+ $component = 'question';
+ $filearea = 'answerfeedback';
+ foreach ($oldanswers as $answer) {
+ $files = $fs->get_area_files($question->contextid, $component, $filearea, $answer->id);
+ foreach ($files as $storedfile) {
+ if (!$storedfile->is_directory()) {
+ $newfile = new object();
+ $newfile->contextid = (int)$newcategory->contextid;
+ $fs->create_file_from_storedfile($newfile, $storedfile);
+ $storedfile->delete();
+ }
+ }
+ }
+ }
+
function save_question_options($question) {
global $DB;
$result = new stdClass;
+ $context = $question->context;
+
if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) {
$oldanswers = array();
}
@@ -49,23 +95,36 @@ class question_shortanswer_qtype extends default_questiontype {
foreach ($question->answer as $key => $dataanswer) {
// Check for, and ingore, completely blank answer from the form.
if (trim($dataanswer) == '' && $question->fraction[$key] == 0 &&
- html_is_blank($question->feedback[$key])) {
+ html_is_blank($question->feedback[$key]['text'])) {
continue;
}
+ $feedbackformat = $question->feedback[$key]['format'];
+
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
$answer = $oldanswer;
$answer->answer = trim($dataanswer);
$answer->fraction = $question->fraction[$key];
- $answer->feedback = $question->feedback[$key];
+
+ // save draft file and rewrite text in feedback
+ $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $oldanswer->id, self::$fileoptions, $question->feedback[$key]['text']);
+ $answer->feedbackformat = $feedbackformat;
+
$DB->update_record("question_answers", $answer);
} else { // This is a completely new answer
$answer = new stdClass;
$answer->answer = trim($dataanswer);
$answer->question = $question->id;
$answer->fraction = $question->fraction[$key];
- $answer->feedback = $question->feedback[$key];
+ // feedback content needs to be rewriten
+ $answer->feedback = '';
+ $answer->feedbackformat = $feedbackformat;
$answer->id = $DB->insert_record("question_answers", $answer);
+
+ // save draft file and rewrite text in feedback
+ $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']);
+ // update feedback content
+ $DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id));
}
$answers[] = $answer->id;
if ($question->fraction[$key] > $maxfraction) {
@@ -97,6 +156,8 @@ class question_shortanswer_qtype extends default_questiontype {
}
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
+ global $CFG;
+ $context = $this->get_context_by_category_id($question->category);
/// This implementation is also used by question type 'numerical'
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
$formatoptions = new stdClass;
@@ -109,7 +170,6 @@ class question_shortanswer_qtype extends default_questiontype {
$questiontext = format_text($question->questiontext,
$question->questiontextformat,
$formatoptions, $cmoptions->course);
- $image = get_question_image($question);
/// Print input controls
@@ -135,6 +195,7 @@ class question_shortanswer_qtype extends default_questiontype {
$class = question_get_feedback_class($answer->fraction);
$feedbackimg = question_get_feedback_image($answer->fraction);
if ($answer->feedback) {
+ $answer->feedback = quiz_rewrite_question_urls($answer->feedback, 'pluginfile.php', $context->id, 'question', 'answerfeedback', array($state->attempt, $state->question), $answer->id);
$feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course);
}
break;
@@ -145,7 +206,7 @@ class question_shortanswer_qtype extends default_questiontype {
/// Removed correct answer, to be displayed later MDL-7496
include($this->get_display_html_path());
}
-
+
function get_display_html_path() {
global $CFG;
return $CFG->dirroot.'/question/type/shortanswer/display.html';
@@ -330,12 +391,12 @@ class question_shortanswer_qtype extends default_questiontype {
// print grade for this submission
print_string('gradingdetails', 'quiz', $grade) ;
// A unit penalty for numerical was applied so display it
- // a temporary solution for unit rendering in numerical
+ // a temporary solution for unit rendering in numerical
// waiting for the new question engine code for a permanent one
if(isset($state->options->raw_unitpenalty) && $state->options->raw_unitpenalty > 0.0 ){
echo ' ';
print_string('unitappliedpenalty','qtype_numerical',question_format_grade($cmoptions, $state->options->raw_unitpenalty ));
- }
+ }
if ($cmoptions->penaltyscheme) {
// print details of grade adjustment due to penalties
if ($state->last_graded->raw_grade > $state->last_graded->grade){
@@ -390,6 +451,33 @@ class question_shortanswer_qtype extends default_questiontype {
return $this->save_question($question, $form, $course);
}
+
+ function check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args) {
+ if ($component == 'question' && $filearea == 'answerfeedback') {
+ $answers = &$question->options->answers;
+ if (isset($state->responses[''])) {
+ $response = $state->responses[''];
+ } else {
+ $response = '';
+ }
+ $answerid = reset($args); // itemid is answer id.
+ if (empty($options->feedback)) {
+ return false;
+ }
+ foreach($answers as $answer) {
+ if ($this->test_response($question, $state, $answer)) {
+ return true;
+ }
+ }
+ return false;
+
+ } else {
+ return parent::check_file_access($question, $state, $options, $contextid, $component,
+ $filearea, $args);
+ }
+ }
+
}
//// END OF CLASS ////
diff --git a/question/type/truefalse/display.html b/question/type/truefalse/display.html
index 2bd99a5702c..344f3d830db 100644
--- a/question/type/truefalse/display.html
+++ b/question/type/truefalse/display.html
@@ -2,10 +2,6 @@
-
-
-
-
:
@@ -27,4 +23,4 @@
print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
-
\ No newline at end of file
+
diff --git a/question/type/truefalse/edit_truefalse_form.php b/question/type/truefalse/edit_truefalse_form.php
index ad70e66a838..4057d886fca 100644
--- a/question/type/truefalse/edit_truefalse_form.php
+++ b/question/type/truefalse/edit_truefalse_form.php
@@ -1,9 +1,26 @@
.
+
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);
}
diff --git a/question/type/truefalse/lib.php b/question/type/truefalse/lib.php
new file mode 100644
index 00000000000..6b8e0057195
--- /dev/null
+++ b/question/type/truefalse/lib.php
@@ -0,0 +1,31 @@
+.
+
+/**
+ * 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);
+}
diff --git a/question/type/truefalse/questiontype.php b/question/type/truefalse/questiontype.php
index 9c2b895e0c0..58c78a13302 100644
--- a/question/type/truefalse/questiontype.php
+++ b/question/type/truefalse/questiontype.php
@@ -1,5 +1,22 @@
.
+
+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());
-
diff --git a/version.php b/version.php
index c0704103393..ae20a02f0c5 100644
--- a/version.php
+++ b/version.php
@@ -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