From e016d20e5f5d6d748077f4e0ea100f00de08c861 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Mon, 28 Feb 2022 13:30:54 +1100 Subject: [PATCH 1/3] MDL-71305 core_question: Remove duplicate strings --- lang/en/question.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lang/en/question.php b/lang/en/question.php index c30a3db43dd..aea74ec9404 100644 --- a/lang/en/question.php +++ b/lang/en/question.php @@ -356,8 +356,6 @@ $string['defaultmark'] = 'Default mark'; $string['errorsavingflags'] = 'Error saving the flag state.'; $string['feedback'] = 'Feedback'; $string['fillincorrect'] = 'Fill in correct responses'; -$string['flagged'] = 'Flagged'; -$string['flagthisquestion'] = 'Flag this question'; $string['generalfeedback'] = 'General feedback'; $string['generalfeedback_help'] = 'General feedback is shown to the student after they have completed the question. Unlike specific feedback, which depends on the question type and what response the student gave, the same general feedback text is shown to all students. @@ -390,7 +388,6 @@ $string['markoutofmax'] = 'Mark {$a->mark} out of {$a->max}'; $string['marks'] = 'Marks'; $string['noresponse'] = '[No response]'; $string['notanswered'] = 'Not answered'; -$string['notflagged'] = 'Not flagged'; $string['notgraded'] = 'Not graded'; $string['notshown'] = 'Not shown'; $string['notyetanswered'] = 'Not yet answered'; @@ -455,7 +452,6 @@ $string['restoremultipletopcats'] = 'The backup file contains more than one top- $string['rightanswer'] = 'Right answer'; $string['rightanswer_help'] = 'An automatically generated summary of the correct response. This can be limited, so you may wish to consider explaining the correct solution in the general feedback for the question, and turning this option off.'; $string['saved'] = 'Saved: {$a}'; -$string['saveflags'] = 'Save the state of the flags'; $string['settingsformultipletries'] = 'Multiple tries'; $string['showhidden'] = 'Also show old questions'; $string['showmarkandmax'] = 'Show mark and max'; From bc8bf406c8920a57c4eedc2a998b97f5a0f5bf37 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Mon, 7 Mar 2022 11:31:56 +1100 Subject: [PATCH 2/3] MDL-71305 core_question: Use toggle button for flag question element --- question/engine/lib.php | 12 ++---- question/engine/renderer.php | 27 ++++++------- question/flags.js | 73 ++++++++++++++++++++++++------------ 3 files changed, 66 insertions(+), 46 deletions(-) diff --git a/question/engine/lib.php b/question/engine/lib.php index 62990f180bd..ace64193025 100644 --- a/question/engine/lib.php +++ b/question/engine/lib.php @@ -747,26 +747,22 @@ abstract class question_flags { 'requires' => array('base', 'dom', 'event-delegate', 'io-base'), ); $actionurl = $CFG->wwwroot . '/question/toggleflag.php'; - $flagtext = array( - 0 => get_string('clickflag', 'question'), - 1 => get_string('clickunflag', 'question') - ); $flagattributes = array( 0 => array( 'src' => $OUTPUT->image_url('i/unflagged') . '', 'title' => get_string('clicktoflag', 'question'), - 'alt' => get_string('notflagged', 'question'), - // 'text' => get_string('clickflag', 'question'), + 'alt' => get_string('flagged', 'question'), // Label on toggle should not change. + 'text' => get_string('clickflag', 'question'), ), 1 => array( 'src' => $OUTPUT->image_url('i/flagged') . '', 'title' => get_string('clicktounflag', 'question'), 'alt' => get_string('flagged', 'question'), - // 'text' => get_string('clickunflag', 'question'), + 'text' => get_string('clickunflag', 'question'), ), ); $PAGE->requires->js_init_call('M.core_question_flags.init', - array($actionurl, $flagattributes, $flagtext), false, $module); + array($actionurl, $flagattributes), false, $module); $done = true; } } diff --git a/question/engine/renderer.php b/question/engine/renderer.php index be328f8447a..4ce0e7c193c 100644 --- a/question/engine/renderer.php +++ b/question/engine/renderer.php @@ -256,8 +256,6 @@ class core_question_renderer extends plugin_renderer_base { * @param int $flagsoption the option that says whether flags should be displayed. */ protected function question_flag(question_attempt $qa, $flagsoption) { - global $CFG; - $divattributes = array('class' => 'questionflag'); switch ($flagsoption) { @@ -283,17 +281,14 @@ class core_question_renderer extends plugin_renderer_base { $flagcontent = html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $id, 'value' => 0)) . - html_writer::empty_tag('input', $checkboxattributes) . html_writer::empty_tag('input', array('type' => 'hidden', 'value' => $postdata, 'class' => 'questionflagpostdata')) . + html_writer::empty_tag('input', $checkboxattributes) . html_writer::tag('label', $this->get_flag_html($qa->is_flagged(), $id . 'img'), array('id' => $id . 'label', 'for' => $id . 'checkbox')) . "\n"; $divattributes = array( 'class' => 'questionflag editable', - 'aria-atomic' => 'true', - 'aria-relevant' => 'text', - 'aria-live' => 'assertive', ); break; @@ -315,18 +310,16 @@ class core_question_renderer extends plugin_renderer_base { protected function get_flag_html($flagged, $id = '') { if ($flagged) { $icon = 'i/flagged'; - $alt = get_string('flagged', 'question'); $label = get_string('clickunflag', 'question'); } else { $icon = 'i/unflagged'; - $alt = get_string('notflagged', 'question'); $label = get_string('clickflag', 'question'); } - $attributes = array( + $attributes = [ 'src' => $this->image_url($icon), - 'alt' => $alt, + 'alt' => '', 'class' => 'questionflagimage', - ); + ]; if ($id) { $attributes['id'] = $id; } @@ -336,10 +329,14 @@ class core_question_renderer extends plugin_renderer_base { return $img; } - protected function edit_question_link(question_attempt $qa, - question_display_options $options) { - global $CFG; - + /** + * Generate the display of the edit question link. + * + * @param question_attempt $qa The question attempt to display. + * @param question_display_options $options controls what should and should not be displayed. + * @return string + */ + protected function edit_question_link(question_attempt $qa, question_display_options $options) { if (empty($options->editquestionparams)) { return ''; } diff --git a/question/flags.js b/question/flags.js index aa8dac16cc5..3720d2409b1 100644 --- a/question/flags.js +++ b/question/flags.js @@ -28,13 +28,11 @@ M.core_question_flags = { flagattributes: null, actionurl: null, - flagtext: null, listeners: [], - init: function(Y, actionurl, flagattributes, flagtext) { + init: function(Y, actionurl, flagattributes) { M.core_question_flags.flagattributes = flagattributes; M.core_question_flags.actionurl = actionurl; - M.core_question_flags.flagtext = flagtext; Y.all('div.questionflag').each(function(flagdiv, i) { var checkbox = flagdiv.one('input[type=checkbox]'); @@ -47,38 +45,67 @@ M.core_question_flags = { input.set('name', checkbox.get('name')); input.set('value', checkbox.get('checked') ? 1 : 0); - // Create an image input to replace the img tag. - var image = Y.Node.create(''); - var flagtext = Y.Node.create('.'); - M.core_question_flags.update_flag(input, image, flagtext); + var ariaPressed = checkbox.get('checked') ? 'true' : 'false'; + var toggle = Y.Node.create('' + + '.' + + ''); + M.core_question_flags.update_flag(input, toggle); checkbox.remove(); flagdiv.one('label').remove(); flagdiv.append(input); - flagdiv.append(image); - flagdiv.append(flagtext); + flagdiv.append(toggle); }); Y.delegate('click', function(e) { - var input = this.one('input.questionflagvalue'); - input.set('value', 1 - input.get('value')); - M.core_question_flags.update_flag(input, this.one('input.questionflagimage'), - this.one('span.questionflagtext')); - var postdata = this.one('input.questionflagpostdata').get('value') + - input.get('value'); - e.halt(); - Y.io(M.core_question_flags.actionurl , {method: 'POST', 'data': postdata}); - M.core_question_flags.fire_listeners(postdata); + M.core_question_flags.process(this); }, document.body, 'div.questionflag'); + Y.delegate('key', function(e) { + e.halt(); + if (e.keyCode == 13) { + M.core_question_flags.process(this); + } + }, document.body, 'down:enter, space', 'div.questionflag'); + Y.delegate('key', function(e) { + e.halt(); + M.core_question_flags.process(this); + }, document.body, 'up:space', 'div.questionflag'); }, - update_flag: function(input, image, flagtext) { + update_flag: function(input, toggle) { var value = input.get('value'); - image.setAttrs(M.core_question_flags.flagattributes[value]); - flagtext.replaceChild(flagtext.create(M.core_question_flags.flagtext[value]), - flagtext.get('firstChild')); - flagtext.set('title', M.core_question_flags.flagattributes[value].title); + toggle.setContent( + '' + + M.core_question_flags.flagattributes[value].text + ); + toggle.set('aria-pressed', parseInt(value) ? 'true' : 'false'); + toggle.set('aria-label', M.core_question_flags.flagattributes[value].alt); + if (M.core_question_flags.flagattributes[value].title != M.core_question_flags.flagattributes[value].text) { + toggle.set('title', M.core_question_flags.flagattributes[value].title); + } else { + toggle.removeAttribute('title'); + } + }, + + /** + * Process the change of flag status. + * + * @param {Y.Node} target The root element + */ + process: function(target) { + var input = target.one('input.questionflagvalue'); + input.set('value', 1 - input.get('value')); + M.core_question_flags.update_flag(input, target.one('[aria-pressed]')); + var postdata = target.one('input.questionflagpostdata').get('value') + + input.get('value'); + + Y.io(M.core_question_flags.actionurl, {method: 'POST', 'data': postdata}); + M.core_question_flags.fire_listeners(postdata); }, add_listener: function(listener) { From d237361d4ab87317ce921e3ea303565e8dabeca9 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Mon, 7 Mar 2022 11:32:14 +1100 Subject: [PATCH 3/3] MDL-71305 core_question: Deprecate notflagged language string --- lang/en/deprecated.txt | 3 ++- lang/en/question.php | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lang/en/deprecated.txt b/lang/en/deprecated.txt index 3a74976206f..1b214e0956a 100644 --- a/lang/en/deprecated.txt +++ b/lang/en/deprecated.txt @@ -78,4 +78,5 @@ loggedoff_help,core_message loggedoffdescription,core_message sendingvia,core_message sendingviawhen,core_message -close,core_contentbank \ No newline at end of file +close,core_contentbank +notflagged,core_question diff --git a/lang/en/question.php b/lang/en/question.php index aea74ec9404..150ccf6a9ff 100644 --- a/lang/en/question.php +++ b/lang/en/question.php @@ -253,7 +253,6 @@ $string['notagfiltersapplied'] = 'No tag filters applied'; $string['notenoughanswers'] = 'This type of question requires at least {$a} answers'; $string['notenoughdatatoeditaquestion'] = 'Neither a question id, nor a category id and question type, was specified.'; $string['notenoughdatatomovequestions'] = 'You need to provide the question ids of questions you want to move.'; -$string['notflagged'] = 'Not flagged'; $string['novirtualquestiontype'] = 'No virtual question type for question type {$a}'; $string['numqas'] = 'No. question attempts'; $string['numquestions'] = 'No. questions'; @@ -497,3 +496,6 @@ $string['yougotnright'] = 'You have correctly selected {$a->num}.'; $string['qbanknotfound'] = 'The \'{$a}\' question bank plugin doesn\'t exist or is not recognised.'; $string['noquestionbanks'] = 'No question bank plugin found.'; $string['questionloaderror'] = 'Could not load the question options.'; + +// Deprecated since Moodle 4.0. +$string['notflagged'] = 'Not flagged';