1
0
mirror of https://github.com/moodle/moodle.git synced 2025-04-25 10:26:17 +02:00

MDL-63944 Question: Convert toggle all to generic module

This commit is contained in:
Andrew Nicols 2019-01-02 15:22:09 +08:00 committed by VinhLe
parent b65bc972e6
commit 270fd3f5e4
7 changed files with 187 additions and 107 deletions

@ -0,0 +1 @@
define(["jquery","core/pubsub"],function(a,b){var c=!1,d={checkboxToggled:"core/checkbox-toggleall:checkboxToggled"},e=function(a,b){return a.find('[data-action="toggle"][data-togglegroup="'+b+'"]')},f=function(a,b){return e(a,b).filter('[data-toggle="slave"]')},g=function(a,b){return e(a,b).filter('[data-toggle="master"]')},h=function(c){var e=c.data.root,g=a(c.target),h=g.data("togglegroup"),i=g.is(":checked"),k=f(e,h),l=k.filter(":checked");j(e,h,i),k.prop("checked",i),b.publish(d.checkboxToggled,{root:e,toggleGroupName:h,slaves:k,checkedSlaves:l,anyChecked:i})},i=function(c){var e=c.data.root,g=a(c.target),h=g.data("togglegroup"),i=f(e,h),k=i.filter(":checked"),l=i.length===k.length;j(e,h,l),b.publish(d.checkboxToggled,{root:e,toggleGroupName:h,slaves:i,checkedSlaves:k,anyChecked:!!k.length})},j=function(b,c,d){var e=g(b,c);e.prop("checked",d),e.each(function(c,e){e=a(e);var f,g=b.find('[for="'+e.attr("id")+'"]');g.length&&(f=d?e.data("toggle-deselectall"):e.data("toggle-selectall"),g.html()!==f&&g.html(f))})},k=function(){if(!c){c=!0;var b=a(document.body);b.on("change",'[data-action="toggle"][data-toggle="master"]',{root:b},h),b.on("change",'[data-action="toggle"][data-toggle="slave"]',{root:b},i)}};return{init:function(){k()},events:d}});

