Development:question edit QTYPES USEABLE BY MULTIANSWER form functions
From MoodleDocs
- Cloze question type
- edit QTYPES USEABLE BY MULTIANSWER form
The code flow of question_edit_QTYPES_USEABLE_BY_MULTIANSWER_form functions that will be used by the new multianswer(Cloze) editing interface.
Contents |
Main question_edit_QTYPES_USEABLE_BY_MULTIANSWER_form()
As described in Development:Cloze question type this function should be created to be able to create the class with or without activating the moodle form.
function question_edit_shortanswer_form($submiturl, $question, $category, $contexts, $formeditable = true,$go=true){
if( $go) parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable );
}
definition_inner(&$mform)
This function can be divided as
- Modification of the main question display like removing grade in multianswer
- Display usual answer parameters
- answer
- grade
- feedback
- others like tolerance in numerical
- Display other answer parameters like units in numerical
- Display specific feedbacks as in multichoice
For the purpose of multianswer two subfunctions should be added so that
- Modification of the main question display like removing grade in multianswer remains in the definition_inner()
- Display usual answer parameters is done by definition_inner_answer()
- answer
- grade
- feedback
- others like tolerance in numerical
- Display other answer parameters like units in numerical is done by definition_inner_other()
- Display specific feedbacks as in multichoice is not useable in multianswer so remains in the definition_inner()
So the definition_inner(&$mform) code become (using a mixed example)
function definition_inner(&$mform) {
// Remove meaningless defaultgrade field.
$mform->removeElement('defaultgrade');
$this->definition_inner_answer($mform,,$this,$this->question,) ;
$this->definition_inner_other($mform,,$this,$this->question,,) ;
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
$mform->addElement('htmleditor', 'correctfeedback', get_string('correctfeedback', 'qtype_multichoice'),
array('course' => $this->coursefilesid));
$mform->setType('correctfeedback', PARAM_RAW);
//etc.
}
The definition_inner_answer() functions should be created only by the QTYPES_USEABLE_BY_MULTIANSWER i.e. shortanswer,numerical and multichoice for regular ones. The definition_inner_other() functions should be created only when necessary by the QTYPES_USEABLE_BY_MULTIANSWER i.e. numerical for regular ones.
definition_inner_answer()
To ientified the parameters in the edit_multianswer they will be named with a prefix like sub_1_, sub_2_ etc. We need also a Question{#1},Question{#2} prefix to be added to the headers and the add new answer button. We need to access the $question and the object using the definition_inner_answer i.e. $this which become $that inside definition_inner_answer. a $display object will be used (and described elsewhere) to control the display. a typical function (without the display control code for numerical)
function definition_inner_answer(&$mform,$prefix=,&$that,$question,$prehdr,$displayoptions) {
$creategrades = get_grade_options();
$gradeoptions = $creategrades->gradeoptions;
$repeated = array();
$repeatedoptions = array();
$repeated[] =& $mform->createElement('header',$prefix.'answerhdr', $prehdr.get_string('answerno', 'qtype_numerical', '{no}'));
$repeated[] =& $mform->createElement('text', $prefix.'answer', get_string('answer', 'quiz'));
$mform->setType('answer', PARAM_RAW);
$repeated[] =& $mform->createElement('text', $prefix.'tolerance', get_string('acceptederror', 'quiz'));
$mform->setType($prefix.'tolerance', PARAM_NUMBER);
$repeated[] =& $mform->createElement('select', $prefix.'fraction', get_string('grade'), $gradeoptions);
$repeatedoptions[$prefix.'fraction']['default'] = 0;
$repeated[] =& $mform->createElement('htmleditor', $prefix.'feedback', get_string('feedback', 'quiz'),
array('course' => $that->coursefilesid));
$mform->setType($prefix.'feedback', PARAM_RAW);
if (isset($question->options)){
$countanswers = count($question->options->answers);
} else {
$countanswers = 0;
}
if ($question->formoptions->repeatelements){
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + 1))?
QUESTION_NUMANS_START : ($countanswers + 1);
} else {
$repeatsatstart = $countanswers;
}
$that->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, $prefix.'noanswers',
$prefix.'addanswers', QUESTION_NUMANS_ADD, $prehdr.' '.get_string('addmoreanswerblanks', 'qtype_numerical'));
}
definition_inner_other()
for numerical
function definition_inner_other(&$mform,$prefix=,&$that,$question,$prehdr,$displayoptions) {
$repeated = array();
if($displayoptions->displayothers == 'hide' ){
$repeated[] =& $mform->createElement('hidden', $prefix.'unit',get_string('unit', 'quiz'));
} else {
$repeated[] =& $mform->createElement('header',$prefix.'unithdr', $prehdr.' '.get_string('unithdr', 'qtype_numerical', '{no}'));
$repeated[] =& $mform->createElement('text', $prefix.'unit', get_string('unit', 'quiz'));
}
$mform->setType($prefix.'unit', PARAM_NOTAGS);
if($displayoptions->displayothers == 'hide' ){
$repeated[] =& $mform->createElement('hidden',$prefix.'multiplier', get_string('multiplier', 'quiz'));
} else {
$repeated[] =& $mform->createElement('text',$prefix.'multiplier', get_string('multiplier', 'quiz'));
}
$mform->setType($prefix.'multiplier', PARAM_NOTAGS);
if (isset($question->options)){
$countunits = count($question->options->units);
} else {
$countunits = 0;
}
if ($question->formoptions->repeatelements){
$repeatsatstart = $countunits + 2;
} else {
$repeatsatstart = $countunits;
}
$that->repeat_elements($repeated, $repeatsatstart, array(), $prefix.'nounits',$prefix.'addunits', 2, $prehdr.' '.get_string('addmoreunitblanks', 'qtype_numerical'));
$firstunit =& $mform->getElement($prefix.'multiplier[0]');
$firstunit->freeze();
$firstunit->setValue('1.0');
$firstunit->setPersistantFreeze(true);
}
set_data()
This should also be divided with the setting data answer with a $prefix. However as the inner_other are always on the multianswer answer form (hidden or not)for the qtypes that have ones(like numerical) there is no need to create a set_data_other().But for consistency it is preferable to set one if a definition_inner_other exits. As we cannot assured that there are $default values to set (i.e. if there is no $question->options )the $default_values should be merged after testing.
// numerical as example
$default_values_answers = $this->set_data_answers($question,);
$default_values_other = $this->set_data_other($question,);
if(is_array($default_values_other) && count($default_values_other)){
if(is_array($default_values_answers)){
$default_values = array_merge($default_values_answers,$default_values_other);
}else $default_values =$default_values_other;
}
$question = (object)((array)$question + $default_values));
set_data_answers()
The $prefix i.e sub_1_ is needed to identify the parameters on the edit_multianswer_form
for numerical note the $answer->tolerance which is specific to numerical
function set_data_answers($question,$prefix=){
$default_values =array();
if (isset($question->options)){
$answers = $question->options->answers;
if (count($answers)) {
$key = 0;
foreach ($answers as $answer){
$default_values[$prefix.'answer['.$key.']'] = $answer->answer;
$default_values[$prefix.'fraction['.$key.']'] = $answer->fraction;
$default_values[$prefix.'tolerance['.$key.']'] = $answer->tolerance;
$default_values[$prefix.'feedback['.$key.']'] = $answer->feedback;
$key++;
}
}
for numerical the following line are added
$units = array_values($question->options->units);
if (!empty($units)) {
foreach ($units as $key => $unit){
$default_values[$prefix.'unit['.$key.']'] = $unit->unit;
$default_values[$prefix.'multiplier['.$key.']'] = $unit->multiplier;
}
}
}
==
