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
 * JS for the mod_form page on mod_bigbluebuttonbn plugin.
18
 *
19
 * @module      mod_bigbluebuttonbn/modform
20
 * @copyright   2021 Blindside Networks Inc
21
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
import {getString} from 'core/str';
25
import Notification from 'core/notification';
26
import Templates from "core/templates";
27
 
28
/**
29
 * Get all selectors in one place.
30
 *
31
 */
32
const ELEMENT_SELECTOR = {
33
    instanceTypeSelection: () => document.querySelector('select#id_type'),
34
    instanceTypeProfiles: () => document.querySelector('[data-profile-types]'),
35
    participantData: () => document.querySelector('[data-participant-data]'),
36
    participantList: () => document.getElementsByName('participants')[0],
37
    participantTable: () => document.getElementById('participant_list_table'),
38
    participantSelectionType: () => document.getElementsByName('bigbluebuttonbn_participant_selection_type')[0],
39
    participantSelection: () => document.getElementsByName('bigbluebuttonbn_participant_selection')[0],
40
    participantAddButton: () => document.getElementsByName('bigbluebuttonbn_participant_selection_add')[0],
41
};
42
/**
43
 * Initialise the moodle form code.
44
 *
45
 * This will help hide or show items depending on the selection of the instance type.
46
 *
47
 * @method init
48
 * @param {object} info
49
 */
50
export const init = (info) => {
51
    const selectedType = ELEMENT_SELECTOR.instanceTypeSelection();
52
    const instanceTypeProfiles = JSON.parse(ELEMENT_SELECTOR.instanceTypeProfiles().dataset.profileTypes);
53
 
54
    let profileType = info.instanceTypeDefault;
55
    if (selectedType !== null && selectedType.selectedIndex !== -1) {
56
        profileType = selectedType.options[selectedType.selectedIndex].value;
57
    }
58
 
59
    const isFeatureEnabled = (profileType, feature) => {
60
        const features = instanceTypeProfiles[profileType].features;
61
        return (features.indexOf(feature) !== -1);
62
    };
63
    applyInstanceTypeProfile(profileType, isFeatureEnabled);
64
 
65
    // Change form visible fields depending on the selection.
66
    selectedType.addEventListener('change', (e) => {
67
        applyInstanceTypeProfile(e.target.value, isFeatureEnabled);
68
    });
69
 
70
    ELEMENT_SELECTOR.participantSelectionType().addEventListener('change', (e) => {
71
        const currentTypeSelect = e.target;
72
        updateSelectionFromType(currentTypeSelect);
73
    });
74
 
75
    ELEMENT_SELECTOR.participantAddButton().addEventListener('click', (e) => {
76
        e.stopPropagation();
77
        e.preventDefault();
78
        participantAddFromCurrentSelection();
79
    });
80
 
81
    participantListInit();
82
};
83
 
84
/**
85
 * Show or hide form element depending on the selected profile
86
 *
87
 * @param {string} profileType
88
 * @param {function} isFeatureEnabled
89
 */
