MDL-67917 user: Add skeleton for new participants filter
[moodle.git] / user / amd / src / local / participantsfilter / filter.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * Base Filter class for a filter type in the participants filter UI.
18  *
19  * @module     core_user/local/participantsfilter/filter
20  * @package    core_user
21  * @copyright  2020 Andrew Nicols <andrew@nicols.co.uk>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
24 import Autocomplete from 'core/form-autocomplete';
25 import Selectors from './selectors';
26 import {get_string as getString} from 'core/str';
28 /**
29  * Fetch all checked options in the select.
30  *
31  * This is a poor-man's polyfill for select.selectedOptions, which is not available in IE11.
32  *
33  * @param {HTMLSelectElement} select
34  * @returns {HTMLOptionElement[]} All selected options
35  */
36 const getOptionsForSelect = select => {
37     return select.querySelectorAll(':checked');
38 };
40 export default class {
42     /**
43      * Constructor for a new filter.
44      *
45      * @param {String} filterType The type of filter that this relates to
46      * @param {HTMLElement} rootNode The root node for the participants filterset
47      */
48     constructor(filterType, rootNode) {
49         this.filterType = filterType;
50         this.rootNode = rootNode;
52         this.addValueSelector();
53     }
55     /**
56      * Perform any tear-down for this filter type.
57      */
58     tearDown() {
59         // eslint-disable-line no-empty-function
60     }
62     /**
63      * Add the value selector to the filter row.
64      */
65     async addValueSelector() {
66         const filterValueNode = this.getFilterValueNode();
68         // Copy the data in place.
69         filterValueNode.innerHTML = this.getSourceDataForFilter().outerHTML;
71         const dataSource = filterValueNode.querySelector('select');
73         Autocomplete.enhance(
74             // The source select element.
75             dataSource,
77             // Whether to allow 'tags' (custom entries).
78             dataSource.dataset.allowCustom == "1",
80             // We do not require AJAX at all as standard.
81             null,
83             // The string to use as a placeholder.
84             await getString('typeorselect', 'core_user'),
86             // Disable case sensitivity on searches.
87             false,
89             // Show suggestions.
90             true,
92             // Do not override the 'no suggestions' string.
93             null,
95             // Close the suggestions if this is not a multi-select.
96             !dataSource.multiple
97         );
98     }
100     /**
101      * Get the root node for this filter.
102      *
103      * @returns {HTMLElement}
104      */
105     get filterRoot() {
106         return this.rootNode.querySelector(Selectors.filter.byName(this.filterType));
107     }
109     /**
110      * Get the possible data for this filter type.
111      *
112      * @returns {Array}
113      */
114     getSourceDataForFilter() {
115         const filterDataNode = this.rootNode.querySelector(Selectors.filterset.regions.datasource);
117         return filterDataNode.querySelector(Selectors.data.fields.byName(this.filterType));
118     }
120     /**
121      * Get the HTMLElement which contains the value selector.
122      *
123      * @returns {HTMLElement}
124      */
125     getFilterValueNode() {
126         return this.filterRoot.querySelector(Selectors.filter.regions.values);
127     }
129     /**
130      * Get the name of this filter.
131      *
132      * @returns {String}
133      */
134     get name() {
135         return this.filterType;
136     }
138     /**
139      * Get the type of join specified.
140      *
141      * @returns {Number}
142      */
143     get jointype() {
144         return this.filterRoot.querySelector(Selectors.filter.fields.join).value;
145     }
147     /**
148      * Get the list of raw values for this filter type.
149      *
150      * @returns {Array}
151      */
152     get rawValues() {
153         const filterValueNode = this.getFilterValueNode();
154         const filterValueSelect = filterValueNode.querySelector('select');
156         return Object.values(getOptionsForSelect(filterValueSelect)).map(option => option.value);
157     }
159     /**
160      * Get the list of values for this filter type.
161      *
162      * @returns {Array}
163      */
164     get values() {
165         return this.rawValues.map(option => parseInt(option, 10));
166     }
168     /**
169      * Get the composed value for this filter.
170      *
171      * @returns {Object}
172      */
173     get filterValue() {
174         return {
175             name: this.name,
176             jointype: this.jointype,
177             values: this.values,
178         };
179     }