mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
Merge branch 'MDL-68864-master' of git://github.com/junpataleta/moodle
This commit is contained in:
commit
2157207971
@ -1,2 +1,2 @@
|
||||
define ("qtype_multichoice/clearchoice",["jquery","core/custom_interaction_events"],function(a,b){var c={ANSWER_RADIOS:".answer input",CLEARRESULTS_BUTTON:"button[data-action=\"clearresults\"]"},d="d-none",e=function(f){var g=f.find(c.CLEARRESULTS_BUTTON);f.on(b.events.activate,c.CLEARRESULTS_BUTTON,function(b,e){f.find(c.ANSWER_RADIOS).each(function(){a(this).prop("checked",!1)});a(b.target).addClass(d);e.originalEvent.preventDefault()});f.on(b.events.activate,c.ANSWER_RADIOS,function(){g.removeClass(d)})};return{init:function init(b){b=a("#"+b);e(b)}}});
|
||||
define ("qtype_multichoice/clearchoice",["jquery","core/custom_interaction_events"],function(a,b){var c={CHOICE_ELEMENT:".answer input",LINK:"a",RADIO:"input[type=\"radio\"]"},d=function(a){a.find(c.RADIO).prop("disabled",!1).prop("checked",!0)},e=function(a,b){return a.find("div[id=\""+b+"\"]")},f=function(a){a.addClass("sr-only");a.find(c.LINK).attr("tabindex",-1)},g=function(a){a.removeClass("sr-only");a.find(c.LINK).attr("tabindex",0);a.find(c.RADIO).prop("disabled",!0)},h=function(a,h){var i=e(a,h);i.on(b.events.activate,c.LINK,function(a,b){d(i);f(i);b.originalEvent.preventDefault()});a.on(b.events.activate,c.CHOICE_ELEMENT,function(){g(i)});i.find(c.RADIO).focus(function(){var b=a.find(c.CHOICE_ELEMENT).first();b.focus()})};return{init:function init(b,c){b=a("#"+b);h(b,c)}}});
|
||||
//# sourceMappingURL=clearchoice.min.js.map
|
||||
|
File diff suppressed because one or more lines are too long
@ -24,31 +24,81 @@
|
||||
define(['jquery', 'core/custom_interaction_events'], function($, CustomEvents) {
|
||||
|
||||
var SELECTORS = {
|
||||
ANSWER_RADIOS: '.answer input',
|
||||
CLEARRESULTS_BUTTON: 'button[data-action="clearresults"]'
|
||||
CHOICE_ELEMENT: '.answer input',
|
||||
LINK: 'a',
|
||||
RADIO: 'input[type="radio"]'
|
||||
};
|
||||
|
||||
var CSSHIDDEN = 'd-none';
|
||||
/**
|
||||
* Mark clear choice radio as enabled and checked.
|
||||
*
|
||||
* @param {Object} clearChoiceContainer The clear choice option container.
|
||||
*/
|
||||
var checkClearChoiceRadio = function(clearChoiceContainer) {
|
||||
clearChoiceContainer.find(SELECTORS.RADIO).prop('disabled', false).prop('checked', true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the clear choice div container.
|
||||
*
|
||||
* @param {Object} root The question root element.
|
||||
* @param {string} fieldPrefix The question outer div prefix.
|
||||
* @returns {Object} The clear choice div container.
|
||||
*/
|
||||
var getClearChoiceElement = function(root, fieldPrefix) {
|
||||
return root.find('div[id="' + fieldPrefix + '"]');
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide clear choice option.
|
||||
*
|
||||
* @param {Object} clearChoiceContainer The clear choice option container.
|
||||
*/
|
||||
var hideClearChoiceOption = function(clearChoiceContainer) {
|
||||
clearChoiceContainer.addClass('sr-only');
|
||||
clearChoiceContainer.find(SELECTORS.LINK).attr('tabindex', -1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows clear choice option.
|
||||
*
|
||||
* @param {Object} clearChoiceContainer The clear choice option container.
|
||||
*/
|
||||
var showClearChoiceOption = function(clearChoiceContainer) {
|
||||
clearChoiceContainer.removeClass('sr-only');
|
||||
clearChoiceContainer.find(SELECTORS.LINK).attr('tabindex', 0);
|
||||
clearChoiceContainer.find(SELECTORS.RADIO).prop('disabled', true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Register event listeners for the clear choice module.
|
||||
*
|
||||
* @param {Object} root The question outer div prefix.
|
||||
* @param {string} fieldPrefix The "Clear choice" div prefix.
|
||||
*/
|
||||
var registerEventListeners = function(root) {
|
||||
var registerEventListeners = function(root, fieldPrefix) {
|
||||
var clearChoiceContainer = getClearChoiceElement(root, fieldPrefix);
|
||||
|
||||
var clearChoiceButton = root.find(SELECTORS.CLEARRESULTS_BUTTON);
|
||||
clearChoiceContainer.on(CustomEvents.events.activate, SELECTORS.LINK, function(e, data) {
|
||||
|
||||
root.on(CustomEvents.events.activate, SELECTORS.CLEARRESULTS_BUTTON, function(e, data) {
|
||||
root.find(SELECTORS.ANSWER_RADIOS).each(function() {
|
||||
$(this).prop('checked', false);
|
||||
});
|
||||
$(e.target).addClass(CSSHIDDEN);
|
||||
data.originalEvent.preventDefault();
|
||||
// Mark the clear choice radio element as checked.
|
||||
checkClearChoiceRadio(clearChoiceContainer);
|
||||
// Now that the hidden radio has been checked, hide the clear choice option.
|
||||
hideClearChoiceOption(clearChoiceContainer);
|
||||
|
||||
data.originalEvent.preventDefault();
|
||||
});
|
||||
|
||||
root.on(CustomEvents.events.activate, SELECTORS.ANSWER_RADIOS, function() {
|
||||
clearChoiceButton.removeClass(CSSHIDDEN);
|
||||
root.on(CustomEvents.events.activate, SELECTORS.CHOICE_ELEMENT, function() {
|
||||
// If the event has been triggered by any other choice, show the clear choice option.
|
||||
showClearChoiceOption(clearChoiceContainer);
|
||||
});
|
||||
|
||||
// If the clear choice radio receives focus from using the tab key, return the focus
|
||||
// to the first answer option.
|
||||
clearChoiceContainer.find(SELECTORS.RADIO).focus(function() {
|
||||
var firstChoice = root.find(SELECTORS.CHOICE_ELEMENT).first();
|
||||
firstChoice.focus();
|
||||
});
|
||||
};
|
||||
|
||||
@ -56,10 +106,11 @@ define(['jquery', 'core/custom_interaction_events'], function($, CustomEvents) {
|
||||
* Initialise clear choice module.
|
||||
|
||||
* @param {string} root The question outer div prefix.
|
||||
* @param {string} fieldPrefix The "Clear choice" div prefix.
|
||||
*/
|
||||
var init = function(root) {
|
||||
var init = function(root, fieldPrefix) {
|
||||
root = $('#' + root);
|
||||
registerEventListeners(root);
|
||||
registerEventListeners(root, fieldPrefix);
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -286,25 +286,38 @@ class qtype_multichoice_single_renderer extends qtype_multichoice_renderer_base
|
||||
}
|
||||
}
|
||||
|
||||
$questiondivid = $qa->get_outer_question_div_unique_id();
|
||||
$clearchoiceid = $this->get_input_id($qa, -1);
|
||||
$clearchoicefieldname = $qa->get_qt_field_name('clearchoice');
|
||||
$clearchoiceradioattrs = [
|
||||
'type' => $this->get_input_type(),
|
||||
'name' => $qa->get_qt_field_name('answer'),
|
||||
'id' => $clearchoiceid,
|
||||
'value' => -1,
|
||||
'class' => 'sr-only'
|
||||
];
|
||||
|
||||
$cssclass = 'qtype_multichoice_clearchoice';
|
||||
// When no choice selected during rendering, then hide the clear choice option.
|
||||
$cssclass = '';
|
||||
$linktabindex = 0;
|
||||
if (!$hascheckedchoice && $response == -1) {
|
||||
$cssclass = 'd-none';
|
||||
$cssclass .= ' sr-only';
|
||||
$clearchoiceradioattrs['checked'] = 'checked';
|
||||
$linktabindex = -1;
|
||||
}
|
||||
// Adds an hidden radio that will be checked to give the impression the choice has been cleared.
|
||||
$clearchoiceradio = html_writer::empty_tag('input', $clearchoiceradioattrs);
|
||||
$clearchoiceradio .= html_writer::link('', get_string('clearchoice', 'qtype_multichoice'),
|
||||
['for' => $clearchoiceid, 'role' => 'button', 'tabindex' => $linktabindex,
|
||||
'class' => 'btn btn-link ml-4 pl-1 mt-2']);
|
||||
|
||||
$clearchoicebutton = html_writer::tag('button', get_string('clearchoice', 'qtype_multichoice'), [
|
||||
'class' => 'btn btn-link ml-3 ' . $cssclass,
|
||||
'data-action' => 'clearresults',
|
||||
'data-target' => '#' . $questiondivid
|
||||
]);
|
||||
// Now wrap the radio and label inside a div.
|
||||
$result = html_writer::tag('div', $clearchoiceradio, ['id' => $clearchoicefieldname, 'class' => $cssclass]);
|
||||
|
||||
// Load required clearchoice AMD module.
|
||||
$this->page->requires->js_call_amd('qtype_multichoice/clearchoice', 'init',
|
||||
[$questiondivid]);
|
||||
[$qa->get_outer_question_div_unique_id(), $clearchoicefieldname]);
|
||||
|
||||
return $clearchoicebutton;
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ Feature: Clear my answers
|
||||
| Course | C1 | Test questions |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | template | questiontext |
|
||||
| Test questions | multichoice | Multi-choice-001 | one_of_four | Question One |
|
||||
| Test questions | multichoice | Multi-choice-001 | one_of_four | Question One |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | preferredbehaviour | canredoquestions |
|
||||
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | 1 |
|
||||
@ -40,3 +40,18 @@ Feature: Clear my answers
|
||||
Then I should not see "Clear my choice"
|
||||
And I click on "Check" "button" in the "Question One" "question"
|
||||
And I should see "Please select an answer" in the "Question One" "question"
|
||||
|
||||
@javascript
|
||||
Scenario: Attempt a quiz and revisit a cleared answer.
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Quiz 1"
|
||||
And I press "Attempt quiz now"
|
||||
And I should see "Question One"
|
||||
And I click on "Four" "radio" in the "Question One" "question"
|
||||
And I follow "Finish attempt ..."
|
||||
And I click on "Return to attempt" "button"
|
||||
And I click on "Clear my choice" "button" in the "Question One" "question"
|
||||
And I follow "Finish attempt ..."
|
||||
And I click on "Return to attempt" "button"
|
||||
Then I should not see "Clear my choice"
|
||||
|
@ -126,6 +126,75 @@ class qtype_multichoice_walkthrough_test extends qbehaviour_walkthrough_test_bas
|
||||
new question_pattern_expectation('/class="r1"/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for clear choice option.
|
||||
*/
|
||||
public function test_deferredfeedback_feedback_multichoice_clearchoice() {
|
||||
|
||||
// Create a multichoice, single question.
|
||||
$mc = test_question_maker::make_a_multichoice_single_question();
|
||||
$mc->shuffleanswers = false;
|
||||
|
||||
$clearchoice = -1;
|
||||
$rightchoice = 0;
|
||||
$wrongchoice = 2;
|
||||
|
||||
$this->start_attempt_at_question($mc, 'deferredfeedback', 3);
|
||||
|
||||
// Let's first submit the wrong choice (2).
|
||||
$this->process_submission(array('answer' => $wrongchoice)); // Wrong choice (2).
|
||||
|
||||
$this->check_current_mark(null);
|
||||
// Clear choice radio should not be checked.
|
||||
$this->check_current_output(
|
||||
$this->get_contains_mc_radio_expectation($rightchoice, true, false), // Not checked.
|
||||
$this->get_contains_mc_radio_expectation($rightchoice + 1, true, false), // Not checked.
|
||||
$this->get_contains_mc_radio_expectation($rightchoice + 2, true, true), // Wrong choice (2) checked.
|
||||
$this->get_contains_mc_radio_expectation($clearchoice, true, false), // Not checked.
|
||||
$this->get_does_not_contain_correctness_expectation(),
|
||||
$this->get_does_not_contain_feedback_expectation()
|
||||
);
|
||||
|
||||
// Now, let's clear our previous choice.
|
||||
$this->process_submission(array('answer' => $clearchoice)); // Clear choice (-1).
|
||||
$this->check_current_mark(null);
|
||||
|
||||
// This time, the clear choice radio should be the only one checked.
|
||||
$this->check_current_output(
|
||||
$this->get_contains_mc_radio_expectation($rightchoice, true, false), // Not checked.
|
||||
$this->get_contains_mc_radio_expectation($rightchoice + 1, true, false), // Not checked.
|
||||
$this->get_contains_mc_radio_expectation($rightchoice + 2, true, false), // Not checked.
|
||||
$this->get_contains_mc_radio_expectation($clearchoice, true, true), // Clear choice radio checked.
|
||||
$this->get_does_not_contain_correctness_expectation(),
|
||||
$this->get_does_not_contain_feedback_expectation()
|
||||
);
|
||||
|
||||
// Finally, let's submit the right choice.
|
||||
$this->process_submission(array('answer' => $rightchoice)); // Right choice (0).
|
||||
$this->check_current_state(question_state::$complete);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
$this->get_contains_mc_radio_expectation($rightchoice, true, true),
|
||||
$this->get_contains_mc_radio_expectation($rightchoice + 1, true, false),
|
||||
$this->get_contains_mc_radio_expectation($rightchoice + 2, true, false),
|
||||
$this->get_contains_mc_radio_expectation($clearchoice, true, false),
|
||||
$this->get_does_not_contain_correctness_expectation(),
|
||||
$this->get_does_not_contain_feedback_expectation()
|
||||
);
|
||||
|
||||
// Finish the attempt.
|
||||
$this->finish();
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$gradedright);
|
||||
$this->check_current_mark(3);
|
||||
$this->check_current_output(
|
||||
$this->get_contains_mc_radio_expectation($rightchoice, false, true),
|
||||
$this->get_contains_correct_expectation(),
|
||||
new question_pattern_expectation('/class="r0 correct"/'),
|
||||
new question_pattern_expectation('/class="r1"/'));
|
||||
}
|
||||
|
||||
public function test_deferredfeedback_feedback_multichoice_multi_showstandardunstruction_yes() {
|
||||
|
||||
// Create a multichoice, multi question.
|
||||
|
Loading…
x
Reference in New Issue
Block a user