Commit a1d81dc6 authored by jun's avatar jun
Browse files

MDL-70032 qtype_multichoice: Fix answer labelling

* Discard the use of the label element in order to be able to render
multiple choice answers as they are and have these act as the radio
button/checkbox' label through the aria-labelledby attribute.
* New JS module qtype_multichoice/answers that listens for click events
on the answer text container and selects the appropriate answer radio
button/checkbox.
parent 99680d1b
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Handles events related to the multiple-choice question type answers.
*
* @module qtype_multichoice/answers
* @package qtype_multichoice
* @copyright 2020 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Selectors for this module.
*
* @type {{ANSWER_LABEL: string}}
*/
const SELECTORS = {
ANSWER_LABEL: '[data-region=answer-label]',
};
/**
* Init method.
*
* @param {string} rootId The ID of the question container.
*/
const init = (rootId) => {
const root = document.getElementById(rootId);
// Add click event handlers for the divs containing the answer since these cannot be enclosed in a label element.
const answerLabels = root.querySelectorAll(SELECTORS.ANSWER_LABEL);
answerLabels.forEach((answerLabel) => {
answerLabel.addEventListener('click', (e) => {
const labelId = e.currentTarget.id;
// Fetch the answer this label is assigned to.
const linkedOption = root.querySelector(`[aria-labelledby="${labelId}"]`);
// Trigger the click event.
linkedOption.click();
});
});
};
export default {
init: init
};
......@@ -88,6 +88,7 @@ abstract class qtype_multichoice_renderer_base extends qtype_with_combined_feedb
$inputattributes['name'] = $this->get_input_name($qa, $value);
$inputattributes['value'] = $this->get_input_value($value);
$inputattributes['id'] = $this->get_input_id($qa, $value);
$inputattributes['aria-labelledby'] = $inputattributes['id'] . '_label';
$isselected = $question->is_choice_selected($response, $value);
if ($isselected) {
$inputattributes['checked'] = 'checked';
......@@ -102,15 +103,16 @@ abstract class qtype_multichoice_renderer_base extends qtype_with_combined_feedb
'value' => 0,
));
}
$questionnumber = html_writer::span($this->number_in_style($value, $question->answernumbering), 'answernumber');
$answertext = $question->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ansid);
$questionanswer = html_writer::div($answertext, 'flex-fill ml-1');
$radiobuttons[] = $hidden . html_writer::empty_tag('input', $inputattributes) .
html_writer::tag('label',
html_writer::span($this->number_in_style($value, $question->answernumbering), 'answernumber') .
html_writer::tag('div',
$question->format_text(
$ans->answer, $ans->answerformat,
$qa, 'question', 'answer', $ansid),
array('class' => 'flex-fill ml-1')),
array('for' => $inputattributes['id'], 'class' => 'd-flex w-100'));
html_writer::div($questionnumber . $questionanswer, 'd-flex w-100', [
'id' => $inputattributes['id'] . '_label',
'data-region' => 'answer-label',
]);
// Param $options->suppresschoicefeedback is a hack specific to the
// oumultiresponse question type. It would be good to refactor to
......@@ -151,6 +153,9 @@ abstract class qtype_multichoice_renderer_base extends qtype_with_combined_feedb
}
$result .= html_writer::end_tag('div'); // Answer.
// Load JS module for the question answers.
$this->page->requires->js_call_amd('qtype_multichoice/answers', 'init',
[$qa->get_outer_question_div_unique_id()]);
$result .= $this->after_choices($qa, $options);
$result .= html_writer::end_tag('div'); // Ablock.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment