MDL-77656 quiz editing: customisable numbers only in unshuffled sections
This works by always outputting both the customised and uncustomised number into the HTML of the Questions page, then uses CSS & JS to show the appropriate one as shuffle is toggled.
This commit is contained in:
@@ -390,7 +390,10 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
|
||||
$sectionstyle = '';
|
||||
if ($structure->is_only_one_slot_in_section($section)) {
|
||||
$sectionstyle = ' only-has-one-slot';
|
||||
$sectionstyle .= ' only-has-one-slot';
|
||||
}
|
||||
if ($section->shufflequestions) {
|
||||
$sectionstyle .= ' shuffled';
|
||||
}
|
||||
|
||||
if ($section->heading) {
|
||||
@@ -750,9 +753,8 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
}
|
||||
|
||||
if ($structure->can_display_number_be_customised($slot)) {
|
||||
$questionnumbercustomised = $this->output->render($structure->make_slot_display_number_in_place_editable(
|
||||
$questionnumber = $this->output->render($structure->make_slot_display_number_in_place_editable(
|
||||
$slotid, $structure->get_context()));
|
||||
$questionnumber = $questionnumbercustomised;
|
||||
} else {
|
||||
$questionnumber = $structure->get_displayed_number_for_slot($slot);
|
||||
}
|
||||
@@ -761,7 +763,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
'slotid' => $slotid,
|
||||
'canbeedited' => $structure->can_be_edited(),
|
||||
'checkbox' => $this->get_checkbox_render($structure, $slot),
|
||||
'questionnumber' => $this->question_number($questionnumber),
|
||||
'questionnumber' => $this->question_number($questionnumber, $structure->get_slot_by_number($slot)->defaultnumber),
|
||||
'questionname' => $this->get_question_name_for_slot($structure, $slot, $pageurl),
|
||||
'questionicons' => $this->get_action_icon($structure, $slot, $pageurl),
|
||||
'questiondependencyicon' => ($structure->can_be_edited() ? $this->question_dependency_icon($structure, $slot) : ''),
|
||||
@@ -865,14 +867,18 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Output the question number.
|
||||
* @param string $number The number, or 'i'.
|
||||
*
|
||||
* @param string $editablenumber The, which may be an in-place editable.
|
||||
* @param string $uncustomisednumber The un-customised number number, or 'i'.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function question_number($number) {
|
||||
if ($number !== get_string('infoshort', 'quiz')) {
|
||||
$number = html_writer::span(get_string('question'), 'accesshide') . ' ' . $number;
|
||||
public function question_number(string $editablenumber, string $uncustomisednumber) {
|
||||
if ($editablenumber !== get_string('infoshort', 'quiz')) {
|
||||
$editablenumber = html_writer::span(get_string('question'), 'accesshide') . ' ' . $editablenumber;
|
||||
$uncustomisednumber = html_writer::span(get_string('question'), 'accesshide') . ' ' . $uncustomisednumber;
|
||||
}
|
||||
return html_writer::tag('span', $number, ['class' => 'slotnumber']);
|
||||
return html_writer::tag('span', $editablenumber, ['class' => 'slotnumber unshuffled']) .
|
||||
html_writer::tag('span', $uncustomisednumber, ['class' => 'slotnumber shuffled']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,37 +139,32 @@ class structure {
|
||||
* @return string the question number ot display for this slot.
|
||||
*/
|
||||
public function get_displayed_number_for_slot($slotnumber) {
|
||||
return $this->slotsinorder[$slotnumber]->displayednumber;
|
||||
$slot = $this->slotsinorder[$slotnumber];
|
||||
return $slot->displaynumber ?? $slot->defaultnumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the question number can be customised.
|
||||
* Check the question has a number that could be customised.
|
||||
*
|
||||
* @param int $slotnumber
|
||||
* @return bool
|
||||
*/
|
||||
public function can_display_number_be_customised(int $slotnumber): bool {
|
||||
if (!$this->is_real_question($slotnumber)) {
|
||||
return false;
|
||||
}
|
||||
$slot = $this->get_slot_by_number($slotnumber);
|
||||
if ($slot->section->shufflequestions) {
|
||||
return false;
|
||||
}
|
||||
if (quiz_has_attempts($this->quizobj->get_quizid())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return $this->is_real_question($slotnumber) && !quiz_has_attempts($this->quizobj->get_quizid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the question number is customised.
|
||||
*
|
||||
* @param int $slotid
|
||||
* @return bool
|
||||
* @todo MDL-76612 Final deprecation in Moodle 4.6
|
||||
* @deprecated since 4.2. $slot->displayednumber is no longer used. If you need this,
|
||||
* use isset(...->displaynumber), but this method was not used.
|
||||
*/
|
||||
public function is_display_number_customised(int $slotid): bool {
|
||||
$slotobj = $this->get_slot_by_id($slotid);
|
||||
return $slotobj->displayednumber === $slotobj->displaynumber;
|
||||
return isset($slotobj->displaynumber);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,11 +179,7 @@ class structure {
|
||||
$editable = has_capability('mod/quiz:manage', $context);
|
||||
|
||||
// Get the current value.
|
||||
if ($this->is_display_number_customised($slotid)) {
|
||||
$value = $slot->displaynumber;
|
||||
} else {
|
||||
$value = $this->get_displayed_number_for_slot($slot->slot);
|
||||
}
|
||||
$value = $slot->displaynumber ?? $slot->defaultnumber;
|
||||
$displayvalue = s($value);
|
||||
|
||||
return new inplace_editable('mod_quiz', 'slotdisplaynumber', $slotid,
|
||||
@@ -729,7 +720,6 @@ class structure {
|
||||
global $DB;
|
||||
|
||||
$slots = qbank_helper::get_question_structure($this->quizobj->get_quizid(), $this->quizobj->get_context());
|
||||
|
||||
$this->questions = [];
|
||||
$this->slotsinorder = [];
|
||||
foreach ($slots as $slotdata) {
|
||||
@@ -759,10 +749,6 @@ class structure {
|
||||
}
|
||||
for ($slot = $section->firstslot; $slot <= $section->lastslot; $slot += 1) {
|
||||
$this->slotsinorder[$slot]->section = $section;
|
||||
if ($section->shufflequestions) {
|
||||
// Hide customised value and disable editing while shuffle checkbox is enabled.
|
||||
$this->slotsinorder[$slot]->displaynumber = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -773,17 +759,17 @@ class structure {
|
||||
protected function populate_question_numbers() {
|
||||
$number = 1;
|
||||
foreach ($this->slotsinorder as $slot) {
|
||||
if ($this->questions[$slot->questionid]->length == 0) {
|
||||
$slot->displayednumber = get_string('infoshort', 'quiz');
|
||||
$question = $this->questions[$slot->questionid];
|
||||
if ($question->length == 0) {
|
||||
$slot->displaynumber = null;
|
||||
$slot->defaultnumber = get_string('infoshort', 'quiz');
|
||||
} else {
|
||||
// Whether question numbering is customised or is numeric and automatically incremented.
|
||||
if (!empty($slot->displaynumber)) {
|
||||
$slot->displayednumber = $slot->displaynumber;
|
||||
} else {
|
||||
$slot->displayednumber = $number;
|
||||
}
|
||||
$number += 1;
|
||||
$slot->defaultnumber = $number;
|
||||
}
|
||||
if ($slot->displaynumber === '') {
|
||||
$slot->displaynumber = null;
|
||||
}
|
||||
$number += $question->length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -560,6 +560,18 @@ table.quizreviewsummary td.cell {
|
||||
min-width: 2em;
|
||||
display: inline-block;
|
||||
}
|
||||
#page-mod-quiz-edit li.section .slotnumber.unshuffled {
|
||||
display: inline-block;
|
||||
}
|
||||
#page-mod-quiz-edit li.section .slotnumber.shuffled {
|
||||
display: none;
|
||||
}
|
||||
#page-mod-quiz-edit li.section.shuffled .slotnumber.unshuffled {
|
||||
display: none;
|
||||
}
|
||||
#page-mod-quiz-edit li.section.shuffled .slotnumber.shuffled {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit .section-heading {
|
||||
margin-left: 20px;
|
||||
|
||||
@@ -93,8 +93,8 @@ Feature: Editing question numbering of the existing questions already in a quiz
|
||||
And I should see question "abcdefghijklmnop" in section "Section 2" in the quiz navigation
|
||||
|
||||
Scenario: Shuffling questions within a section with customised question numbers.
|
||||
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
And I should see "Section 1"
|
||||
When I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
Then I should see "Section 1"
|
||||
And I should see "i" on quiz page "1"
|
||||
And I should see "1.a" on quiz page "1"
|
||||
And I should see "1.b" on quiz page "1"
|
||||
@@ -102,8 +102,7 @@ Feature: Editing question numbering of the existing questions already in a quiz
|
||||
And I should see "3" on quiz page "2"
|
||||
And I should see "4" on quiz page "2"
|
||||
|
||||
When I set the field "Shuffle" to "1"
|
||||
And I reload the page
|
||||
And I set the field "Shuffle" to "1"
|
||||
And I should see "Section 1"
|
||||
And I should see "i" on quiz page "1"
|
||||
And I should see "1" on quiz page "1"
|
||||
@@ -111,9 +110,9 @@ Feature: Editing question numbering of the existing questions already in a quiz
|
||||
And I should see "Section 2"
|
||||
And I should see "3" on quiz page "2"
|
||||
And I should see "4" on quiz page "2"
|
||||
|
||||
When I set the field "Shuffle" to "0"
|
||||
And I reload the page
|
||||
|
||||
And I set the field "Shuffle" to "0"
|
||||
And I should see "Section 1"
|
||||
And I should see "i" on quiz page "1"
|
||||
And I should see "1.a" on quiz page "1"
|
||||
|
||||
+5
-4
@@ -1133,17 +1133,21 @@ Y.extend(SECTIONTOOLBOX, TOOLBOX, {
|
||||
* @param {EventFacade} ev The event that was fired.
|
||||
* @param {Node} button The button that triggered this action.
|
||||
* @param {Node} activity The activity node that this action will be performed on.
|
||||
* @param {String} action The action that has been requested.
|
||||
* @return Boolean
|
||||
*/
|
||||
edit_shuffle_questions: function(ev, button, activity) {
|
||||
var newvalue;
|
||||
if (activity.one(SELECTOR.EDITSHUFFLEQUESTIONSACTION).get('checked')) {
|
||||
newvalue = 1;
|
||||
activity.addClass('shuffled');
|
||||
} else {
|
||||
newvalue = 0;
|
||||
activity.removeClass('shuffled');
|
||||
}
|
||||
|
||||
// Prevent the default actions.
|
||||
ev.preventDefault();
|
||||
|
||||
// Get the element we're working on
|
||||
var data = {
|
||||
'class': 'section',
|
||||
@@ -1152,9 +1156,6 @@ Y.extend(SECTIONTOOLBOX, TOOLBOX, {
|
||||
'newshuffle': newvalue
|
||||
};
|
||||
|
||||
// Prevent the default actions.
|
||||
ev.preventDefault();
|
||||
|
||||
// Send request.
|
||||
var spinner = M.util.add_spinner(Y, activity.one(SELECTOR.EDITSHUFFLEAREA));
|
||||
this.send_request(data, spinner);
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -1133,17 +1133,21 @@ Y.extend(SECTIONTOOLBOX, TOOLBOX, {
|
||||
* @param {EventFacade} ev The event that was fired.
|
||||
* @param {Node} button The button that triggered this action.
|
||||
* @param {Node} activity The activity node that this action will be performed on.
|
||||
* @param {String} action The action that has been requested.
|
||||
* @return Boolean
|
||||
*/
|
||||
edit_shuffle_questions: function(ev, button, activity) {
|
||||
var newvalue;
|
||||
if (activity.one(SELECTOR.EDITSHUFFLEQUESTIONSACTION).get('checked')) {
|
||||
newvalue = 1;
|
||||
activity.addClass('shuffled');
|
||||
} else {
|
||||
newvalue = 0;
|
||||
activity.removeClass('shuffled');
|
||||
}
|
||||
|
||||
// Prevent the default actions.
|
||||
ev.preventDefault();
|
||||
|
||||
// Get the element we're working on
|
||||
var data = {
|
||||
'class': 'section',
|
||||
@@ -1152,9 +1156,6 @@ Y.extend(SECTIONTOOLBOX, TOOLBOX, {
|
||||
'newshuffle': newvalue
|
||||
};
|
||||
|
||||
// Prevent the default actions.
|
||||
ev.preventDefault();
|
||||
|
||||
// Send request.
|
||||
var spinner = M.util.add_spinner(Y, activity.one(SELECTOR.EDITSHUFFLEAREA));
|
||||
this.send_request(data, spinner);
|
||||
|
||||
+5
-4
@@ -317,17 +317,21 @@ Y.extend(SECTIONTOOLBOX, TOOLBOX, {
|
||||
* @param {EventFacade} ev The event that was fired.
|
||||
* @param {Node} button The button that triggered this action.
|
||||
* @param {Node} activity The activity node that this action will be performed on.
|
||||
* @param {String} action The action that has been requested.
|
||||
* @return Boolean
|
||||
*/
|
||||
edit_shuffle_questions: function(ev, button, activity) {
|
||||
var newvalue;
|
||||
if (activity.one(SELECTOR.EDITSHUFFLEQUESTIONSACTION).get('checked')) {
|
||||
newvalue = 1;
|
||||
activity.addClass('shuffled');
|
||||
} else {
|
||||
newvalue = 0;
|
||||
activity.removeClass('shuffled');
|
||||
}
|
||||
|
||||
// Prevent the default actions.
|
||||
ev.preventDefault();
|
||||
|
||||
// Get the element we're working on
|
||||
var data = {
|
||||
'class': 'section',
|
||||
@@ -336,9 +340,6 @@ Y.extend(SECTIONTOOLBOX, TOOLBOX, {
|
||||
'newshuffle': newvalue
|
||||
};
|
||||
|
||||
// Prevent the default actions.
|
||||
ev.preventDefault();
|
||||
|
||||
// Send request.
|
||||
var spinner = M.util.add_spinner(Y, activity.one(SELECTOR.EDITSHUFFLEAREA));
|
||||
this.send_request(data, spinner);
|
||||
|
||||
Reference in New Issue
Block a user