Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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/>.
15
 
16
/**
17
 * Content bank UI actions.
18
 *
19
 * @module     core_contentbank/sort
20
 * @copyright  2020 Bas Brands <bas@moodle.com>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
import selectors from './selectors';
25
import {getString} from 'core/str';
26
import Prefetch from 'core/prefetch';
27
import Notification from 'core/notification';
28
import {setUserPreference} from 'core_user/repository';
29
 
30
/**
31
 * Set up the contentbank views.
32
 *
33
 * @method init
34
 */
35
export const init = () => {
36
    const contentBank = document.querySelector(selectors.regions.contentbank);
37
    Prefetch.prefetchStrings('contentbank', ['contentname', 'uses', 'lastmodified', 'size', 'type', 'author']);
38
    Prefetch.prefetchStrings('moodle', ['sortbyx', 'sortbyxreverse']);
39
    registerListenerEvents(contentBank);
40
};
41
 
42
/**
43
 * Register contentbank related event listeners.
44
 *
45
 * @method registerListenerEvents
46
 * @param {HTMLElement} contentBank The DOM node of the content bank
47
 */
48
const registerListenerEvents = (contentBank) => {
49
 
50
    contentBank.addEventListener('click', e => {
51
        const viewList = contentBank.querySelector(selectors.actions.viewlist);
52
        const viewGrid = contentBank.querySelector(selectors.actions.viewgrid);
53
        const fileArea = contentBank.querySelector(selectors.regions.filearea);
54
        const shownItems = fileArea.querySelectorAll(selectors.elements.listitem);
55
 
56
        // View as Grid button.
57
        if (e.target.closest(selectors.actions.viewgrid)) {
58
            contentBank.classList.remove('view-list');
59
            contentBank.classList.add('view-grid');
60
            if (fileArea && shownItems) {
61
                fileArea.setAttribute('role', 'list');
62
                shownItems.forEach(listItem => {
63
                    listItem.setAttribute('role', 'listitem');
64
                    listItem.querySelectorAll(selectors.elements.cell).forEach(cell => cell.removeAttribute('role'));
65
                });
66
 
67
                const heading = fileArea.querySelector(selectors.elements.heading);
68
                if (heading) {
69
                    heading.removeAttribute('role');
70
                    heading.querySelectorAll(selectors.elements.cell).forEach(cell => cell.removeAttribute('role'));
71
                }
72
            }
73
            viewGrid.classList.add('active');
74
            viewList.classList.remove('active');
75
            setViewListPreference(false);
76
 
77
            return;
78
        }
79
 
80
        // View as List button.
81
        if (e.target.closest(selectors.actions.viewlist)) {
82
            contentBank.classList.remove('view-grid');
83
            contentBank.classList.add('view-list');
84
            if (fileArea && shownItems) {
85
                fileArea.setAttribute('role', 'table');
86
                shownItems.forEach(listItem => {
87
                    listItem.setAttribute('role', 'row');
88
                    listItem.querySelectorAll(selectors.elements.cell).forEach(cell => cell.setAttribute('role', 'cell'));
89
                });
90
 
91
                const heading = fileArea.querySelector(selectors.elements.heading);
92
                if (heading) {
93
                    heading.setAttribute('role', 'row');
94
                    heading.querySelectorAll(selectors.elements.cell).forEach(cell => cell.setAttribute('role', 'columnheader'));
95
                }
96
            }
97
            viewList.classList.add('active');
98
            viewGrid.classList.remove('active');
99
            setViewListPreference(true);
100
 
101
            return;
102
        }
103
 
104
        if (fileArea && shownItems) {
105
 
106
            // Sort by file name alphabetical
107
            const sortByName = e.target.closest(selectors.actions.sortname);
108
            if (sortByName) {
109
                const ascending = updateSortButtons(contentBank, sortByName);
110
                updateSortOrder(fileArea, shownItems, 'data-file', ascending);
111
                return;
112
            }
113
 
114
            // Sort by uses.
115
            const sortByUses = e.target.closest(selectors.actions.sortuses);
116
            if (sortByUses) {
117
                const ascending = updateSortButtons(contentBank, sortByUses);
118
                updateSortOrder(fileArea, shownItems, 'data-uses', ascending);
119
                return;
120
            }
121
 
122
            // Sort by date.
123
            const sortByDate = e.target.closest(selectors.actions.sortdate);
124
            if (sortByDate) {
125
                const ascending = updateSortButtons(contentBank, sortByDate);
126
                updateSortOrder(fileArea, shownItems, 'data-timemodified', ascending);
127
                return;
128
            }
129
 
130
            // Sort by size.
131
            const sortBySize = e.target.closest(selectors.actions.sortsize);
132
            if (sortBySize) {
133
                const ascending = updateSortButtons(contentBank, sortBySize);
134
                updateSortOrder(fileArea, shownItems, 'data-bytes', ascending);
135
                return;
136
            }
137
 
138
            // Sort by type.
139
            const sortByType = e.target.closest(selectors.actions.sorttype);
140
            if (sortByType) {
141
                const ascending = updateSortButtons(contentBank, sortByType);
142
                updateSortOrder(fileArea, shownItems, 'data-type', ascending);
143
                return;
144
            }
145
 
146
            // Sort by author.
147
            const sortByAuthor = e.target.closest(selectors.actions.sortauthor);
148
            if (sortByAuthor) {
149
                const ascending = updateSortButtons(contentBank, sortByAuthor);
150
                updateSortOrder(fileArea, shownItems, 'data-author', ascending);
151
            }
152
            return;
153
        }
154
    });
155
};
156
 
