mirror of
https://github.com/moodle/moodle.git
synced 2025-06-02 22:25:04 +02:00
MDL-67917 user: Add skeleton for new participants filter
Part of MDL-67743 AMOS BEGIN CPY [select,core],[selectfiltertype,core_user] AMOS END
This commit is contained in:
parent
f456195599
commit
77ba77f10a
@ -22,7 +22,12 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['addcondition'] = 'Add condition';
|
||||
$string['applyfilters'] = 'Apply filters';
|
||||
$string['clearfilterrow'] = 'Remove filter row';
|
||||
$string['clearfilters'] = 'Clear filters';
|
||||
$string['countparticipantsfound'] = '{$a} participants found';
|
||||
$string['match'] = 'Match';
|
||||
$string['privacy:courserequestpath'] = 'Requested courses';
|
||||
$string['privacy:descriptionpath'] = 'Profile description';
|
||||
$string['privacy:devicespath'] = 'User devices';
|
||||
@ -126,6 +131,8 @@ $string['privacy:passwordresetpath'] = 'Password resets';
|
||||
$string['privacy:profileimagespath'] = 'Profile images';
|
||||
$string['privacy:privatefilespath'] = 'Private files';
|
||||
$string['privacy:sessionpath'] = 'Session data';
|
||||
$string['selectfiltertype'] = 'Select';
|
||||
$string['target:upcomingactivitiesdue'] = 'Upcoming activities due';
|
||||
$string['target:upcomingactivitiesdue_help'] = 'This target generates reminders for upcoming activities due.';
|
||||
$string['target:upcomingactivitiesdueinfo'] = 'All upcoming activities due insights are listed here. These students have received these insights directly.';
|
||||
$string['typeorselect'] = 'Type or select...';
|
||||
|
2
user/amd/build/local/participantsfilter/filter.min.js
vendored
Normal file
2
user/amd/build/local/participantsfilter/filter.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_user/local/participantsfilter/filter",["exports","core/form-autocomplete","./selectors","core/str"],function(a,b,c,d){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=e(b);c=e(c);function e(a){return a&&a.__esModule?a:{default:a}}function f(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function g(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function g(a){f(i,d,e,g,h,"next",a)}function h(a){f(i,d,e,g,h,"throw",a)}g(void 0)})}}function h(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function i(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function j(a,b,c){if(b)i(a.prototype,b);if(c)i(a,c);return a}var k=function(a){return a.querySelectorAll(":checked")},l=function(){function a(b,c){h(this,a);this.filterType=b;this.rootNode=c;this.addValueSelector()}j(a,[{key:"tearDown",value:function tearDown(){}},{key:"addValueSelector",value:function(){var a=g(regeneratorRuntime.mark(function a(){var c,e;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:c=this.getFilterValueNode();c.innerHTML=this.getSourceDataForFilter().outerHTML;e=c.querySelector("select");a.t0=b.default;a.t1=e;a.t2="1"==e.dataset.allowCustom;a.next=8;return(0,d.get_string)("typeorselect","core_user");case 8:a.t3=a.sent;a.t4=!e.multiple;a.t0.enhance.call(a.t0,a.t1,a.t2,null,a.t3,!1,!0,null,a.t4);case 11:case"end":return a.stop();}}},a,this)}));return function addValueSelector(){return a.apply(this,arguments)}}()},{key:"getSourceDataForFilter",value:function getSourceDataForFilter(){var a=this.rootNode.querySelector(c.default.filterset.regions.datasource);return a.querySelector(c.default.data.fields.byName(this.filterType))}},{key:"getFilterValueNode",value:function getFilterValueNode(){return this.filterRoot.querySelector(c.default.filter.regions.values)}},{key:"filterRoot",get:function get(){return this.rootNode.querySelector(c.default.filter.byName(this.filterType))}},{key:"name",get:function get(){return this.filterType}},{key:"jointype",get:function get(){return this.filterRoot.querySelector(c.default.filter.fields.join).value}},{key:"rawValues",get:function get(){var a=this.getFilterValueNode(),b=a.querySelector("select");return Object.values(k(b)).map(function(a){return a.value})}},{key:"values",get:function get(){return this.rawValues.map(function(a){return parseInt(a,10)})}},{key:"filterValue",get:function get(){return{name:this.name,jointype:this.jointype,values:this.values}}}]);return a}();a.default=l;return a.default});
|
||||
//# sourceMappingURL=filter.min.js.map
|
File diff suppressed because one or more lines are too long
2
user/amd/build/local/participantsfilter/filtertypes/courseid.min.js
vendored
Normal file
2
user/amd/build/local/participantsfilter/filtertypes/courseid.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_user/local/participantsfilter/filtertypes/courseid",["exports","../filter"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){c=function(a){return typeof a}}else{c=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return c(a)}function d(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function e(a){return function(){var b=this,c=arguments;return new Promise(function(e,f){var i=a.apply(b,c);function g(a){d(i,e,f,g,h,"next",a)}function h(a){d(i,e,f,g,h,"throw",a)}g(void 0)})}}function f(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function g(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function h(a,b,c){if(b)g(a.prototype,b);if(c)g(a,c);return a}function i(a,b){if("function"!=typeof b&&null!==b){throw new TypeError("Super expression must either be null or a function")}a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,writable:!0,configurable:!0}});if(b)j(a,b)}function j(a,b){j=Object.setPrototypeOf||function(a,b){a.__proto__=b;return a};return j(a,b)}function k(a){return function(){var b=p(a),c;if(n()){var d=p(this).constructor;c=Reflect.construct(b,arguments,d)}else{c=b.apply(this,arguments)}return l(this,c)}}function l(a,b){if(b&&("object"===c(b)||"function"==typeof b)){return b}return m(a)}function m(a){if(void 0===a){throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}return a}function n(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{Date.prototype.toString.call(Reflect.construct(Date,[],function(){}));return!0}catch(a){return!1}}function p(a){p=Object.setPrototypeOf?Object.getPrototypeOf:function(a){return a.__proto__||Object.getPrototypeOf(a)};return p(a)}var q=function(a){i(b,a);var c=k(b);function b(a,d){f(this,b);return c.call(this,a,d)}h(b,[{key:"addValueSelector",value:function(){var a=e(regeneratorRuntime.mark(function a(){return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:case"end":return a.stop();}}},a)}));return function addValueSelector(){return a.apply(this,arguments)}}()},{key:"filterValue",get:function get(){return{name:this.name,jointype:1,values:[parseInt(this.rootNode.dataset.tableCourseId,10)]}}}]);return b}(b.default);a.default=q;return a.default});
|
||||
//# sourceMappingURL=courseid.min.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../../src/local/participantsfilter/filtertypes/courseid.js"],"names":["filterType","filterSet","name","jointype","values","parseInt","rootNode","dataset","tableCourseId","Filter"],"mappings":"uLAuBA,uD,+9DAGI,WAAYA,CAAZ,CAAwBC,CAAxB,CAAmC,8BACzBD,CADyB,CACbC,CADa,CAElC,C,4TAWiB,CACd,MAAO,CACHC,IAAI,CAAE,KAAKA,IADR,CAEHC,QAAQ,CAAE,CAFP,CAGHC,MAAM,CAAE,CAACC,QAAQ,CAAC,KAAKC,QAAL,CAAcC,OAAd,CAAsBC,aAAvB,CAAsC,EAAtC,CAAT,CAHL,CAKV,C,cApBwBC,S","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Course ID filter.\n *\n * @module core_user/local/participantsfilter/filtertypes/courseid\n * @package core_user\n * @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Filter from '../filter';\n\nexport default class extends Filter {\n constructor(filterType, filterSet) {\n super(filterType, filterSet);\n }\n\n async addValueSelector() {\n // eslint-disable-line no-empty-function\n }\n\n /**\n * Get the composed value for this filter.\n *\n * @returns {Object}\n */\n get filterValue() {\n return {\n name: this.name,\n jointype: 1,\n values: [parseInt(this.rootNode.dataset.tableCourseId, 10)],\n };\n }\n}\n"],"file":"courseid.min.js"}
|
2
user/amd/build/local/participantsfilter/selectors.min.js
vendored
Normal file
2
user/amd/build/local/participantsfilter/selectors.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_user/local/participantsfilter/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a){return"[data-filterregion=\"".concat(a,"\"]")},c=function(a){return"[data-filteraction=\"".concat(a,"\"]")},d=function(a){return"[data-filterfield=\"".concat(a,"\"]")},e={filter:{region:b("filter"),actions:{remove:c("remove")},fields:{join:d("join"),type:d("type")},regions:{values:b("value")},byName:function byName(a){return"".concat(b("filter"),"[data-filter-type=\"").concat(a,"\"]")}},filterset:{region:b("actions"),actions:{addRow:c("add"),applyFilters:c("apply"),resetFilters:c("reset")},regions:{filterlist:b("filters"),datasource:b("filtertypedata")}},data:{fields:{byName:function byName(a){return"[data-field-name=\"".concat(a,"\"]")}},typeList:b("filtertypelist")}};a.default=e;return a.default});
|
||||
//# sourceMappingURL=selectors.min.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../src/local/participantsfilter/selectors.js"],"names":["getFilterRegion","region","getFilterAction","action","getFilterField","field","filter","actions","remove","fields","join","type","regions","values","byName","name","filterset","addRow","applyFilters","resetFilters","filterlist","datasource","data","typeList"],"mappings":"iKAwBMA,CAAAA,CAAe,CAAG,SAAAC,CAAM,uCAA2BA,CAA3B,Q,CACxBC,CAAe,CAAG,SAAAC,CAAM,uCAA2BA,CAA3B,Q,CACxBC,CAAc,CAAG,SAAAC,CAAK,sCAA0BA,CAA1B,Q,GAEb,CACXC,MAAM,CAAE,CACJL,MAAM,CAAED,CAAe,CAAC,QAAD,CADnB,CAEJO,OAAO,CAAE,CACLC,MAAM,CAAEN,CAAe,CAAC,QAAD,CADlB,CAFL,CAKJO,MAAM,CAAE,CACJC,IAAI,CAAEN,CAAc,CAAC,MAAD,CADhB,CAEJO,IAAI,CAAEP,CAAc,CAAC,MAAD,CAFhB,CALJ,CASJQ,OAAO,CAAE,CACLC,MAAM,CAAEb,CAAe,CAAC,OAAD,CADlB,CATL,CAYJc,MAAM,CAAE,gBAAAC,CAAI,kBAAOf,CAAe,CAAC,QAAD,CAAtB,gCAAsDe,CAAtD,QAZR,CADG,CAeXC,SAAS,CAAE,CACPf,MAAM,CAAED,CAAe,CAAC,SAAD,CADhB,CAEPO,OAAO,CAAE,CACLU,MAAM,CAAEf,CAAe,CAAC,KAAD,CADlB,CAELgB,YAAY,CAAEhB,CAAe,CAAC,OAAD,CAFxB,CAGLiB,YAAY,CAAEjB,CAAe,CAAC,OAAD,CAHxB,CAFF,CAOPU,OAAO,CAAE,CACLQ,UAAU,CAAEpB,CAAe,CAAC,SAAD,CADtB,CAELqB,UAAU,CAAErB,CAAe,CAAC,gBAAD,CAFtB,CAPF,CAfA,CA2BXsB,IAAI,CAAE,CACFb,MAAM,CAAE,CACJK,MAAM,CAAE,gBAAAC,CAAI,qCAAyBA,CAAzB,QADR,CADN,CAIFQ,QAAQ,CAAEvB,CAAe,CAAC,gBAAD,CAJvB,CA3BK,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module containing the selectors for user filters.\n *\n * @module core_user/local/user_filter/selectors\n * @package core_user\n * @copyright 2020 Michael Hawkins <michaelh@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst getFilterRegion = region => `[data-filterregion=\"${region}\"]`;\nconst getFilterAction = action => `[data-filteraction=\"${action}\"]`;\nconst getFilterField = field => `[data-filterfield=\"${field}\"]`;\n\nexport default {\n filter: {\n region: getFilterRegion('filter'),\n actions: {\n remove: getFilterAction('remove'),\n },\n fields: {\n join: getFilterField('join'),\n type: getFilterField('type'),\n },\n regions: {\n values: getFilterRegion('value'),\n },\n byName: name => `${getFilterRegion('filter')}[data-filter-type=\"${name}\"]`,\n },\n filterset: {\n region: getFilterRegion('actions'),\n actions: {\n addRow: getFilterAction('add'),\n applyFilters: getFilterAction('apply'),\n resetFilters: getFilterAction('reset'),\n },\n regions: {\n filterlist: getFilterRegion('filters'),\n datasource: getFilterRegion('filtertypedata'),\n },\n },\n data: {\n fields: {\n byName: name => `[data-field-name=\"${name}\"]`,\n },\n typeList: getFilterRegion('filtertypelist'),\n },\n};\n"],"file":"selectors.min.js"}
|
2
user/amd/build/participantsfilter.min.js
vendored
Normal file
2
user/amd/build/participantsfilter.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
user/amd/build/participantsfilter.min.js.map
Normal file
1
user/amd/build/participantsfilter.min.js.map
Normal file
File diff suppressed because one or more lines are too long
180
user/amd/src/local/participantsfilter/filter.js
Normal file
180
user/amd/src/local/participantsfilter/filter.js
Normal file
@ -0,0 +1,180 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Base Filter class for a filter type in the participants filter UI.
|
||||
*
|
||||
* @module core_user/local/participantsfilter/filter
|
||||
* @package core_user
|
||||
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
import Autocomplete from 'core/form-autocomplete';
|
||||
import Selectors from './selectors';
|
||||
import {get_string as getString} from 'core/str';
|
||||
|
||||
/**
|
||||
* Fetch all checked options in the select.
|
||||
*
|
||||
* This is a poor-man's polyfill for select.selectedOptions, which is not available in IE11.
|
||||
*
|
||||
* @param {HTMLSelectElement} select
|
||||
* @returns {HTMLOptionElement[]} All selected options
|
||||
*/
|
||||
const getOptionsForSelect = select => {
|
||||
return select.querySelectorAll(':checked');
|
||||
};
|
||||
|
||||
export default class {
|
||||
|
||||
/**
|
||||
* Constructor for a new filter.
|
||||
*
|
||||
* @param {String} filterType The type of filter that this relates to
|
||||
* @param {HTMLElement} rootNode The root node for the participants filterset
|
||||
*/
|
||||
constructor(filterType, rootNode) {
|
||||
this.filterType = filterType;
|
||||
this.rootNode = rootNode;
|
||||
|
||||
this.addValueSelector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any tear-down for this filter type.
|
||||
*/
|
||||
tearDown() {
|
||||
// eslint-disable-line no-empty-function
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the value selector to the filter row.
|
||||
*/
|
||||
async addValueSelector() {
|
||||
const filterValueNode = this.getFilterValueNode();
|
||||
|
||||
// Copy the data in place.
|
||||
filterValueNode.innerHTML = this.getSourceDataForFilter().outerHTML;
|
||||
|
||||
const dataSource = filterValueNode.querySelector('select');
|
||||
|
||||
Autocomplete.enhance(
|
||||
// The source select element.
|
||||
dataSource,
|
||||
|
||||
// Whether to allow 'tags' (custom entries).
|
||||
dataSource.dataset.allowCustom == "1",
|
||||
|
||||
// We do not require AJAX at all as standard.
|
||||
null,
|
||||
|
||||
// The string to use as a placeholder.
|
||||
await getString('typeorselect', 'core_user'),
|
||||
|
||||
// Disable case sensitivity on searches.
|
||||
false,
|
||||
|
||||
// Show suggestions.
|
||||
true,
|
||||
|
||||
// Do not override the 'no suggestions' string.
|
||||
null,
|
||||
|
||||
// Close the suggestions if this is not a multi-select.
|
||||
!dataSource.multiple
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root node for this filter.
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
get filterRoot() {
|
||||
return this.rootNode.querySelector(Selectors.filter.byName(this.filterType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the possible data for this filter type.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
getSourceDataForFilter() {
|
||||
const filterDataNode = this.rootNode.querySelector(Selectors.filterset.regions.datasource);
|
||||
|
||||
return filterDataNode.querySelector(Selectors.data.fields.byName(this.filterType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTMLElement which contains the value selector.
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
getFilterValueNode() {
|
||||
return this.filterRoot.querySelector(Selectors.filter.regions.values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this filter.
|
||||
*
|
||||
* @returns {String}
|
||||
*/
|
||||
get name() {
|
||||
return this.filterType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of join specified.
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
get jointype() {
|
||||
return this.filterRoot.querySelector(Selectors.filter.fields.join).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of raw values for this filter type.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
get rawValues() {
|
||||
const filterValueNode = this.getFilterValueNode();
|
||||
const filterValueSelect = filterValueNode.querySelector('select');
|
||||
|
||||
return Object.values(getOptionsForSelect(filterValueSelect)).map(option => option.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of values for this filter type.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
get values() {
|
||||
return this.rawValues.map(option => parseInt(option, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the composed value for this filter.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
get filterValue() {
|
||||
return {
|
||||
name: this.name,
|
||||
jointype: this.jointype,
|
||||
values: this.values,
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Course ID filter.
|
||||
*
|
||||
* @module core_user/local/participantsfilter/filtertypes/courseid
|
||||
* @package core_user
|
||||
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
import Filter from '../filter';
|
||||
|
||||
export default class extends Filter {
|
||||
constructor(filterType, filterSet) {
|
||||
super(filterType, filterSet);
|
||||
}
|
||||
|
||||
async addValueSelector() {
|
||||
// eslint-disable-line no-empty-function
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the composed value for this filter.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
get filterValue() {
|
||||
return {
|
||||
name: this.name,
|
||||
jointype: 1,
|
||||
values: [parseInt(this.rootNode.dataset.tableCourseId, 10)],
|
||||
};
|
||||
}
|
||||
}
|
62
user/amd/src/local/participantsfilter/selectors.js
Normal file
62
user/amd/src/local/participantsfilter/selectors.js
Normal file
@ -0,0 +1,62 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Module containing the selectors for user filters.
|
||||
*
|
||||
* @module core_user/local/user_filter/selectors
|
||||
* @package core_user
|
||||
* @copyright 2020 Michael Hawkins <michaelh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
const getFilterRegion = region => `[data-filterregion="${region}"]`;
|
||||
const getFilterAction = action => `[data-filteraction="${action}"]`;
|
||||
const getFilterField = field => `[data-filterfield="${field}"]`;
|
||||
|
||||
export default {
|
||||
filter: {
|
||||
region: getFilterRegion('filter'),
|
||||
actions: {
|
||||
remove: getFilterAction('remove'),
|
||||
},
|
||||
fields: {
|
||||
join: getFilterField('join'),
|
||||
type: getFilterField('type'),
|
||||
},
|
||||
regions: {
|
||||
values: getFilterRegion('value'),
|
||||
},
|
||||
byName: name => `${getFilterRegion('filter')}[data-filter-type="${name}"]`,
|
||||
},
|
||||
filterset: {
|
||||
region: getFilterRegion('actions'),
|
||||
actions: {
|
||||
addRow: getFilterAction('add'),
|
||||
applyFilters: getFilterAction('apply'),
|
||||
resetFilters: getFilterAction('reset'),
|
||||
},
|
||||
regions: {
|
||||
filterlist: getFilterRegion('filters'),
|
||||
datasource: getFilterRegion('filtertypedata'),
|
||||
},
|
||||
},
|
||||
data: {
|
||||
fields: {
|
||||
byName: name => `[data-field-name="${name}"]`,
|
||||
},
|
||||
typeList: getFilterRegion('filtertypelist'),
|
||||
},
|
||||
};
|
330
user/amd/src/participantsfilter.js
Normal file
330
user/amd/src/participantsfilter.js
Normal file
@ -0,0 +1,330 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Participants filter managemnet.
|
||||
*
|
||||
* @module core_user/participants_filter
|
||||
* @package core_user
|
||||
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import CourseFilter from './local/participantsfilter/filtertypes/courseid';
|
||||
import * as DynamicTable from 'core_table/dynamic';
|
||||
import GenericFilter from './local/participantsfilter/filter';
|
||||
import Notification from 'core/notification';
|
||||
import Selectors from './local/participantsfilter/selectors';
|
||||
import Templates from 'core/templates';
|
||||
|
||||
/**
|
||||
* Initialise the participants filter on the element with the given id.
|
||||
*
|
||||
* @param {String} participantsRegionId
|
||||
*/
|
||||
export const init = participantsRegionId => {
|
||||
// Keep a reference to the filterset.
|
||||
const filterSet = document.querySelector(`#${participantsRegionId}`);
|
||||
|
||||
// Keep a reference to all of the active filters.
|
||||
const activeFilters = {
|
||||
courseid: new CourseFilter('courseid', filterSet),
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the filter list region.
|
||||
*
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
const getFilterRegion = () => filterSet.querySelector(Selectors.filterset.regions.filterlist);
|
||||
|
||||
/**
|
||||
* Add an unselected filter row.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
const addFilterRow = () => {
|
||||
return Templates.renderForPromise('core_user/local/participantsfilter/filterrow', {})
|
||||
.then(({html, js}) => {
|
||||
const newContentNodes = Templates.appendNodeContents(getFilterRegion(), html, js);
|
||||
|
||||
return newContentNodes;
|
||||
})
|
||||
.then(filterRow => {
|
||||
// Note: This is a nasty hack.
|
||||
// We should try to find a better way of doing this.
|
||||
// We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy
|
||||
// it in place.
|
||||
const typeList = filterSet.querySelector(Selectors.data.typeList);
|
||||
|
||||
filterRow.forEach(contentNode => {
|
||||
const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);
|
||||
|
||||
if (contentTypeList) {
|
||||
contentTypeList.innerHTML = typeList.innerHTML;
|
||||
}
|
||||
});
|
||||
|
||||
return filterRow;
|
||||
})
|
||||
.then(filterRow => {
|
||||
updateFiltersOptions();
|
||||
|
||||
return filterRow;
|
||||
})
|
||||
.catch(Notification.exception);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the filter data source node fro the specified filter type.
|
||||
*
|
||||
* @param {String} filterType
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
const getFilterDataSource = filterType => {
|
||||
const filterDataNode = filterSet.querySelector(Selectors.filterset.regions.datasource);
|
||||
|
||||
return filterDataNode.querySelector(Selectors.data.fields.byName(filterType));
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a filter to the list of active filters, performing any necessary setup.
|
||||
*
|
||||
* @param {HTMLElement} filterRow
|
||||
* @param {String} filterType
|
||||
*/
|
||||
const addFilter = async(filterRow, filterType) => {
|
||||
// Name the filter on the filter row.
|
||||
filterRow.dataset.filterType = filterType;
|
||||
|
||||
const filterDataNode = getFilterDataSource(filterType);
|
||||
|
||||
// Instantiate the Filter class.
|
||||
let Filter = GenericFilter;
|
||||
if (filterDataNode.dataset.filterTypeClass) {
|
||||
Filter = await import(filterDataNode.dataset.filterTypeClass);
|
||||
}
|
||||
activeFilters[filterType] = new Filter(filterType, filterSet);
|
||||
|
||||
// Disable the select.
|
||||
const typeField = filterRow.querySelector(Selectors.filter.fields.type);
|
||||
typeField.disabled = 'disabled';
|
||||
|
||||
// Update the list of available filter types.
|
||||
updateFiltersOptions();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the registered filter class for the named filter.
|
||||
*
|
||||
* @param {String} name
|
||||
* @return {Object} See the Filter class.
|
||||
*/
|
||||
const getFilterObject = name => {
|
||||
return activeFilters[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove or replace the specified filter row and associated class, ensuring that if there is only one filter row,
|
||||
* that it is replaced instead of being removed.
|
||||
*
|
||||
* @param {HTMLElement} filterRow
|
||||
*/
|
||||
const removeOrReplaceFilterRow = filterRow => {
|
||||
const filterCount = getFilterRegion().querySelectorAll(Selectors.filter.region).length;
|
||||
|
||||
if (filterCount === 1) {
|
||||
replaceFilterRow(filterRow);
|
||||
} else {
|
||||
removeFilterRow(filterRow);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the specified filter row and associated class.
|
||||
*
|
||||
* @param {HTMLElement} filterRow
|
||||
*/
|
||||
const removeFilterRow = filterRow => {
|
||||
// Remove the filter object.
|
||||
removeFilterObject(filterRow.dataset.filterType);
|
||||
|
||||
// Remove the actual filter HTML.
|
||||
filterRow.remove();
|
||||
|
||||
// Refresh the table.
|
||||
updateTableFromFilter();
|
||||
|
||||
// Update the list of available filter types.
|
||||
updateFiltersOptions();
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace the specified filter row with a new one.
|
||||
*
|
||||
* @param {HTMLElement} filterRow
|
||||
* @return {Promise}
|
||||
*/
|
||||
const replaceFilterRow = filterRow => {
|
||||
// Remove the filter object.
|
||||
removeFilterObject(filterRow.dataset.filterType);
|
||||
|
||||
return Templates.renderForPromise('core_user/local/participantsfilter/filterrow', {})
|
||||
.then(({html, js}) => {
|
||||
const newContentNodes = Templates.replaceNode(filterRow, html, js);
|
||||
|
||||
return newContentNodes;
|
||||
})
|
||||
.then(filterRow => {
|
||||
// Note: This is a nasty hack.
|
||||
// We should try to find a better way of doing this.
|
||||
// We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy
|
||||
// it in place.
|
||||
const typeList = filterSet.querySelector(Selectors.data.typeList);
|
||||
|
||||
filterRow.forEach(contentNode => {
|
||||
const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);
|
||||
|
||||
if (contentTypeList) {
|
||||
contentTypeList.innerHTML = typeList.innerHTML;
|
||||
}
|
||||
});
|
||||
|
||||
return filterRow;
|
||||
})
|
||||
.then(filterRow => {
|
||||
updateFiltersOptions();
|
||||
|
||||
return filterRow;
|
||||
})
|
||||
.then(filterRow => {
|
||||
// Refresh the table.
|
||||
updateTableFromFilter();
|
||||
|
||||
return filterRow;
|
||||
})
|
||||
.catch(Notification.exception);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the Filter Object from the register.
|
||||
*
|
||||
* @param {string} filterName The name of the filter to be removed
|
||||
*/
|
||||
const removeFilterObject = filterName => {
|
||||
if (filterName) {
|
||||
const filter = getFilterObject(filterName);
|
||||
if (filter) {
|
||||
filter.tearDown();
|
||||
|
||||
// Remove from the list of active filters.
|
||||
delete activeFilters[filterName];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all filters.
|
||||
*/
|
||||
const removeAllFilters = async() => {
|
||||
const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);
|
||||
filters.forEach((filterRow) => {
|
||||
removeOrReplaceFilterRow(filterRow);
|
||||
});
|
||||
|
||||
// Refresh the table.
|
||||
updateTableFromFilter();
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the list of filter types to filter out those already selected.
|
||||
*/
|
||||
const updateFiltersOptions = () => {
|
||||
const filters = getFilterRegion().querySelectorAll(Selectors.filter.region);
|
||||
filters.forEach(filterRow => {
|
||||
const options = filterRow.querySelectorAll(Selectors.filter.fields.type + ' option');
|
||||
options.forEach(option => {
|
||||
if (option.value === filterRow.dataset.filterType) {
|
||||
option.classList.remove('hidden');
|
||||
option.disabled = false;
|
||||
} else if (activeFilters[option.value]) {
|
||||
option.classList.add('hidden');
|
||||
option.disabled = true;
|
||||
} else {
|
||||
option.classList.remove('hidden');
|
||||
option.disabled = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the Dynamic table based upon the current filter.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
const updateTableFromFilter = () => {
|
||||
// TODO The main join type does not exist yet.
|
||||
const joinType = 1;
|
||||
|
||||
return DynamicTable.setFilters(
|
||||
DynamicTable.getTableFromId(filterSet.dataset.tableRegion),
|
||||
{
|
||||
filters: Object.values(activeFilters).map(filter => filter.filterValue),
|
||||
jointype: joinType,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Add listeners for the main actions.
|
||||
filterSet.querySelector(Selectors.filterset.region).addEventListener('click', e => {
|
||||
if (e.target.closest(Selectors.filterset.actions.addRow)) {
|
||||
e.preventDefault();
|
||||
|
||||
addFilterRow();
|
||||
}
|
||||
|
||||
if (e.target.closest(Selectors.filterset.actions.applyFilters)) {
|
||||
e.preventDefault();
|
||||
|
||||
updateTableFromFilter();
|
||||
}
|
||||
|
||||
if (e.target.closest(Selectors.filterset.actions.resetFilters)) {
|
||||
e.preventDefault();
|
||||
|
||||
removeAllFilters();
|
||||
}
|
||||
});
|
||||
|
||||
// Add the listener to remove a single filter.
|
||||
filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('click', e => {
|
||||
if (e.target.closest(Selectors.filter.actions.remove)) {
|
||||
e.preventDefault();
|
||||
|
||||
removeOrReplaceFilterRow(e.target.closest(Selectors.filter.region));
|
||||
}
|
||||
});
|
||||
|
||||
// Add listeners for the filter type selection.
|
||||
filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('change', e => {
|
||||
const typeField = e.target.closest(Selectors.filter.fields.type);
|
||||
if (typeField && typeField.value) {
|
||||
const filter = e.target.closest(Selectors.filter.region);
|
||||
|
||||
addFilter(filter, typeField.value);
|
||||
}
|
||||
});
|
||||
};
|
150
user/classes/output/participants_filter.php
Normal file
150
user/classes/output/participants_filter.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Class for rendering user filters on the course participants page.
|
||||
*
|
||||
* @package core_user
|
||||
* @copyright 2020 Michael Hawkins <michaelh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_user\output;
|
||||
|
||||
use context_course;
|
||||
use renderable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use templatable;
|
||||
|
||||
/**
|
||||
* Class for rendering user filters on the course participants page.
|
||||
*
|
||||
* @copyright 2020 Michael Hawkins <michaelh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class participants_filter implements renderable, templatable {
|
||||
|
||||
/** @var context_course $context The context where the filters are being rendered. */
|
||||
protected $context;
|
||||
|
||||
/** @var string $tableregionid The table to be updated by this filter */
|
||||
protected $tableregionid;
|
||||
|
||||
/**
|
||||
* Participants filter constructor.
|
||||
*
|
||||
* @param context_course $context The context where the filters are being rendered.
|
||||
* @param string $tableregionid The table to be updated by this filter
|
||||
*/
|
||||
public function __construct(context_course $context, string $tableregionid) {
|
||||
$this->context = $context;
|
||||
$this->tableregionid = $tableregionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data for all filter types.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_filtertypes(): array {
|
||||
$filtertypes = [];
|
||||
|
||||
if ($filtertype = $this->get_enrolmentstatus_filter()) {
|
||||
$filtertypes[] = $filtertype;
|
||||
}
|
||||
|
||||
return $filtertypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data for the enrolment status filter.
|
||||
*
|
||||
* @return stdClass|null
|
||||
*/
|
||||
protected function get_enrolmentstatus_filter(): ?stdClass {
|
||||
if (!has_capability('moodle/course:enrolreview', $this->context)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->get_filter_object(
|
||||
'status',
|
||||
get_string('participationstatus', 'core_enrol'),
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
[
|
||||
(object) [
|
||||
'value' => ENROL_USER_ACTIVE,
|
||||
'title' => get_string('active'),
|
||||
],
|
||||
(object) [
|
||||
'value' => ENROL_USER_SUSPENDED,
|
||||
'title' => get_string('inactive'),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the renderer data in a mustache template friendly format.
|
||||
*
|
||||
* @param renderer_base $output Unused.
|
||||
* @return stdClass Data in a format compatible with a mustache template.
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
return (object) [
|
||||
'tableregionid' => $this->tableregionid,
|
||||
'courseid' => $this->context->instanceid,
|
||||
'filtertypes' => $this->get_filtertypes(),
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a standardised filter object.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param bool $custom
|
||||
* @param bool $multiple
|
||||
* @param string|null $filterclass
|
||||
* @param array $values
|
||||
* @return stdClass|null
|
||||
*/
|
||||
protected function get_filter_object(
|
||||
string $name,
|
||||
string $title,
|
||||
bool $custom,
|
||||
bool $multiple,
|
||||
?string $filterclass,
|
||||
array $values
|
||||
): ?stdClass {
|
||||
if (empty($values)) {
|
||||
// Do not show empty filters.
|
||||
return null;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'name' => $name,
|
||||
'title' => $title,
|
||||
'allowcustom' => $custom,
|
||||
'allowmultiple' => $multiple,
|
||||
'filtertypeclass' => $filterclass,
|
||||
'values' => $values,
|
||||
];
|
||||
}
|
||||
}
|
@ -143,6 +143,8 @@ $lastaccess = 0;
|
||||
$searchkeywords = [];
|
||||
$enrolid = 0;
|
||||
|
||||
$participanttable = new \core_user\table\participants("user-index-participants-{$course->id}");
|
||||
|
||||
$filterset = new \core_user\table\participants_filterset();
|
||||
$filterset->add_filter(new integer_filter('courseid', filter::JOINTYPE_DEFAULT, [(int)$course->id]));
|
||||
$enrolfilter = new integer_filter('enrolments');
|
||||
@ -249,6 +251,10 @@ echo html_writer::div($enrolbuttonsout, 'float-right', [
|
||||
$renderer = $PAGE->get_renderer('core_user');
|
||||
echo $renderer->unified_filter($course, $context, $filtersapplied, $baseurl);
|
||||
|
||||
// Render the user filters.
|
||||
$userrenderer = $PAGE->get_renderer('core_user');
|
||||
echo $userrenderer->participants_filter($context, $participanttable->uniqueid);
|
||||
|
||||
echo '<div class="userlist">';
|
||||
|
||||
// Add filters to the baseurl after creating unified_filter to avoid losing them.
|
||||
|
@ -259,6 +259,20 @@ class core_user_renderer extends plugin_renderer_base {
|
||||
return $this->output->render_from_template('core_user/unified_filter', $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the data required for the participants filter on the course participants page.
|
||||
*
|
||||
* @param context $context The context of the course being displayed
|
||||
* @param string $tableregionid The table to be updated by this filter
|
||||
* @return string
|
||||
*/
|
||||
public function participants_filter(context $context, string $tableregionid): string {
|
||||
$renderable = new \core_user\output\participants_filter($context, $tableregionid);
|
||||
$templatecontext = $renderable->export_for_template($this->output);
|
||||
|
||||
return $this->output->render_from_template('core_user/participantsfilter', $templatecontext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted filter option.
|
||||
*
|
||||
|
56
user/templates/local/participantsfilter/filterrow.mustache
Normal file
56
user/templates/local/participantsfilter/filterrow.mustache
Normal file
@ -0,0 +1,56 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_user/local/participantsfilter/filterrow
|
||||
|
||||
Template for use by each filter condition.
|
||||
|
||||
Context variables required for this template:
|
||||
* filtertypes - Array of filter types available.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"filtertypes": [
|
||||
{
|
||||
"name": "status",
|
||||
"title": "Status"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div data-filterregion="filter" class="rounded mb-3 p-2 bg-white border border-secondary d-flex align-items-center">
|
||||
<label for="core_user-local-participantsfilter-filterrow-jointype-{{uniqid}}" class="pt-2">{{#str}}match, core_user{{/str}}</label>
|
||||
<select class="custom-select" data-filterfield="join" id="core_user-local-participantsfilter-filterrow-jointype-{{uniqid}}">
|
||||
<option value="0">{{#str}}none{{/str}}</option>
|
||||
<option selected=selected value="1">{{#str}}any{{/str}}</option>
|
||||
<option value="2">{{#str}}all{{/str}}</option>
|
||||
</select>
|
||||
|
||||
<label class="sr-only pt-2" for="core_user-local-participantsfilter-filterrow-filtertype-{{uniqid}}">filtertype</label>
|
||||
<select class="custom-select" data-filterfield="type" id="core_user-local-participantsfilter-filterrow-filtertype-{{uniqid}}">
|
||||
<option value="">{{#str}}selectfiltertype, core_user{{/str}}</option>
|
||||
{{#filtertypes}}
|
||||
<option value="{{name}}">{{title}}</option>
|
||||
{{/filtertypes}}
|
||||
</select>
|
||||
|
||||
<div data-filterregion="value"></div>
|
||||
|
||||
<button data-filteraction="remove" class="ml-auto btn btn-link text-reset" aria-label="{{#str}}clearfilterrow, core_user{{/str}}">
|
||||
<i class="icon fa fa-times-circle pt-2"></i>
|
||||
</button>
|
||||
</div>
|
61
user/templates/local/participantsfilter/filtertype.mustache
Normal file
61
user/templates/local/participantsfilter/filtertype.mustache
Normal file
@ -0,0 +1,61 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_user/local/participantsfilter/filtertype
|
||||
|
||||
Filter type data, not shown to users but used as a source of data for form autocompletion.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* filtertypes
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"name": "status",
|
||||
"title": "Enrolment Status",
|
||||
"allowcustom": "0",
|
||||
"allowmultiple" false,
|
||||
"filtertypeclass": "core_user/local/participantsfilter/filtertypes/courseid",
|
||||
"values": [
|
||||
{
|
||||
"value": "0",
|
||||
"title": "Inactive"
|
||||
},
|
||||
{
|
||||
"value": "1",
|
||||
"title": "Active"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<select {{!
|
||||
}}{{#allowmultiple}}multiple="multiple"{{/allowmultiple}} {{!
|
||||
}}data-field-name="{{name}}" {{!
|
||||
}}data-field-title="{{title}}" {{!
|
||||
}}data-allow-custom="{{allowcustom}}" {{!
|
||||
}}class="hidden" {{!
|
||||
}}{{#filtertypeclass}}data-filter-type-class="{{filtertypeclass}}" {{/filtertypeclass}}{{!
|
||||
}}>
|
||||
{{#values}}
|
||||
<option value="{{value}}">{{title}}</option>
|
||||
{{/values}}
|
||||
</select>
|
64
user/templates/local/participantsfilter/filtertypes.mustache
Normal file
64
user/templates/local/participantsfilter/filtertypes.mustache
Normal file
@ -0,0 +1,64 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_user/local/participantsfilter/filtertypes
|
||||
|
||||
Placeholder to fetch all filter types.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* data-filterregion="filtertypedata"
|
||||
|
||||
Context variables required for this template:
|
||||
* filtertypes
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"filtertypes": [
|
||||
{
|
||||
"name": "status",
|
||||
"title": "Enrolment Status",
|
||||
"allowcustom": "0",
|
||||
"values": [
|
||||
{
|
||||
"value": "0",
|
||||
"title": "Inactive"
|
||||
},
|
||||
{
|
||||
"value": "1",
|
||||
"title": "Active"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="hidden" data-filterregion="filtertypedata">
|
||||
{{#filtertypes}}
|
||||
{{> core_user/local/participantsfilter/filtertype}}
|
||||
{{/filtertypes}}
|
||||
</div>
|
||||
<div class="hidden">
|
||||
<select disabled="disabled" data-filterfield="type" data-filterregion="filtertypelist">
|
||||
<option value="">{{#str}}selectfiltertype, core_user{{/str}}</option>
|
||||
{{#filtertypes}}
|
||||
<option value="{{name}}">{{title}}</option>
|
||||
{{/filtertypes}}
|
||||
</select>
|
||||
</div>
|
67
user/templates/participantsfilter.mustache
Normal file
67
user/templates/participantsfilter.mustache
Normal file
@ -0,0 +1,67 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_user/participantsfilter
|
||||
|
||||
Template for the form containing one or more filter rows.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"filtertypes": [
|
||||
{
|
||||
"name": "status",
|
||||
"title": "Status",
|
||||
"values": [
|
||||
{
|
||||
"value": 1,
|
||||
"title": "Active"
|
||||
},
|
||||
{
|
||||
"value": 0,
|
||||
"title": "Suspended"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
|
||||
<div id="core_user-participantsfilter-{{uniqid}}" class="filter-group mt-5 p-3 rounded border border-secondary" data-table-region="{{tableregionid}}" data-table-course-id="{{courseid}}">
|
||||
<div data-filterregion="filters">
|
||||
{{> core_user/local/participantsfilter/filterrow }}
|
||||
</div>
|
||||
|
||||
<div class="display-block" data-filterregion="actions">
|
||||
|
||||
<button type="button" class="btn btn-link d-inline-block float-left" data-filteraction="add">
|
||||
<i class="fa fa-plus"></i><span class="pl-3">{{#str}}addcondition, core_user{{/str}}</span>
|
||||
</button>
|
||||
|
||||
<div class="float-right">
|
||||
<button data-filteraction="reset" type="button" class="btn btn-light d-inline-block">{{#str}}clearfilters, core_user{{/str}}</button>
|
||||
<button data-filteraction="apply" type="button" class="btn btn-primary d-inline-block">{{#str}}applyfilters, core_user{{/str}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{> core_user/local/participantsfilter/filtertypes}}
|
||||
</div>
|
||||
|
||||
{{#js}}
|
||||
require(['core_user/participantsfilter'], function(ParticipantsFilter) {
|
||||
ParticipantsFilter.init('core_user-participantsfilter-{{uniqid}}');
|
||||
});
|
||||
{{/js}}
|
Loading…
x
Reference in New Issue
Block a user