9a959502d68f26c1cb4dbec3ea40963a8e50a31d
[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';
26 import Events from './local/dynamic/events';
28 let watching = false;
30 /**
31  * Ensure that a table is a dynamic table.
32  *
33  * @param {HTMLElement} tableRoot
34  * @returns {Bool}
35  */
36 const checkTableIsDynamic = tableRoot => {
37     if (!tableRoot) {
38         // The table is not a dynamic table.
39         throw new Error("The table specified is not a dynamic table and cannot be updated");
40     }
42     if (!tableRoot.matches(Selectors.main.region)) {
43         // The table is not a dynamic table.
44         throw new Error("The table specified is not a dynamic table and cannot be updated");
45     }
47     return true;
48 };
50 /**
51  * Get the filterset data from a known dynamic table.
52  *
53  * @param {HTMLElement} tableRoot
54  * @returns {Object}
55  */
56 const getFiltersetFromTable = tableRoot => {
57     return JSON.parse(tableRoot.dataset.tableFilters);
58 };
60 /**
61  * Update the specified table based on its current values.
62  *
63  * @param {HTMLElement} tableRoot
64  * @returns {Promise}
65  */
66 export const refreshTableContent = tableRoot => {
67     const filterset = getFiltersetFromTable(tableRoot);
69     return fetchTableData(
70         tableRoot.dataset.tableComponent,
71         tableRoot.dataset.tableHandler,
72         tableRoot.dataset.tableUniqueid,
73         {
74             sortBy: tableRoot.dataset.tableSortBy,
75             sortOrder: tableRoot.dataset.tableSortOrder,
76             joinType: filterset.jointype,
77             filters: filterset.filters,
78             firstinitial: tableRoot.dataset.tableFirstInitial,
79             lastinitial: tableRoot.dataset.tableLastInitial,
80             pageNumber: tableRoot.dataset.tablePageNumber,
81             pageSize: tableRoot.dataset.tablePageSize,
82         }
83     )
84     .then(data => {
85         const placeholder = document.createElement('div');
86         placeholder.innerHTML = data.html;
87         tableRoot.replaceWith(...placeholder.childNodes);
89         // Update the tableRoot.
90         return getTableFromId(tableRoot.dataset.tableUniqueid);
91     }).then(tableRoot => {
92         tableRoot.dispatchEvent(new CustomEvent(Events.tableContentRefreshed, {
93             bubbles: true,
94         }));
96         return tableRoot;
97     });
98 };
100 export const updateTable = (tableRoot, {
101     sortBy = null,
102     sortOrder = null,
103     filters = null,
104     firstInitial = null,
105     lastInitial = null,
106     pageNumber = null,
107     pageSize = null,
108 } = {}, refreshContent = true) => {
109     checkTableIsDynamic(tableRoot);
111     // Update sort fields.
112     if (sortBy && sortOrder) {
113         tableRoot.dataset.tableSortBy = sortBy;
114         tableRoot.dataset.tableSortOrder = sortOrder;
115     }
117     // Update initials.
118     if (firstInitial !== null) {
119         tableRoot.dataset.tableFirstInitial = firstInitial;
120     }
122     if (lastInitial !== null) {
123         tableRoot.dataset.tableLastInitial = lastInitial;
124     }
126     if (pageNumber !== null) {
127         tableRoot.dataset.tablePageNumber = pageNumber;
128     }
130     if (pageSize !== null) {
131         tableRoot.dataset.tablePageSize = pageSize;
132     }
134     // Update filters.
135     if (filters) {
136         tableRoot.dataset.tableFilters = JSON.stringify(filters);
137     }
139     // Refresh.
140     if (refreshContent) {
141         return refreshTableContent(tableRoot);
142     } else {
143         return Promise.resolve(tableRoot);
144     }
145 };
147 /**
148  * Update the specified table using the new filters.
149  *
150  * @param {HTMLElement} tableRoot
151  * @param {Object} filters
152  * @param {Bool} refreshContent
153  * @returns {Promise}
154  */
155 export const setFilters = (tableRoot, filters, refreshContent = true) =>
156     updateTable(tableRoot, {filters}, refreshContent);
158 /**
159  * Update the sort order.
160  *
161  * @param {HTMLElement} tableRoot
162  * @param {String} sortBy
163  * @param {Number} sortOrder
164  * @param {Bool} refreshContent
165  * @returns {Promise}
166  */
167 export const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>
168     updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);
170 /**
171  * Set the page number.
172  *
173  * @param {HTMLElement} tableRoot
174  * @param {String} pageNumber
175  * @param {Bool} refreshContent
176  * @returns {Promise}
177  */
178 export const setPageNumber = (tableRoot, pageNumber, refreshContent = true) =>
179     updateTable(tableRoot, {pageNumber}, refreshContent);
181 /**
182  * Set the page size.
183  *
184  * @param {HTMLElement} tableRoot
185  * @param {Number} pageSize
186  * @param {Bool} refreshContent
187  * @returns {Promise}
188  */
189 export const setPageSize = (tableRoot, pageSize, refreshContent = true) =>
190     updateTable(tableRoot, {pageSize, pageNumber: 0}, refreshContent);
192 /**
193  * Update the first initial to show.
194  *
195  * @param {HTMLElement} tableRoot
196  * @param {String} firstInitial
197  * @param {Bool} refreshContent
198  * @returns {Promise}
199  */
200 export const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>
201     updateTable(tableRoot, {firstInitial}, refreshContent);
203 /**
204  * Update the last initial to show.
205  *
206  * @param {HTMLElement} tableRoot
207  * @param {String} lastInitial
208  * @param {Bool} refreshContent
209  * @returns {Promise}
210  */
211 export const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>
212     updateTable(tableRoot, {lastInitial}, refreshContent);
214 /**
215  * Set up listeners to handle table updates.
216  */
217 export const init = () => {
218     if (watching) {
219         // Already watching.
220         return;
221     }
222     watching = true;
224     document.addEventListener('click', e => {
225         const tableRoot = e.target.closest(Selectors.main.region);
227         if (!tableRoot) {
228             return;
229         }
231         const sortableLink = e.target.closest(Selectors.table.links.sortableColumn);
232         if (sortableLink) {
233             e.preventDefault();
235             setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);
236         }
238         const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);
239         if (firstInitialLink !== null) {
240             e.preventDefault();
242             setFirstInitial(tableRoot, firstInitialLink.dataset.initial);
243         }
245         const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);
246         if (lastInitialLink !== null) {
247             e.preventDefault();
249             setLastInitial(tableRoot, lastInitialLink.dataset.initial);
250         }
252         const pageItem = e.target.closest(Selectors.paginationBar.links.pageItem);
253         if (pageItem) {
254             e.preventDefault();
256             setPageNumber(tableRoot, pageItem.dataset.pageNumber);
257         }
258     });
259 };
261 /**
262  * Fetch the table via its table region id.
263  *
264  * @param {String} tableRegionId
265  * @returns {HTMLElement}
266  */
267 export const getTableFromId = tableRegionId => {
268     const tableRoot = document.querySelector(Selectors.main.fromRegionId(tableRegionId));
271     if (!tableRoot) {
272         // The table is not a dynamic table.
273         throw new Error("The table specified is not a dynamic table and cannot be updated");
274     }
276     return tableRoot;
277 };
279 export {
280     Events
281 };