Proyectos de Subversion Moodle

Rev

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