MDL-67786 core_contentbank: Unit and behat tests
[moodle.git] / lib / table / amd / src / dynamic.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  * Module to handle dynamic table features.
18  *
19  * @module     core_table/dynamic
20  * @package    core_table
21  * @copyright  2020 Simey Lameze <simey@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
24 import {fetch as fetchTableData} from 'core_table/local/dynamic/repository';
25 import * as Selectors from 'core_table/local/dynamic/selectors';
27 let watching = false;
29 /**
30  * Ensure that a table is a dynamic table.
31  *
32  * @param {HTMLElement} tableRoot
33  * @returns {Bool}
34  */
35 const checkTableIsDynamic = tableRoot => {
36     if (!tableRoot) {
37         // The table is not a dynamic table.
38         throw new Error("The table specified is not a dynamic table and cannot be updated");
39     }
41     if (!tableRoot.matches(Selectors.main.region)) {
42         // The table is not a dynamic table.
43         throw new Error("The table specified is not a dynamic table and cannot be updated");
44     }
46     return true;
47 };
49 /**
50  * Get the filterset data from a known dynamic table.
51  *
52  * @param {HTMLElement} tableRoot
53  * @returns {Object}
54  */
55 const getFiltersetFromTable = tableRoot => {
56     return JSON.parse(tableRoot.dataset.tableFilters);
57 };
59 /**
60  * Update the specified table based on its current values.
61  *
62  * @param {HTMLElement} tableRoot
63  * @returns {Promise}
64  */
65 export const refreshTableContent = tableRoot => {
66     const filterset = getFiltersetFromTable(tableRoot);
68     return fetchTableData(
69         tableRoot.dataset.tableHandler,
70         tableRoot.dataset.tableUniqueid,
71         {
72             sortBy: tableRoot.dataset.tableSortBy,
73             sortOrder: tableRoot.dataset.tableSortOrder,
74             joinType: filterset.jointype,
75             filters: filterset.filters,
76             firstinitial: tableRoot.dataset.tableFirstInitial,
77             lastinitial: tableRoot.dataset.tableLastInitial,
78         }
79     )
80     .then(data => {
81         const placeholder = document.createElement('div');
82         placeholder.innerHTML = data.html;
83         tableRoot.replaceWith(...placeholder.childNodes);
85         return data;
86     });
87 };
89 export const updateTable = (tableRoot, {
90     sortBy = null,
91     sortOrder = null,
92     filters = null,
93     firstInitial = null,
94     lastInitial = null,
95 } = {}, refreshContent = true) => {
96     checkTableIsDynamic(tableRoot);
98     // Update sort fields.
99     if (sortBy && sortOrder) {
100         tableRoot.dataset.tableSortBy = sortBy;
101         tableRoot.dataset.tableSortOrder = sortOrder;
102     }
104     // Update initials.
105     if (firstInitial !== null) {
106         tableRoot.dataset.tableFirstInitial = firstInitial;
107     }
109     if (lastInitial !== null) {
110         tableRoot.dataset.tableLastInitial = lastInitial;
111     }
113     // Update filters.
114     if (filters) {
115         tableRoot.dataset.tableFilters = JSON.stringify(filters);
116     }
118     // Refresh.
119     if (refreshContent) {
120         return refreshTableContent(tableRoot);
121     } else {
122         return Promise.resolve();
123     }
124 };
126 /**
127  * Update the specified table using the new filters.
128  *
129  * @param {HTMLElement} tableRoot
130  * @param {Object} filters
131  * @param {Bool} refreshContent
132  * @returns {Promise}
133  */
134 export const setFilters = (tableRoot, filters, refreshContent = true) =>
135     updateTable(tableRoot, {filters}, refreshContent);
137 /**
138  * Update the sort order.
139  *
140  * @param {HTMLElement} tableRoot
141  * @param {String} sortBy
142  * @param {Number} sortOrder
143  * @param {Bool} refreshContent
144  * @returns {Promise}
145  */
146 export const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>
147     updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);
149 /**
150  * Update the first initial to show.
151  *
152  * @param {HTMLElement} tableRoot
153  * @param {String} firstInitial
154  * @param {Bool} refreshContent
155  * @returns {Promise}
156  */
157 export const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>
158     updateTable(tableRoot, {firstInitial}, refreshContent);
160 /**
161  * Update the last initial to show.
162  *
163  * @param {HTMLElement} tableRoot
164  * @param {String} lastInitial
165  * @param {Bool} refreshContent
166  * @returns {Promise}
167  */
168 export const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>
169     updateTable(tableRoot, {lastInitial}, refreshContent);
171 /**
172  * Set up listeners to handle table updates.
173  */
174 export const init = () => {
175     if (watching) {
176         // Already watching.
177         return;
178     }
179     watching = true;
181     document.addEventListener('click', e => {
182         const tableRoot = e.target.closest(Selectors.main.region);
184         if (!tableRoot) {
185             return;
186         }
188         const sortableLink = e.target.closest(Selectors.table.links.sortableColumn);
189         if (sortableLink) {
190             e.preventDefault();
192             setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);
193         }
195         const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);
196         if (firstInitialLink !== null) {
197             e.preventDefault();
199             setFirstInitial(tableRoot, firstInitialLink.dataset.initial);
200         }
202         const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);
203         if (lastInitialLink !== null) {
204             e.preventDefault();
206             setLastInitial(tableRoot, lastInitialLink.dataset.initial);
207         }
208     });
209 };