Merge branch 'MDL-67786-master' of git://github.com/aanabit/moodle
[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             pageNumber: tableRoot.dataset.tablePageNumber,
79             pageSize: tableRoot.dataset.tablePageSize,
80         }
81     )
82     .then(data => {
83         const placeholder = document.createElement('div');
84         placeholder.innerHTML = data.html;
85         tableRoot.replaceWith(...placeholder.childNodes);
87         return data;
88     });
89 };
91 export const updateTable = (tableRoot, {
92     sortBy = null,
93     sortOrder = null,
94     filters = null,
95     firstInitial = null,
96     lastInitial = null,
97     pageNumber = null,
98     pageSize = null,
99 } = {}, refreshContent = true) => {
100     checkTableIsDynamic(tableRoot);
102     // Update sort fields.
103     if (sortBy && sortOrder) {
104         tableRoot.dataset.tableSortBy = sortBy;
105         tableRoot.dataset.tableSortOrder = sortOrder;
106     }
108     // Update initials.
109     if (firstInitial !== null) {
110         tableRoot.dataset.tableFirstInitial = firstInitial;
111     }
113     if (lastInitial !== null) {
114         tableRoot.dataset.tableLastInitial = lastInitial;
115     }
117     if (pageNumber !== null) {
118         tableRoot.dataset.tablePageNumber = pageNumber;
119     }
121     if (pageSize !== null) {
122         tableRoot.dataset.tablePageSize = pageSize;
123     }
125     // Update filters.
126     if (filters) {
127         tableRoot.dataset.tableFilters = JSON.stringify(filters);
128     }
130     // Refresh.
131     if (refreshContent) {
132         return refreshTableContent(tableRoot);
133     } else {
134         return Promise.resolve();
135     }
136 };
138 /**
139  * Update the specified table using the new filters.
140  *
141  * @param {HTMLElement} tableRoot
142  * @param {Object} filters
143  * @param {Bool} refreshContent
144  * @returns {Promise}
145  */
146 export const setFilters = (tableRoot, filters, refreshContent = true) =>
147     updateTable(tableRoot, {filters}, refreshContent);
149 /**
150  * Update the sort order.
151  *
152  * @param {HTMLElement} tableRoot
153  * @param {String} sortBy
154  * @param {Number} sortOrder
155  * @param {Bool} refreshContent
156  * @returns {Promise}
157  */
158 export const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>
159     updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);
161 /**
162  * Set the page number.
163  *
164  * @param {HTMLElement} tableRoot
165  * @param {String} pageNumber
166  * @param {Bool} refreshContent
167  * @returns {Promise}
168  */
169 export const setPageNumber = (tableRoot, pageNumber, refreshContent = true) =>
170     updateTable(tableRoot, {pageNumber}, refreshContent);
172 /**
173  * Set the page size.
174  *
175  * @param {HTMLElement} tableRoot
176  * @param {Number} pageSize
177  * @param {Bool} refreshContent
178  * @returns {Promise}
179  */
180 export const setPageSize = (tableRoot, pageSize, refreshContent = true) =>
181     updateTable(tableRoot, {pageSize, pageNumber: 0}, refreshContent);
183 /**
184  * Update the first initial to show.
185  *
186  * @param {HTMLElement} tableRoot
187  * @param {String} firstInitial
188  * @param {Bool} refreshContent
189  * @returns {Promise}
190  */
191 export const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>
192     updateTable(tableRoot, {firstInitial}, refreshContent);
194 /**
195  * Update the last initial to show.
196  *
197  * @param {HTMLElement} tableRoot
198  * @param {String} lastInitial
199  * @param {Bool} refreshContent
200  * @returns {Promise}
201  */
202 export const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>
203     updateTable(tableRoot, {lastInitial}, refreshContent);
205 /**
206  * Set up listeners to handle table updates.
207  */
208 export const init = () => {
209     if (watching) {
210         // Already watching.
211         return;
212     }
213     watching = true;
215     document.addEventListener('click', e => {
216         const tableRoot = e.target.closest(Selectors.main.region);
218         if (!tableRoot) {
219             return;
220         }
222         const sortableLink = e.target.closest(Selectors.table.links.sortableColumn);
223         if (sortableLink) {
224             e.preventDefault();
226             setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);
227         }
229         const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);
230         if (firstInitialLink !== null) {
231             e.preventDefault();
233             setFirstInitial(tableRoot, firstInitialLink.dataset.initial);
234         }
236         const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);
237         if (lastInitialLink !== null) {
238             e.preventDefault();
240             setLastInitial(tableRoot, lastInitialLink.dataset.initial);
241         }
243         const pageItem = e.target.closest(Selectors.paginationBar.links.pageItem);
244         if (pageItem) {
245             e.preventDefault();
247             setPageNumber(tableRoot, pageItem.dataset.pageNumber);
248         }
249     });
250 };