157
 
158
/**
159
 * Set the contentbank user preference in list view
160
 *
161
 * @param  {Bool} viewList view ContentBank as list.
162
 * @return {Promise} Repository promise.
163
 */
164
const setViewListPreference = function(viewList) {
165
 
166
    // If the given status is not hidden, the preference has to be deleted with a null value.
167
    if (viewList === false) {
168
        viewList = null;
169
    }
170
 
171
    return setUserPreference('core_contentbank_view_list', viewList)
172
        .catch(Notification.exception);
173
};
174
 
175
/**
176
 * Update the sort button view.
177
 *
178
 * @method updateSortButtons
179
 * @param {HTMLElement} contentBank The DOM node of the contentbank button
180
 * @param {HTMLElement} sortButton The DOM node of the sort button
181
 * @return {Bool} sort ascending
182
 */
183
const updateSortButtons = (contentBank, sortButton) => {
184
    const sortButtons = contentBank.querySelectorAll(selectors.elements.sortbutton);
185
 
186
    sortButtons.forEach((button) => {
187
        if (button !== sortButton) {
188
            button.classList.remove('dir-asc');
189
            button.classList.remove('dir-desc');
190
            button.classList.add('dir-none');
191
 
192
            button.closest(selectors.elements.cell).setAttribute('aria-sort', 'none');
193
 
194
            updateButtonTitle(button, false);
195
        }
196
    });
197
 
198
    let ascending = true;
199
 
200
    if (sortButton.classList.contains('dir-none')) {
201
        sortButton.classList.remove('dir-none');
202
        sortButton.classList.add('dir-asc');
203
        sortButton.closest(selectors.elements.cell).setAttribute('aria-sort', 'ascending');
204
    } else if (sortButton.classList.contains('dir-asc')) {
205
        sortButton.classList.remove('dir-asc');
206
        sortButton.classList.add('dir-desc');
207
        sortButton.closest(selectors.elements.cell).setAttribute('aria-sort', 'descending');
208
        ascending = false;
209
    } else if (sortButton.classList.contains('dir-desc')) {
210
        sortButton.classList.remove('dir-desc');
211
        sortButton.classList.add('dir-asc');
212
        sortButton.closest(selectors.elements.cell).setAttribute('aria-sort', 'ascending');
213
    }
214
 
215
    updateButtonTitle(sortButton, ascending);
216
 
217
    return ascending;
218
};
219
 
220
/**
221
 * Update the button title.
222
 *
223
 * @method updateButtonTitle
224
 * @param {HTMLElement} button Button to update
225
 * @param {Bool} ascending Sort direction
226
 * @return {Promise} string promise
227
 */
228
const updateButtonTitle = (button, ascending) => {
229
 
230
    const sortString = (ascending ? 'sortbyxreverse' : 'sortbyx');
231
 
232
    return getString(button.dataset.string, 'contentbank')
233
    .then(columnName => {
234
        return getString(sortString, 'core', columnName);
235
    })
236
    .then(sortByString => {
237
        button.setAttribute('title', sortByString);
238
        return sortByString;
239
    })
240
    .catch();
241
};
242
 
243
/**
244
 * Update the sort order of the itemlist and update the DOM
245
 *
246
 * @method updateSortOrder
247
 * @param {HTMLElement} fileArea the Dom container for the itemlist
248
 * @param {Array} itemList Nodelist of Dom elements
249
 * @param {String} attribute the attribut to sort on
250
 * @param {Bool} ascending Sort Ascending
251
 */
252
const updateSortOrder = (fileArea, itemList, attribute, ascending) => {
253
    const sortList = [].slice.call(itemList).sort(function(a, b) {
254
 
255
        let aa = a.getAttribute(attribute);
256
        let bb = b.getAttribute(attribute);
257
        if (!isNaN(aa)) {
258
           aa = parseInt(aa);
259
           bb = parseInt(bb);
260
        }
261
 
262
        if (ascending) {
263
            return aa > bb ? 1 : -1;
264
        } else {
265
            return aa < bb ? 1 : -1;
266
        }
267
    });
268
    sortList.forEach(listItem => fileArea.appendChild(listItem));
269
};