diff --git a/lib/questionlib.php b/lib/questionlib.php index f1c77be8491..5de7963fa5c 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -590,7 +590,8 @@ function question_move_questions_to_category($questionids, $newcategoryid) { SELECT q.id, q.qtype, qc.contextid FROM {question} q JOIN {question_categories} qc ON q.category = qc.id - WHERE q.id $questionidcondition", $params); + WHERE q.id $questionidcondition OR q.parent $questionidcondition", + array_merge($params, $params)); foreach ($questions as $question) { if ($newcontextid != $question->contextid) { question_bank::get_qtype($question->qtype)->move_files( diff --git a/question/format/multianswer/format.php b/question/format/multianswer/format.php index b7c412ea056..b9ea3bd526c 100644 --- a/question/format/multianswer/format.php +++ b/question/format/multianswer/format.php @@ -61,7 +61,8 @@ class qformat_multianswer extends qformat_default { $question->length = 1; $question->penalty = 0.3333333; - if (!empty($question)) { + if (!empty($question) && isset($question->options) && isset($question->options->questions) && + count($question->options->questions) != 0 ) { $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question')); $questions[] = $question; } diff --git a/question/format/xml/format.php b/question/format/xml/format.php index 69e9695f6f4..ea2e1679f94 100644 --- a/question/format/xml/format.php +++ b/question/format/xml/format.php @@ -449,12 +449,12 @@ class qformat_xml extends qformat_default { */ public function import_multianswer($question) { global $USER; - question_bank::get_qtype('multianswer'); + $qtypemultianswer = question_bank::get_qtype('multianswer'); $questiontext = $this->import_text_with_files($question, array('#', 'questiontext', 0)); $qo = qtype_multianswer_extract_question($questiontext); - + $qo = $qtypemultianswer->set_subquestions_elements_itemid($qo, '@@PLUGINFILE@@'); // 'header' parts particular to multianswer $qo->qtype = 'multianswer'; $qo->course = $this->course; diff --git a/question/type/multianswer/edit_multianswer_form.php b/question/type/multianswer/edit_multianswer_form.php index cd792f78a1f..cdecffb0b60 100644 --- a/question/type/multianswer/edit_multianswer_form.php +++ b/question/type/multianswer/edit_multianswer_form.php @@ -189,8 +189,10 @@ class qtype_multianswer_edit_form extends question_edit_form { $mform->addElement('static', 'sub_'.$sub.'_layout', get_string('layout', 'qtype_multianswer')); } - + $nbanswer = 0; + $choices = array(); foreach ($this->questiondisplay->options->questions[$sub]->answer as $key => $ans) { + $nbanswer++; $mform->addElement('static', 'sub_'.$sub.'_answer['.$key.']', get_string('answer', 'question')); @@ -205,6 +207,15 @@ class qtype_multianswer_edit_form extends question_edit_form { $mform->addElement('static', 'sub_'.$sub.'_feedback['.$key.']', get_string('feedback', 'question')); + if ($this->questiondisplay->options->questions[$sub]->qtype == 'multichoice' && + $this->questiondisplay->options->questions[$sub]->layout == 0) { + $choices[] = $ans['text']; + } + } + if ($nbanswer > 0 && $this->questiondisplay->options->questions[$sub]->qtype == 'multichoice' && + $this->questiondisplay->options->questions[$sub]->layout == 0) { + $mform->addElement('select', 'sub_'.$sub.'_layoutselectinline', + get_string('layoutselectinline', 'qtype_multianswer'), $choices); } } @@ -364,6 +375,7 @@ class qtype_multianswer_edit_form extends question_edit_form { get_string('layoutundefined', 'qtype_multianswer'); } } + $choices = array(); foreach ($subquestion->answer as $key => $answer) { if ($subquestion->qtype == 'numerical' && $key == 0) { $default_values[$prefix.'tolerance['.$key.']'] = @@ -388,9 +400,19 @@ class qtype_multianswer_edit_form extends question_edit_form { $maxfraction = $subquestion->fraction[$key]; } } - - $default_values[$prefix.'answer['.$key.']'] = - htmlspecialchars($answer); + if ($subquestion->qtype == 'multichoice' && $subquestion->layout == '0') { + $a = new stdClass(); + $a->strip = strip_tags($trimmedanswer); + $a->html = htmlspecialchars($trimmedanswer); + $default_values[$prefix.'answer['.$key.']'] = get_string('answerselectelementshownas', + 'qtype_multianswer', $a); + $choices[$answercount] = $trimmedanswer; + } else { + $default_values[$prefix.'answer['.$key.']'] = htmlspecialchars($answer); + } + } + if ($subquestion->qtype == 'multichoice' && $subquestion->layout == '0') { + $default_values[$prefix.'_layoutselectinline'] = $choices; } if ($answercount == 0) { if ($subquestion->qtype == 'multichoice') { diff --git a/question/type/multianswer/lang/en/qtype_multianswer.php b/question/type/multianswer/lang/en/qtype_multianswer.php index ddc01555a6a..0a294a49726 100644 --- a/question/type/multianswer/lang/en/qtype_multianswer.php +++ b/question/type/multianswer/lang/en/qtype_multianswer.php @@ -23,6 +23,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['answerselectelementempty'] = '{$a->html}
This answer will appear empty as the dropdown menu does not show HTML components.'; +$string['answerselectelementshownas'] = '{$a->html}
This answer will be rendered in the dropdown menu as : {$a->strip}'; $string['confirmquestionsaveasedited'] = 'I confirm that I want the question to be saved as edited'; $string['confirmsave'] = 'Confirm then save {$a}'; $string['correctanswer'] = 'Correct answer'; diff --git a/question/type/multianswer/lib.php b/question/type/multianswer/lib.php new file mode 100644 index 00000000000..59faf589a41 --- /dev/null +++ b/question/type/multianswer/lib.php @@ -0,0 +1,47 @@ +. + +/** + * Serve question type files + * + * @since 2.0 + * @package qtype_multianswer + * @copyright Pierre Pichet + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +defined('MOODLE_INTERNAL') || die(); + + +/** + * Checks file access for multianswer questions. + * @package qtype_multianswer + * @category files + * @param stdClass $course course object + * @param stdClass $cm course module object + * @param stdClass $context context object + * @param string $filearea file area + * @param array $args extra arguments + * @param bool $forcedownload whether or not force download + * @param array $options additional options affecting the file serving + * @return bool + */ +function qtype_multianswer_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) { + global $DB, $CFG; + require_once($CFG->libdir . '/questionlib.php'); + question_pluginfile($course, $context, 'qtype_multianswer', $filearea, $args, $forcedownload, $options); +} diff --git a/question/type/multianswer/questiontype.php b/question/type/multianswer/questiontype.php index 5df9f2cce59..0153882e66c 100644 --- a/question/type/multianswer/questiontype.php +++ b/question/type/multianswer/questiontype.php @@ -168,8 +168,45 @@ class qtype_multianswer extends question_type { $this->save_hints($question, true); } + /** + * Set the itemid if the element contains a valid file identify by (draftfile.php). + * param array() $question from qtype_multianswer_extract_question(). + * param string $searchcriteria i.e $searchcriteria ,@@PLUGINFILE@@. + * return $question. + */ + public function set_subquestions_elements_itemid($question, $searchcriteria = '') { + if (isset($question->options) && isset($question->options->questions) && + $question->options->questions != '' && isset($question->questiontext['itemid']) + && $question->questiontext['itemid'] != '' && $searchcriteria != '') { + $questiontextitemid = $question->questiontext['itemid']; + foreach ($question->options->questions as $wrapped) { + if (preg_match('/'.$searchcriteria.'/', $wrapped->questiontext['text'])) { + $wrapped->questiontext['itemid'] = $questiontextitemid; + } else { + $wrapped->questiontext['itemid'] = ''; + } + foreach ($wrapped->answer as $key => $answer) { + if (is_array($answer)) { + if (preg_match('/'.$searchcriteria.'/', $answer['text'])) { + $wrapped->answer[$key]['itemid'] = $questiontextitemid; + } else { + $wrapped->answer[$key]['itemid'] = ''; + } + } + if (preg_match('/'.$searchcriteria.'/', $wrapped->feedback[$key]['text'])) { + $wrapped->feedback[$key]['itemid'] = $questiontextitemid; + } else { + $wrapped->feedback[$key]['itemid'] = ''; + } + } + } + } + return $question; + } + public function save_question($authorizedquestion, $form) { $question = qtype_multianswer_extract_question($form->questiontext); + $question = $this->set_subquestions_elements_itemid($question, 'draftfile.php'); if (isset($authorizedquestion->id)) { $question->id = $authorizedquestion->id; } @@ -296,9 +333,15 @@ define('ANSWER_REGEX_ALTERNATIVES', 9); function qtype_multianswer_extract_question($text) { // Variable $text is an array [text][format][itemid]. + // If the main question contains a file then its [itemid] + // will not be empty. + // The other subquestions question , answers feedback and + // multiple choice vertical and horizontal answers should be declared + // array and should have [itemid] set to [text][itemid]. $question = new stdClass(); $question->qtype = 'multianswer'; $question->questiontext = $text; + $question->questiontext['text'] = str_replace(array('
', '
'), array('', ''), $question->questiontext['text']); $question->generalfeedback['text'] = ''; $question->generalfeedback['format'] = FORMAT_HTML; $question->generalfeedback['itemid'] = ''; @@ -314,6 +357,9 @@ function qtype_multianswer_extract_question($text) { $wrapped->generalfeedback['text'] = ''; $wrapped->generalfeedback['format'] = FORMAT_HTML; $wrapped->generalfeedback['itemid'] = ''; + $wrapped->questiontext['text'] = $answerregs[0]; + $wrapped->questiontext['format'] = $question->questiontext['format']; + $wrapped->questiontext['itemid'] = $question->questiontext['itemid']; if (isset($answerregs[ANSWER_REGEX_NORM])&& $answerregs[ANSWER_REGEX_NORM]!== '') { $wrapped->defaultmark = $answerregs[ANSWER_REGEX_NORM]; } else { @@ -388,9 +434,6 @@ function qtype_multianswer_extract_question($text) { $wrapped->answer = array(); $wrapped->fraction = array(); $wrapped->feedback = array(); - $wrapped->questiontext['text'] = $answerregs[0]; - $wrapped->questiontext['format'] = FORMAT_HTML; - $wrapped->questiontext['itemid'] = ''; $answerindex = 0; $remainingalts = $answerregs[ANSWER_REGEX_ALTERNATIVES]; @@ -408,7 +451,7 @@ function qtype_multianswer_extract_question($text) { $feedback = str_replace('\}', '}', $feedback); $wrapped->feedback["$answerindex"]['text'] = str_replace('\#', '#', $feedback); $wrapped->feedback["$answerindex"]['format'] = FORMAT_HTML; - $wrapped->feedback["$answerindex"]['itemid'] = ''; + $wrapped->feedback["$answerindex"]['itemid'] = $question->questiontext['itemid']; } else { $wrapped->feedback["$answerindex"]['text'] = ''; $wrapped->feedback["$answerindex"]['format'] = FORMAT_HTML; @@ -436,6 +479,11 @@ function qtype_multianswer_extract_question($text) { 'text' => $wrapped->answer["$answerindex"], 'format' => FORMAT_HTML, 'itemid' => ''); + if ($wrapped->answer["$answerindex"]['text'] != '' && + ($wrapped->layout == qtype_multichoice_base::LAYOUT_HORIZONTAL || + $wrapped->layout == qtype_multichoice_base::LAYOUT_VERTICAL )) { + $wrapped->answer["$answerindex"]['itemid'] = $question->questiontext['itemid']; + } } } $tmp = explode($altregs[0], $remainingalts, 2); diff --git a/question/type/multianswer/renderer.php b/question/type/multianswer/renderer.php index d67d0fc8620..403c9851d2c 100644 --- a/question/type/multianswer/renderer.php +++ b/question/type/multianswer/renderer.php @@ -388,7 +388,7 @@ class qtype_multianswer_multichoice_vertical_renderer extends qtype_multianswer_ question_state::$gradedright) { $feedback[] = get_string('correctansweris', 'qtype_multichoice', $subq->format_text($ans->answer, $ans->answerformat, - $qa, 'question', 'answer', $ansid)); + $qa, 'question', 'answer', $ans->id)); break; } } diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php index 2d290aacb57..995de5cb573 100644 --- a/question/type/numerical/questiontype.php +++ b/question/type/numerical/questiontype.php @@ -206,7 +206,8 @@ class qtype_numerical extends question_type { } $options->question = $question->id; $options->answer = $answer->id; - if (trim($question->tolerance[$key]) == '') { + // When the answer is * the tolerance can be absent i.e. in multianswer. + if (!isset($question->tolerance[$key]) || trim($question->tolerance[$key]) == '') { $options->tolerance = ''; } else { $options->tolerance = $this->apply_unit($question->tolerance[$key],