90
const applyInstanceTypeProfile = (profileType, isFeatureEnabled) => {
91
    let showAll = isFeatureEnabled(profileType, 'all');
92
    const showFieldset = (id, show) => {
93
        // Show room settings validation.
94
        const node = document.querySelector('#' + id);
95
        if (!node) {
96
            return;
97
        }
98
        if (show) {
99
            node.style.display = 'block';
100
            return;
101
        }
102
        node.style.display = 'none';
103
    };
104
    const showInput = (id, show) => {
105
        // Show room settings validation.
106
        const node = document.querySelector('#' + id);
107
        if (!node) {
108
            return;
109
        }
110
        var ancestor = node.closest('div').closest('div');
111
        if (show) {
112
            ancestor.style.display = 'block';
113
            return;
114
        }
115
        ancestor.style.display = 'none';
116
    };
117
    const showFormGroup = (id, show) => {
118
        // Show room settings validation.
119
        const node = document.querySelector('#fgroup_id_' + id);
120
        if (!node) {
121
            return;
122
        }
123
        if (show) {
124
            node.classList.remove('hidden');
125
            return;
126
        }
127
        node.classList.add('hidden');
128
    };
129
    // Show room settings validation.
130
    showFieldset('id_room', showAll ||
131
        isFeatureEnabled(profileType, 'showroom'));
132
    showInput('id_record', showAll ||
133
        isFeatureEnabled(profileType, 'showroom'));
134
    // Show recordings settings validation.
135
    showFieldset('id_recordings', showAll ||
136
        isFeatureEnabled(profileType, 'showrecordings'));
137
    // Show recordings imported settings validation.
138
    showInput('id_recordings_imported', showAll ||
139
        isFeatureEnabled(profileType, 'showrecordings'));
140
    // Show lock settings validation.
141
    showFieldset('id_lock', showAll ||
142
        isFeatureEnabled(profileType, 'lock'));
143
    // Show guest settings validation.
144
    showFieldset('id_guestaccess', showAll ||
145
        isFeatureEnabled(profileType, 'showroom'));
146
    // Preuploadpresentation feature validation.
147
    showFieldset('id_preuploadpresentation', showAll ||
148
        isFeatureEnabled(profileType, 'preuploadpresentation'));
149
    // Participants feature validation.
150
    showFieldset('id_permissions', showAll ||
151
        isFeatureEnabled(profileType, 'permissions'));
152
    // Schedule feature validation.
153
    showFieldset('id_schedule', showAll ||
154
        isFeatureEnabled(profileType, 'schedule'));
155
    // Common module settings validation.
156
    showFieldset('id_modstandardelshdr', showAll ||
157
        isFeatureEnabled(profileType, 'modstandardelshdr'));
158
    // Restrict access validation.
159
    showFieldset('id_availabilityconditionsheader', showAll ||
160
        isFeatureEnabled(profileType, 'availabilityconditionsheader'));
161
    // Tags validation.
162
    showFieldset('id_tagshdr', showAll || isFeatureEnabled(profileType, 'tagshdr'));
163
    // Competencies validation.
164
    showFieldset('id_competenciessection', showAll ||
165
        isFeatureEnabled(profileType, 'competenciessection'));
166
    // Completion validation.
167
    showFormGroup('completionattendancegroup', showAll ||
168
        isFeatureEnabled(profileType, 'completionattendance'));
169
    // Completion validation.
170
    showFormGroup('completionengagementgroup', showAll ||
171
        isFeatureEnabled(profileType, 'completionengagement'));
172
};
173
 
174
/**
175
 * Init the participant list
176
 */
177
const participantListInit = () => {
178
    const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
179
    const participantList = getParticipantList();
180
    participantList.forEach(participant => {
181
        const selectionTypeValue = participant.selectiontype;
182
        const selectionValue = participant.selectionid;
183
        const selectionRole = participant.role;
184
        if (participant.selectiontype === 'all' ||
185
            typeof participantData[participant.selectiontype].children[participant.selectionid] !== 'undefined') {
186
            // Add it to the form, but don't add the delete button if it is the first item.
187
            participantAddToForm(selectionTypeValue, selectionValue, selectionRole, true).then();
188
        }
189
    });
190
};
191
 
192
/**
193
 * Add rows to the participant list depending on the current selection.
194
 *
195
 * @param {string} selectionTypeValue
196
 * @param {string} selectionValue
197
 * @param {string} selectedRole
198
 * @param {boolean} canRemove
199
 * @returns {Promise<void>}
200
 */
201
const participantAddToForm = async(selectionTypeValue, selectionValue, selectedRole, canRemove) => {
202
    const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
203
    const sviewer = await getString('mod_form_field_participant_bbb_role_viewer', 'mod_bigbluebuttonbn');
204
    const smoderator = await getString('mod_form_field_participant_bbb_role_moderator', 'mod_bigbluebuttonbn');
205
    let roles = {
206
        viewer: {'id': 'viewer', label: sviewer},
207
        moderator: {'id': 'moderator', label: smoderator}
208
    };
209
    roles[selectedRole].isselected = true;
210
    try {
211
        const listTable = document.querySelector('#participant_list_table tbody');
212
        const templateContext = {
213
            'selectiontypevalue': selectionTypeValue,
214
            'selectionvalue': selectionValue,
215
            'participanttype': participantData[selectionTypeValue].name,
216
            'participantvalue':
217
                (selectionTypeValue !== 'all') ?
218
                    participantData[selectionTypeValue].children[selectionValue].name : null,
219
            'roles': Object.values(roles),
220
            'canRemove': canRemove
221
        };
222
        const {html, js} = await Templates.renderForPromise('mod_bigbluebuttonbn/participant_form_add', templateContext);
223
        const newNode = Templates.appendNodeContents(listTable, html, js)[0];
224
        newNode.querySelector('.participant-select').addEventListener('change', () => {
225
            participantListRoleUpdate(selectionTypeValue, selectionValue);
226
        });
227
        // Now add the callbacks: participantListRoleUpdate() and participantRemove().
228
        const removeNode = newNode.querySelector('.remove-button');
229
        if (removeNode) {
230
            removeNode
231
                .addEventListener('click', () => {
232
                    participantRemove(selectionTypeValue, selectionValue);
233
                });
234
        }
235
 
236
    } catch (e) {
237
        Notification.exception(e);
238
    }
239
};
240
/*
241
 
242
 */
