Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | 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
 * Lazy loaded list of items.
18
 *
19
 * @module     core_message/message_drawer_lazy_load_list
20
 * @copyright  2018 Ryan Wyllie <ryan@moodle.com>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
define(
24
[
25
    'jquery',
26
    'core/custom_interaction_events'
27
],
28
function(
29
    $,
30
    CustomEvents
31
) {
32
 
33
    var SELECTORS = {
34
        ROOT: '[data-region="lazy-load-list"]',
35
        LOADING_ICON_CONTAINER: '[data-region="loading-icon-container"]',
36
        CONTENT_CONTAINER: '[data-region="content-container"]',
37
        EMPTY_MESSAGE: '[data-region="empty-message-container"]',
38
        PLACEHOLDER: '[data-region="placeholder-container"]'
39
    };
40
 
41
    /**
42
     * Flag element as loading.
43
     *
44
     * @param {Object} root The section container element.
45
     */
46
    var startLoading = function(root) {
47
        root.attr('data-loading', true);
48
    };
49
 
50
    /**
51
     * Flag element as not loading.
52
     *
53
     * @param {Object} root The section container element.
54
     */
55
    var stopLoading = function(root) {
56
        root.attr('data-loading', false);
57
    };
58
 
59
    /**
60
     * Check if the element is loading.
61
     *
62
     * @param {Object} root The section container element.
63
     * @return {Bool}
64
     */
65
    var isLoading = function(root) {
66
        return root.attr('data-loading') === 'true';
67
    };
68
 
69
    /**
70
     * Get user id
71
     *
72
     * @param  {Object} root The section container element.
73
     * @return {Number} Logged in user id.
74
     */
75
    var getUserId = function(root) {
76
        return root.attr('data-user-id');
77
    };
78
 
79
    /**
80
     * Get the section content container element.
81
     *
82
     * @param  {Object} root The section container element.
83
     * @return {Object} The section content container element.
84
     */
85
    var getContentContainer = function(root) {
86
        return root.find(SELECTORS.CONTENT_CONTAINER);
87
    };
88
 
89
    /**
90
     * Get the root element.
91
     *
92
     * @param  {Object} containerElement The container element to search in.
93
     * @return {Object} The list root element.
94
     */
95
    var getRoot = function(containerElement) {
96
        return containerElement.find(SELECTORS.ROOT);
97
    };
98
 
99
    /**
100
     * Show the loading icon.
101
     *
102
     * @param {Object} root The section container element.
103
     */
104
    var showLoadingIcon = function(root) {
105
        root.find(SELECTORS.LOADING_ICON_CONTAINER).removeClass('hidden');
106
    };
107
 
108
    /**
109
     * Hide the loading icon.
110
     *
111
     * @param {Object} root The section container element.
112
     */
113
    var hideLoadingIcon = function(root) {
114
        root.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden');
115
    };
116
 
117
    /**
118
     * Show the empty message.
119
     *
120
     * @param {Object} root The section container element.
121
     */
122
    var showEmptyMessage = function(root) {
123
        root.find(SELECTORS.EMPTY_MESSAGE).removeClass('hidden');
124
    };
125
 
126
    /**
127
     * Hide the empty message.
128
     *
129
     * @param {Object} root The section container element.
130
     */
131
    var hideEmptyMessage = function(root) {
132
        root.find(SELECTORS.EMPTY_MESSAGE).addClass('hidden');
133
    };
134
 
135
    /**
136
     * Show the placeholder element.
137
     *
138
     * @param {Object} root The section container element.
139
     */
140
    var showPlaceholder = function(root) {
141
        root.find(SELECTORS.PLACEHOLDER).removeClass('hidden');
142
    };
143
 
144
    /**
145
     * Hide the placeholder element.
146
     *
147
     * @param {Object} root The section container element.
148
     */
149
    var hidePlaceholder = function(root) {
150
        root.find(SELECTORS.PLACEHOLDER).addClass('hidden');
151
    };
152
 
153
    /**
154
     * Show the section content container.
155
     *
156
     * @param {Object} root The section container element.
157
     */
158
    var showContent = function(root) {
159
        getContentContainer(root).removeClass('hidden');
160
    };
161
 
162
    /**
163
     * Hide the section content container.
164
     *
165
     * @param {Object} root The section container element.
166
     */
167
    var hideContent = function(root) {
168
        getContentContainer(root).addClass('hidden');
169
    };
170
 
171
    /**
172
     * If the section has loaded all content.
173
     *
174
     * @param {Object} root The section container element.
175
     * @return {Bool}
176
     */
177
    var hasLoadedAll = function(root) {
178
        return root.attr('data-loaded-all') == 'true';
179
    };
180
 
181
    /**
182
     * If the section has loaded all content.
183
     *
184
     * @param {Object} root The section container element.
185
     * @param {Bool} value If all items have been loaded.
186
     */
187
    var setLoadedAll = function(root, value) {
188
        root.attr('data-loaded-all', value);
189
    };
190
 
191
    /**
192
     * If the section can load more items.
193
     *
194
     * @param {Object} root The section container element.
195
     * @return {Bool}
196
     */
197
    var canLoadMore = function(root) {
198
        return !hasLoadedAll(root) && !isLoading(root);
199
    };
200
 
201
    /**
202
     * Load all items in this container from callback and render them.
203
     *
204
     * @param {Object} root The section container element.
205
     * @param {Function} loadCallback The callback to load items.
206
     * @param {Function} renderCallback The callback to render the results.
207
     * @return {Object} jQuery promise
208
     */
209
    var loadAndRender = function(root, loadCallback, renderCallback) {
210
        var userId = getUserId(root);
211
        startLoading(root);
212
 
213
        return loadCallback(root, userId)
214
            .then(function(items) {
215
                if (items.length > 0) {
216
                    var contentContainer = getContentContainer(root);
217
                    return renderCallback(contentContainer, items, userId)
218
                        .then(function() {
219
                            return items;
220
                        });
221
                } else {
222
                    return items;
223
                }
224
            })
225
            .then(function(items) {
226
                stopLoading(root);
227
                root.attr('data-seen', true);
228
 
229
                if (!items.length) {
230
                    setLoadedAll(root, true);
231
                }
232
 
233
                return items;
234
            })
235
            .catch(function() {
236
                stopLoading(root);
237
                root.attr('data-seen', true);
238
                return;
239
            });
240
    };
241
 
242
    /**
243
     * First load of this section.
244
     *
245
     * @param {Object} root The section container element.
246
     * @param {Function} loadCallback The callback to load items.
247
     * @param {Function} renderCallback The callback to render the results.
248
     * @return {Object} promise
249
     */
250
    var initialLoadAndRender = function(root, loadCallback, renderCallback) {
251
        getContentContainer(root).empty();
252
        showPlaceholder(root);
253
        hideContent(root);
254
        return loadAndRender(root, loadCallback, renderCallback)
255
            .then(function(items) {
256
                hidePlaceholder(root);
257
 
258
                if (!items.length) {
259
                    showEmptyMessage(root);
260
                } else {
261
                    showContent(root);
262
                }
263
 
264
                return;
265
            })
266
            .catch(function() {
267
                hidePlaceholder(root);
268
                showContent(root);
269
                return;
270
            });
271
    };
272
 
273
    /**
274
     * Listen to, and handle events in this section.
275
     *
276
     * @param {Object} root The section container element.
277
     * @param {Function} loadCallback The callback to load items.
278
     * @param {Function} renderCallback The callback to render the results.
279
     */
280
    var registerEventListeners = function(root, loadCallback, renderCallback) {
281
        CustomEvents.define(root, [
282
            CustomEvents.events.scrollBottom
283
        ]);
284
 
285
        root.on(CustomEvents.events.scrollBottom, function() {
286
            if (canLoadMore(root)) {
287
                showLoadingIcon(root);
288
                loadAndRender(root, loadCallback, renderCallback)
289
                    .then(function() {
290
                        return hideLoadingIcon(root);
291
                    })
292
                    .catch(function() {
293
                        return hideLoadingIcon(root);
294
                    });
295
            }
296
        });
297
    };
298
 
299
    /**
300
     * Setup the section.
301
     *
302
     * @param {Object} root The section container element.
303
     * @param {Function} loadCallback The callback to load items.
304
     * @param {Function} renderCallback The callback to render the results.
305
     */
306
    var show = function(root, loadCallback, renderCallback) {
307
        root = $(root);
308
 
309
        if (!root.attr('data-init')) {
310
            registerEventListeners(root, loadCallback, renderCallback);
311
            initialLoadAndRender(root, loadCallback, renderCallback);
312
            root.attr('data-init', true);
313
        }
314
    };
315
 
316
    return {
317
        show: show,
318
        getContentContainer: getContentContainer,
319
        getRoot: getRoot,
320
        setLoadedAll: setLoadedAll,
321
        showEmptyMessage: showEmptyMessage,
322
        hideEmptyMessage: hideEmptyMessage,
323
        showContent: showContent,
324
        hideContent: hideContent
325
    };
326
});