@ -0,0 +1,126 @@
// 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/>.
/**
* A module to help with toggle select/deselect all.
*
* @module core/checkbox-toggleall
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/pubsub'], function($, PubSub) {
var registered = false;
var events = {
checkboxToggled: 'core/checkbox-toggleall:checkboxToggled',
};
var getAllCheckboxes = function(root, toggleGroup) {
return root.find('[data-action="toggle"][data-togglegroup="' + toggleGroup + '"]');
};
var getAllSlaveCheckboxes = function(root, toggleGroup) {
return getAllCheckboxes(root, toggleGroup).filter('[data-toggle="slave"]');
};
var getControlCheckboxes = function(root, toggleGroup) {
return getAllCheckboxes(root, toggleGroup).filter('[data-toggle="master"]');
};
var toggleSlavesFromMasters = function(e) {
var root = e.data.root;
var target = $(e.target);
var toggleGroupName = target.data('togglegroup');
var targetState = target.is(':checked');
var slaves = getAllSlaveCheckboxes(root, toggleGroupName);
var checkedSlaves = slaves.filter(':checked');
setMasterStates(root, toggleGroupName, targetState);
// Set the slave checkboxes from the masters.
slaves.prop('checked', targetState);
PubSub.publish(events.checkboxToggled, {
root: root,
toggleGroupName: toggleGroupName,
slaves: slaves,
checkedSlaves: checkedSlaves,
anyChecked: targetState,
});
};
var toggleMastersFromSlaves = function(e) {
var root = e.data.root;
var target = $(e.target);
var toggleGroupName = target.data('togglegroup');
var slaves = getAllSlaveCheckboxes(root, toggleGroupName);
var checkedSlaves = slaves.filter(':checked');
var targetState = (slaves.length === checkedSlaves.length);
setMasterStates(root, toggleGroupName, targetState);
PubSub.publish(events.checkboxToggled, {
root: root,
toggleGroupName: toggleGroupName,
slaves: slaves,
checkedSlaves: checkedSlaves,
anyChecked: !!checkedSlaves.length,
});
};
var setMasterStates = function(root, toggleGroupName, targetState) {
// Set the master checkboxes value and ARIA labels..
var masters = getControlCheckboxes(root, toggleGroupName);
masters.prop('checked', targetState);
masters.each(function(i, masterCheckbox) {
masterCheckbox = $(masterCheckbox);
var masterLabel = root.find('[for="' + masterCheckbox.attr('id') + '"]');
var targetString;
if (masterLabel.length) {
if (targetState) {
targetString = masterCheckbox.data('toggle-deselectall');
} else {
targetString = masterCheckbox.data('toggle-selectall');
}
if (masterLabel.html() !== targetString) {
masterLabel.html(targetString);
}
}
});
};
var registerListeners = function() {
if (!registered) {
registered = true;
var root = $(document.body);
root.on('change', '[data-action="toggle"][data-toggle="master"]', {root: root}, toggleSlavesFromMasters);
root.on('change', '[data-action="toggle"][data-toggle="slave"]', {root: root}, toggleMastersFromSlaves);
}
};
return {
init: function() {
registerListeners();
},
events: events,
};
});

@ -1 +1 @@
define(["jquery","core/str","core/notification"],function(a,b,c){return{_strings:null,_buttons:null,init:function(){var d=a("#qbheadercheckbox");if(0!=d.length){var e=this;b.get_strings([{key:"selectall",component:"moodle"},{key:"deselectall",component:"moodle"}]).then(function(b){e._strings=b,d.attr({disabled:!1,checked:0!=e._getSizeChecked(),title:b[0]}),d.click(e,e._headerClick),e._buttons=a(".modulespecificbuttonscontainer input, .modulespecificbuttonscontainer select, .modulespecificbuttonscontainer link, .modulespecificbuttonscontainer link"),e._buttons.attr("disabled",0==e._getSizeChecked()),e._buttons.length>0&&a(".categoryquestionscontainer").delegate('td.checkbox input[type="checkbox"]',"change",e,e._questionClick)}).fail(c.exception)}},_headerClick:function(b){var c=b.data,d=a("#qbheadercheckbox"),e=d.is(":checked"),f=e?1:0;a("#categoryquestions tbody [type=checkbox]").prop("checked",e),c._buttons.attr("disabled",0===c._getSizeChecked()),d.attr("title",c._strings[f])},_questionClick:function(b){var c=b.data,d=a("#qbheadercheckbox"),e=c._getSizeChecked(),f=a("#categoryquestions tbody [type=checkbox]").length,g=0!=e&&e==f;d.prop("checked",g),c._buttons.attr("disabled",0===e)},_getSizeChecked:function(){return a('#categoryquestions td.checkbox input[type="checkbox"]:checked').length}}});
define(["jquery","core/pubsub","core/checkbox-toggleall"],function(a,b,c){var d=function(){b.subscribe(c.events.checkboxToggled,e)},e=function(a){"qbank"===a.toggleGroupName&&f(a.anyChecked)},f=function(b){var c=a(".modulespecificbuttonscontainer").find("input, select, link");c.attr("disabled",!b)};return{init:function(){f(!1),d()}}});

113
question/amd/src/qbankmanager.js Executable file → Normal file

@ -22,107 +22,34 @@
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/notification'], function($, str, notification) {
define(['jquery', 'core/pubsub', 'core/checkbox-toggleall'], function($, PubSub, ToggleAll) {
var registerListeners = function() {
PubSub.subscribe(ToggleAll.events.checkboxToggled, toggleButtonStates);
};
var toggleButtonStates = function(data) {
if ('qbank' !== data.toggleGroupName) {
return;
}
setButtonState(data.anyChecked);
};
var setButtonState = function(state) {
var buttons = $('.modulespecificbuttonscontainer').find('input, select, link');
buttons.attr('disabled', !state);
};
return {
/**
* A reference to the header checkbox.
*
* @property _strings
* @type Node
* @private
*/
_strings: null,
/**
* A reference to the add to quiz button.
*
* @property _buttons
* @type Node
* @private
*/
_buttons: null,
/**
* Set up the Question Bank Manager.
*
* @method init
*/
init: function() {
// Find the header checkbox, and set the initial values.
var header = $('#qbheadercheckbox');
if (header.length == 0) {
return;
}
var self = this;
str.get_strings([
{key: 'selectall', component: 'moodle'},
{key: 'deselectall', component: 'moodle'},
]).then(function(strings) {
self._strings = strings;
header.attr({
disabled: false,
checked: self._getSizeChecked() != 0,
title: strings[0]
});
header.click(self, self._headerClick);
self._buttons = $(".modulespecificbuttonscontainer input, .modulespecificbuttonscontainer select," +
" .modulespecificbuttonscontainer link, .modulespecificbuttonscontainer link");
self._buttons.attr('disabled', self._getSizeChecked() == 0);
if (self._buttons.length > 0) {
$('.categoryquestionscontainer')
.delegate('td.checkbox input[type="checkbox"]', 'change', self, self._questionClick);
}
return;
}).fail(notification.exception);
setButtonState(false);
registerListeners();
},
/**
* Handle toggling of the header checkbox.
*
* @method _headerClick
* @param {Event} event of element.
* @private
*/
_headerClick: function(event) {
var self = event.data;
var header = $('#qbheadercheckbox');
var isCheckedHeader = header.is(':checked');
var indexStringTitle = isCheckedHeader ? 1 : 0;
$("#categoryquestions tbody [type=checkbox]").prop("checked", isCheckedHeader);
self._buttons.attr('disabled', self._getSizeChecked() === 0);
header.attr('title', self._strings[indexStringTitle]);
},
/**
* Handle toggling of a question checkbox.
*
* @method _questionClick
* @param {Event} event of element.
* @private
*/
_questionClick: function(event) {
var self = event.data;
var header = $('#qbheadercheckbox');
var areChecked = self._getSizeChecked();
var lengthCheckbox = $("#categoryquestions tbody [type=checkbox]").length;
var ischeckboxHeader = (areChecked != 0) && areChecked == lengthCheckbox;
header.prop('checked', ischeckboxHeader);
self._buttons.attr('disabled', (areChecked === 0));
},
/**
* Get size all row checked of table.
* @method _getSizeChecked
* @return {Number}
* @private
*/
_getSizeChecked: function() {
return $('#categoryquestions td.checkbox input[type="checkbox"]:checked').length;
}
};
});