243
 
244
/**
245
 * Update the related form element with the list value.
246
 *
247
 * @param {object} list
248
 */
249
const participantListUpdate = (list) => {
250
    const participantList = ELEMENT_SELECTOR.participantList();
251
    participantList.value = JSON.stringify(list);
252
};
253
 
254
/**
255
 *
256
 * @returns {any}
257
 */
258
const getParticipantList = () => {
259
    const participantListValue = ELEMENT_SELECTOR.participantList().value;
260
    if (participantListValue) {
261
        return JSON.parse(participantListValue);
262
    }
263
    return [];
264
};
265
 
266
/**
267
 * Remove participant both in the table/form and in the form element.
268
 *
269
 * @param {string} selectionTypeValue
270
 * @param {string} selectionValue
271
 */
272
const participantRemove = (selectionTypeValue, selectionValue) => {
273
    const pList = getParticipantList();
274
    const id = 'participant_list_tr_' + selectionTypeValue + '-' + selectionValue;
275
    const participantListTable = ELEMENT_SELECTOR.participantTable();
276
    const selectionid = (selectionValue === '' ? null : selectionValue);
277
    for (let i = 0; i < pList.length; i++) {
278
        if (pList[i].selectiontype === selectionTypeValue &&
279
            pList[i].selectionid === selectionid) {
280
            pList.splice(i, 1);
281
        }
282
    }
283
    // Remove from the form.
284
    for (let i = 0; i < participantListTable.rows.length; i++) {
285
        if (participantListTable.rows[i].id === id) {
286
            participantListTable.deleteRow(i);
287
        }
288
    }
289
    // Update value in the form.
290
    participantListUpdate(pList);
291
};
292
 
293
/**
294
 * Role update
295
 *
296
 * @param {string} type
297
 * @param {string} id
298
 */
299
const participantListRoleUpdate = (type, id) => {
300
    // Update in memory.
301
    const participantListRoleSelection = document.querySelector(`#participant_list_tr_${type}-${id} .participant-select`);
302
    const pList = getParticipantList();
303
 
304
    for (var i = 0; i < pList.length; i++) {
305
        if (pList[i].selectiontype === type && pList[i].selectionid === id) {
306
            pList[i].role = participantListRoleSelection.value;
307
        }
308
    }
309
    // Update in the form.
310
    participantListUpdate(pList);
311
};
312
 
313
/**
314
 * Add participant from the currently selected options
315
 */
316
const participantAddFromCurrentSelection = () => {
317
    let selectionType = ELEMENT_SELECTOR.participantSelectionType();
318
    let selection = ELEMENT_SELECTOR.participantSelection();
319
    const pList = getParticipantList();
320
    // Lookup to see if it has been added already.
321
    for (var i = 0; i < pList.length; i++) {
322
        if (pList[i].selectiontype === selectionType.value &&
323
            pList[i].selectionid === selection.value) {
324
            return;
325
        }
326
    }
327
    pList.push({
328
        "selectiontype": selectionType.value,
329
        "selectionid": selection.value,
330
        "role": "viewer"
331
    });
332
    // Add it to the form.
333
    participantAddToForm(selectionType.value, selection.value, 'viewer', true).then();
334
    // Update in the form.
335
    participantListUpdate(pList);
336
};
337
 
338
/**
339
 * Update selectable options when changing types
340
 *
341
 * @param {HTMLNode} currentTypeSelect
342
 */
343
const updateSelectionFromType = (currentTypeSelect) => {
344
    const createNewOption = (selectItem, label, value) => {
345
        const option = document.createElement('option');
346
        option.text = label;
347
        option.value = value;
348
 
349
        selectItem.add(option);
350
    };
351
 
352
    const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
353
    // Clear all selection items.
354
    const participantSelect = ELEMENT_SELECTOR.participantSelection();
355
    while (participantSelect.firstChild) {
356
        participantSelect.removeChild(participantSelect.firstChild);
357
    }
358
    // Add options depending on the selection.
359
    if (currentTypeSelect.selectedIndex !== -1) {
360
        const options = Object.values(participantData[currentTypeSelect.value].children);
361
        options.forEach(option => {
362
            createNewOption(participantSelect, option.name, option.id);
363
        });
364
 
365
        if (currentTypeSelect.value === 'all') {
366
            createNewOption(participantSelect, '---------------', 'all');
367
            participantSelect.disabled = true;
368
        } else {
369
            participantSelect.disabled = false;
370
        }
371
    }
372
};