MDL-68796 core_contentbank: Store view preferences
[moodle.git] / contentbank / amd / src / sort.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  * Content bank UI actions.
18  *
19  * @module     core_contentbank/sort
20  * @package    core_contentbank
21  * @copyright  2020 Bas Brands <bas@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 import selectors from './selectors';
26 import {get_string as getString} from 'core/str';
27 import Prefetch from 'core/prefetch';
28 import Ajax from 'core/ajax';
29 import Notification from 'core/notification';
31 /**
32  * Set up the contentbank views.
33  *
34  * @method init
35  */
36 export const init = () => {
37     const contentBank = document.querySelector(selectors.regions.contentbank);
38     Prefetch.prefetchStrings('contentbank', ['sortbyx', 'sortbyxreverse', 'contentname',
39         'lastmodified', 'size', 'type']);
40     registerListenerEvents(contentBank);
41 };
43 /**
44  * Register contentbank related event listeners.
45  *
46  * @method registerListenerEvents
47  * @param {HTMLElement} contentBank The DOM node of the content bank
48  */
49 const registerListenerEvents = (contentBank) => {
51     // The search.
52     const fileArea = document.querySelector(selectors.regions.filearea);
53     const shownItems = fileArea.querySelectorAll(selectors.elements.listitem);
55     // The view buttons.
56     const viewGrid = contentBank.querySelector(selectors.actions.viewgrid);
57     const viewList = contentBank.querySelector(selectors.actions.viewlist);
59     viewGrid.addEventListener('click', () => {
60         contentBank.classList.remove('view-list');
61         contentBank.classList.add('view-grid');
62         viewGrid.classList.add('active');
63         viewList.classList.remove('active');
64         setViewListPreference(false);
65     });
67     viewList.addEventListener('click', () => {
68         contentBank.classList.remove('view-grid');
69         contentBank.classList.add('view-list');
70         viewList.classList.add('active');
71         viewGrid.classList.remove('active');
72         setViewListPreference(true);
73     });
75     // Sort by file name alphabetical
76     const sortByName = contentBank.querySelector(selectors.actions.sortname);
77     sortByName.addEventListener('click', () => {
78         const ascending = updateSortButtons(contentBank, sortByName);
79         updateSortOrder(fileArea, shownItems, 'data-file', ascending);
80     });
82     // Sort by date.
83     const sortByDate = contentBank.querySelector(selectors.actions.sortdate);
84     sortByDate.addEventListener('click', () => {
85         const ascending = updateSortButtons(contentBank, sortByDate);
86         updateSortOrder(fileArea, shownItems, 'data-timemodified', ascending);
87     });
89     // Sort by size.
90     const sortBySize = contentBank.querySelector(selectors.actions.sortsize);
91     sortBySize.addEventListener('click', () => {
92         const ascending = updateSortButtons(contentBank, sortBySize);
93         updateSortOrder(fileArea, shownItems, 'data-bytes', ascending);
94     });
96     // Sort by type
97     const sortByType = contentBank.querySelector(selectors.actions.sorttype);
98     sortByType.addEventListener('click', () => {
99         const ascending = updateSortButtons(contentBank, sortByType);
100         updateSortOrder(fileArea, shownItems, 'data-type', ascending);
101     });
102 };
105 /**
106  * Set the contentbank user preference in list view
107  *
108  * @param  {Bool} viewList view ContentBank as list.
109  * @return {Promise} Repository promise.
110  */
111 const setViewListPreference = function(viewList) {
113     // If the given status is not hidden, the preference has to be deleted with a null value.
114     if (viewList === false) {
115         viewList = null;
116     }
118     const request = {
119         methodname: 'core_user_update_user_preferences',
120         args: {
121             preferences: [
122                 {
123                     type: 'core_contentbank_view_list',
124                     value: viewList
125                 }
126             ]
127         }
128     };
130     return Ajax.call([request])[0].catch(Notification.exception);
131 };
133 /**
134  * Update the sort button view.
135  *
136  * @method updateSortButtons
137  * @param {HTMLElement} contentBank The DOM node of the contentbank button
138  * @param {HTMLElement} sortButton The DOM node of the sort button
139  * @return {Bool} sort ascending
140  */
141 const updateSortButtons = (contentBank, sortButton) => {
142     const sortButtons = contentBank.querySelectorAll(selectors.elements.sortbutton);
144     sortButtons.forEach((button) => {
145         if (button !== sortButton) {
146             button.classList.remove('dir-asc');
147             button.classList.remove('dir-desc');
148             button.classList.add('dir-none');
150             updateButtonTitle(button, false);
151         }
152     });
154     let ascending = true;
156     if (sortButton.classList.contains('dir-none')) {
157         sortButton.classList.remove('dir-none');
158         sortButton.classList.add('dir-asc');
159     } else if (sortButton.classList.contains('dir-asc')) {
160         sortButton.classList.remove('dir-asc');
161         sortButton.classList.add('dir-desc');
162         ascending = false;
163     } else if (sortButton.classList.contains('dir-desc')) {
164         sortButton.classList.remove('dir-desc');
165         sortButton.classList.add('dir-asc');
166     }
168     updateButtonTitle(sortButton, ascending);
170     return ascending;
171 };
173 /**
174  * Update the button title.
175  *
176  * @method updateButtonTitle
177  * @param {HTMLElement} button Button to update
178  * @param {Bool} ascending Sort direction
179  * @return {Promise} string promise
180  */
181 const updateButtonTitle = (button, ascending) => {
183     const sortString = (ascending ? 'sortbyxreverse' : 'sortbyx');
185     return getString(button.dataset.string, 'contentbank')
186     .then(columnName => {
187         return getString(sortString, 'core', columnName);
188     })
189     .then(sortByString => {
190         button.setAttribute('title', sortByString);
191         return sortByString;
192     })
193     .catch();
194 };
196 /**
197  * Update the sort order of the itemlist and update the DOM
198  *
199  * @method updateSortOrder
200  * @param {HTMLElement} fileArea the Dom container for the itemlist
201  * @param {Array} itemList Nodelist of Dom elements
202  * @param {String} attribute, the attribut to sort on
203  * @param {Bool} ascending, Sort Ascending
204  */
205 const updateSortOrder = (fileArea, itemList, attribute, ascending) => {
206     const sortList = [].slice.call(itemList).sort(function(a, b) {
208         let aa = a.getAttribute(attribute);
209         let bb = b.getAttribute(attribute);
210         if (!isNaN(aa)) {
211            aa = parseInt(aa);
212            bb = parseInt(bb);
213         }
215         if (ascending) {
216             return aa > bb ? 1 : -1;
217         } else {
218             return aa < bb ? 1 : -1;
219         }
220     });
221     sortList.forEach(listItem => fileArea.appendChild(listItem));
222 };