@ -26,7 +26,9 @@ class checkbox_column extends column_base {
protected $strselect;
public function init() {
$this->strselect = get_string('select');
global $PAGE;
$PAGE->requires->js_call_amd('core/checkbox-toggleall', 'init');
}
public function get_name() {
@ -34,22 +36,42 @@ class checkbox_column extends column_base {
}
protected function get_title() {
return '<input type="checkbox" disabled="disabled" id="qbheadercheckbox" name="qbheadercheckbox" />' .
'<label class="accesshide" for="qbheadercheckbox">' . get_string('selectall', 'moodle') . '</label>';
$input = \html_writer::empty_tag('input', [
'id' => 'qbheadercheckbox',
'title' => get_string('select'),
'name' => 'qbheadercheckbox',
'type' => 'checkbox',
'value' => '1',
'data-action' => 'toggle',
'data-toggle' => 'master',
'data-togglegroup' => 'qbank',
'data-toggle-selectall' => get_string('selectall', 'moodle'),
'data-toggle-deselectall' => get_string('deselectall', 'moodle'),
]);
$label = \html_writer::tag('label', get_string('selectall', 'moodle'), [
'class' => 'accesshide',
'for' => 'qbheadercheckbox',
]);
return $input . $label;
}
protected function get_title_tip() {
global $PAGE;
$PAGE->requires->strings_for_js(array('selectall', 'deselectall'), 'moodle');
$PAGE->requires->js_call_amd('core_question/qbankmanager', 'init');
return get_string('selectquestionsforbulk', 'question');
}
protected function display_content($question, $rowclasses) {
global $PAGE;
echo '<input title="' . $this->strselect . '" type="checkbox" name="q' .
$question->id . '" id="checkq' . $question->id . '" value="1"/>';
echo \html_writer::empty_tag('input', [
'title' => get_string('select'),
'type' => 'checkbox',
'name' => "q{$question->id}",
'id' => "checkq{$question->id}",
'value' => '1',
'data-action' => 'toggle',
'data-toggle' => 'slave',
'data-togglegroup' => 'qbank',
]);
}
public function get_required_fields() {

@ -773,10 +773,14 @@ class view {
* @param array $addcontexts contexts where the user is allowed to add new questions.
*/
protected function display_bottom_controls($totalnumber, $recurse, $category, \context $catcontext, array $addcontexts) {
global $PAGE;
$caneditall = has_capability('moodle/question:editall', $catcontext);
$canuseall = has_capability('moodle/question:useall', $catcontext);
$canmoveall = has_capability('moodle/question:moveall', $catcontext);
$PAGE->requires->js_call_amd('core_question/qbankmanager', 'init');
echo '<div class="modulespecificbuttonscontainer">';
if ($caneditall || $canmoveall || $canuseall) {
echo '<strong>&nbsp;'.get_string('withselected', 'question').':</strong><br />';

@ -24,7 +24,7 @@ Feature: The questions in the question bank can be selected in various ways
| Test questions | numerical | C question 3 name | teacher1 | Question 3 text |
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Questions" node in "Course administration > Question bank"
And I navigate to "Questions" in current page administration
@javascript
Scenario: The question text can be chosen all in the list of questions
@ -33,7 +33,7 @@ Feature: The questions in the question bank can be selected in various ways
Then the field "A question 1 name" matches value "1"
And the field "B question 2 name" matches value "1"
And the field "C question 3 name" matches value "1"
When I click on "Select all" "checkbox"
When I click on "Deselect all" "checkbox"
Then the field "A question 1 name" matches value ""
And the field "B question 2 name" matches value ""
And the field "C question 3 name" matches value ""
@ -45,7 +45,7 @@ Feature: The questions in the question bank can be selected in various ways
Then the field "Select all" matches value ""
When I click on "B question 2 name" "checkbox"
And I click on "C question 3 name" "checkbox"
Then the field "Select all" matches value "1"
Then the field "Deselect all" matches value "1"
@javascript
Scenario: The action button can be disabled when the question not be chosen in the list of questions