| 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'));
 | 
        
           | 1441 | ariadna | 166 |     // Standards grading feature validation.
 | 
        
           |  |  | 167 |     showFieldset('id_modstandardgrade', showAll ||
 | 
        
           |  |  | 168 |         isFeatureEnabled(profileType, 'modstandardgrade'));
 | 
        
           | 1 | efrain | 169 |     // Completion validation.
 | 
        
           | 1441 | ariadna | 170 |     showFieldset('id_activitycompletionheader', showAll ||
 | 
        
           |  |  | 171 |         isFeatureEnabled(profileType, 'activitycompletionheader'));
 | 
        
           |  |  | 172 |     // Completion validation.
 | 
        
           | 1 | efrain | 173 |     showFormGroup('completionattendancegroup', showAll ||
 | 
        
           |  |  | 174 |         isFeatureEnabled(profileType, 'completionattendance'));
 | 
        
           |  |  | 175 |     // Completion validation.
 | 
        
           |  |  | 176 |     showFormGroup('completionengagementgroup', showAll ||
 | 
        
           |  |  | 177 |         isFeatureEnabled(profileType, 'completionengagement'));
 | 
        
           |  |  | 178 | };
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 | /**
 | 
        
           |  |  | 181 |  * Init the participant list
 | 
        
           |  |  | 182 |  */
 | 
        
           |  |  | 183 | const participantListInit = () => {
 | 
        
           |  |  | 184 |     const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
 | 
        
           |  |  | 185 |     const participantList = getParticipantList();
 | 
        
           |  |  | 186 |     participantList.forEach(participant => {
 | 
        
           |  |  | 187 |         const selectionTypeValue = participant.selectiontype;
 | 
        
           |  |  | 188 |         const selectionValue = participant.selectionid;
 | 
        
           |  |  | 189 |         const selectionRole = participant.role;
 | 
        
           |  |  | 190 |         if (participant.selectiontype === 'all' ||
 | 
        
           |  |  | 191 |             typeof participantData[participant.selectiontype].children[participant.selectionid] !== 'undefined') {
 | 
        
           |  |  | 192 |             // Add it to the form, but don't add the delete button if it is the first item.
 | 
        
           |  |  | 193 |             participantAddToForm(selectionTypeValue, selectionValue, selectionRole, true).then();
 | 
        
           |  |  | 194 |         }
 | 
        
           |  |  | 195 |     });
 | 
        
           |  |  | 196 | };
 | 
        
           |  |  | 197 |   | 
        
           |  |  | 198 | /**
 | 
        
           |  |  | 199 |  * Add rows to the participant list depending on the current selection.
 | 
        
           |  |  | 200 |  *
 | 
        
           |  |  | 201 |  * @param {string} selectionTypeValue
 | 
        
           |  |  | 202 |  * @param {string} selectionValue
 | 
        
           |  |  | 203 |  * @param {string} selectedRole
 | 
        
           |  |  | 204 |  * @param {boolean} canRemove
 | 
        
           |  |  | 205 |  * @returns {Promise<void>}
 | 
        
           |  |  | 206 |  */
 | 
        
           |  |  | 207 | const participantAddToForm = async(selectionTypeValue, selectionValue, selectedRole, canRemove) => {
 | 
        
           |  |  | 208 |     const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
 | 
        
           |  |  | 209 |     const sviewer = await getString('mod_form_field_participant_bbb_role_viewer', 'mod_bigbluebuttonbn');
 | 
        
           |  |  | 210 |     const smoderator = await getString('mod_form_field_participant_bbb_role_moderator', 'mod_bigbluebuttonbn');
 | 
        
           |  |  | 211 |     let roles = {
 | 
        
           |  |  | 212 |         viewer: {'id': 'viewer', label: sviewer},
 | 
        
           |  |  | 213 |         moderator: {'id': 'moderator', label: smoderator}
 | 
        
           |  |  | 214 |     };
 | 
        
           |  |  | 215 |     roles[selectedRole].isselected = true;
 | 
        
           |  |  | 216 |     try {
 | 
        
           |  |  | 217 |         const listTable = document.querySelector('#participant_list_table tbody');
 | 
        
           |  |  | 218 |         const templateContext = {
 | 
        
           |  |  | 219 |             'selectiontypevalue': selectionTypeValue,
 | 
        
           |  |  | 220 |             'selectionvalue': selectionValue,
 | 
        
           |  |  | 221 |             'participanttype': participantData[selectionTypeValue].name,
 | 
        
           |  |  | 222 |             'participantvalue':
 | 
        
           |  |  | 223 |                 (selectionTypeValue !== 'all') ?
 | 
        
           |  |  | 224 |                     participantData[selectionTypeValue].children[selectionValue].name : null,
 | 
        
           |  |  | 225 |             'roles': Object.values(roles),
 | 
        
           |  |  | 226 |             'canRemove': canRemove
 | 
        
           |  |  | 227 |         };
 | 
        
           |  |  | 228 |         const {html, js} = await Templates.renderForPromise('mod_bigbluebuttonbn/participant_form_add', templateContext);
 | 
        
           |  |  | 229 |         const newNode = Templates.appendNodeContents(listTable, html, js)[0];
 | 
        
           |  |  | 230 |         newNode.querySelector('.participant-select').addEventListener('change', () => {
 | 
        
           |  |  | 231 |             participantListRoleUpdate(selectionTypeValue, selectionValue);
 | 
        
           |  |  | 232 |         });
 | 
        
           |  |  | 233 |         // Now add the callbacks: participantListRoleUpdate() and participantRemove().
 | 
        
           |  |  | 234 |         const removeNode = newNode.querySelector('.remove-button');
 | 
        
           |  |  | 235 |         if (removeNode) {
 | 
        
           |  |  | 236 |             removeNode
 | 
        
           |  |  | 237 |                 .addEventListener('click', () => {
 | 
        
           |  |  | 238 |                     participantRemove(selectionTypeValue, selectionValue);
 | 
        
           |  |  | 239 |                 });
 | 
        
           |  |  | 240 |         }
 | 
        
           |  |  | 241 |   | 
        
           |  |  | 242 |     } catch (e) {
 | 
        
           |  |  | 243 |         Notification.exception(e);
 | 
        
           |  |  | 244 |     }
 | 
        
           |  |  | 245 | };
 | 
        
           |  |  | 246 | /*
 | 
        
           |  |  | 247 |   | 
        
           |  |  | 248 |  */
 | 
        
           |  |  | 249 |   | 
        
           |  |  | 250 | /**
 | 
        
           |  |  | 251 |  * Update the related form element with the list value.
 | 
        
           |  |  | 252 |  *
 | 
        
           |  |  | 253 |  * @param {object} list
 | 
        
           |  |  | 254 |  */
 | 
        
           |  |  | 255 | const participantListUpdate = (list) => {
 | 
        
           |  |  | 256 |     const participantList = ELEMENT_SELECTOR.participantList();
 | 
        
           |  |  | 257 |     participantList.value = JSON.stringify(list);
 | 
        
           |  |  | 258 | };
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 | /**
 | 
        
           |  |  | 261 |  *
 | 
        
           |  |  | 262 |  * @returns {any}
 | 
        
           |  |  | 263 |  */
 | 
        
           |  |  | 264 | const getParticipantList = () => {
 | 
        
           |  |  | 265 |     const participantListValue = ELEMENT_SELECTOR.participantList().value;
 | 
        
           |  |  | 266 |     if (participantListValue) {
 | 
        
           |  |  | 267 |         return JSON.parse(participantListValue);
 | 
        
           |  |  | 268 |     }
 | 
        
           |  |  | 269 |     return [];
 | 
        
           |  |  | 270 | };
 | 
        
           |  |  | 271 |   | 
        
           |  |  | 272 | /**
 | 
        
           |  |  | 273 |  * Remove participant both in the table/form and in the form element.
 | 
        
           |  |  | 274 |  *
 | 
        
           |  |  | 275 |  * @param {string} selectionTypeValue
 | 
        
           |  |  | 276 |  * @param {string} selectionValue
 | 
        
           |  |  | 277 |  */
 | 
        
           |  |  | 278 | const participantRemove = (selectionTypeValue, selectionValue) => {
 | 
        
           |  |  | 279 |     const pList = getParticipantList();
 | 
        
           |  |  | 280 |     const id = 'participant_list_tr_' + selectionTypeValue + '-' + selectionValue;
 | 
        
           |  |  | 281 |     const participantListTable = ELEMENT_SELECTOR.participantTable();
 | 
        
           |  |  | 282 |     const selectionid = (selectionValue === '' ? null : selectionValue);
 | 
        
           |  |  | 283 |     for (let i = 0; i < pList.length; i++) {
 | 
        
           |  |  | 284 |         if (pList[i].selectiontype === selectionTypeValue &&
 | 
        
           |  |  | 285 |             pList[i].selectionid === selectionid) {
 | 
        
           |  |  | 286 |             pList.splice(i, 1);
 | 
        
           |  |  | 287 |         }
 | 
        
           |  |  | 288 |     }
 | 
        
           |  |  | 289 |     // Remove from the form.
 | 
        
           |  |  | 290 |     for (let i = 0; i < participantListTable.rows.length; i++) {
 | 
        
           |  |  | 291 |         if (participantListTable.rows[i].id === id) {
 | 
        
           |  |  | 292 |             participantListTable.deleteRow(i);
 | 
        
           |  |  | 293 |         }
 | 
        
           |  |  | 294 |     }
 | 
        
           |  |  | 295 |     // Update value in the form.
 | 
        
           |  |  | 296 |     participantListUpdate(pList);
 | 
        
           |  |  | 297 | };
 | 
        
           |  |  | 298 |   | 
        
           |  |  | 299 | /**
 | 
        
           |  |  | 300 |  * Role update
 | 
        
           |  |  | 301 |  *
 | 
        
           |  |  | 302 |  * @param {string} type
 | 
        
           |  |  | 303 |  * @param {string} id
 | 
        
           |  |  | 304 |  */
 | 
        
           |  |  | 305 | const participantListRoleUpdate = (type, id) => {
 | 
        
           |  |  | 306 |     // Update in memory.
 | 
        
           |  |  | 307 |     const participantListRoleSelection = document.querySelector(`#participant_list_tr_${type}-${id} .participant-select`);
 | 
        
           |  |  | 308 |     const pList = getParticipantList();
 | 
        
           |  |  | 309 |   | 
        
           |  |  | 310 |     for (var i = 0; i < pList.length; i++) {
 | 
        
           |  |  | 311 |         if (pList[i].selectiontype === type && pList[i].selectionid === id) {
 | 
        
           |  |  | 312 |             pList[i].role = participantListRoleSelection.value;
 | 
        
           |  |  | 313 |         }
 | 
        
           |  |  | 314 |     }
 | 
        
           |  |  | 315 |     // Update in the form.
 | 
        
           |  |  | 316 |     participantListUpdate(pList);
 | 
        
           |  |  | 317 | };
 | 
        
           |  |  | 318 |   | 
        
           |  |  | 319 | /**
 | 
        
           |  |  | 320 |  * Add participant from the currently selected options
 | 
        
           |  |  | 321 |  */
 | 
        
           |  |  | 322 | const participantAddFromCurrentSelection = () => {
 | 
        
           |  |  | 323 |     let selectionType = ELEMENT_SELECTOR.participantSelectionType();
 | 
        
           |  |  | 324 |     let selection = ELEMENT_SELECTOR.participantSelection();
 | 
        
           |  |  | 325 |     const pList = getParticipantList();
 | 
        
           |  |  | 326 |     // Lookup to see if it has been added already.
 | 
        
           |  |  | 327 |     for (var i = 0; i < pList.length; i++) {
 | 
        
           |  |  | 328 |         if (pList[i].selectiontype === selectionType.value &&
 | 
        
           |  |  | 329 |             pList[i].selectionid === selection.value) {
 | 
        
           |  |  | 330 |             return;
 | 
        
           |  |  | 331 |         }
 | 
        
           |  |  | 332 |     }
 | 
        
           |  |  | 333 |     pList.push({
 | 
        
           |  |  | 334 |         "selectiontype": selectionType.value,
 | 
        
           |  |  | 335 |         "selectionid": selection.value,
 | 
        
           |  |  | 336 |         "role": "viewer"
 | 
        
           |  |  | 337 |     });
 | 
        
           |  |  | 338 |     // Add it to the form.
 | 
        
           |  |  | 339 |     participantAddToForm(selectionType.value, selection.value, 'viewer', true).then();
 | 
        
           |  |  | 340 |     // Update in the form.
 | 
        
           |  |  | 341 |     participantListUpdate(pList);
 | 
        
           |  |  | 342 | };
 | 
        
           |  |  | 343 |   | 
        
           |  |  | 344 | /**
 | 
        
           |  |  | 345 |  * Update selectable options when changing types
 | 
        
           |  |  | 346 |  *
 | 
        
           |  |  | 347 |  * @param {HTMLNode} currentTypeSelect
 | 
        
           |  |  | 348 |  */
 | 
        
           |  |  | 349 | const updateSelectionFromType = (currentTypeSelect) => {
 | 
        
           |  |  | 350 |     const createNewOption = (selectItem, label, value) => {
 | 
        
           |  |  | 351 |         const option = document.createElement('option');
 | 
        
           |  |  | 352 |         option.text = label;
 | 
        
           |  |  | 353 |         option.value = value;
 | 
        
           |  |  | 354 |   | 
        
           |  |  | 355 |         selectItem.add(option);
 | 
        
           |  |  | 356 |     };
 | 
        
           |  |  | 357 |   | 
        
           |  |  | 358 |     const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
 | 
        
           |  |  | 359 |     // Clear all selection items.
 | 
        
           |  |  | 360 |     const participantSelect = ELEMENT_SELECTOR.participantSelection();
 | 
        
           |  |  | 361 |     while (participantSelect.firstChild) {
 | 
        
           |  |  | 362 |         participantSelect.removeChild(participantSelect.firstChild);
 | 
        
           |  |  | 363 |     }
 | 
        
           |  |  | 364 |     // Add options depending on the selection.
 | 
        
           |  |  | 365 |     if (currentTypeSelect.selectedIndex !== -1) {
 | 
        
           |  |  | 366 |         const options = Object.values(participantData[currentTypeSelect.value].children);
 | 
        
           |  |  | 367 |         options.forEach(option => {
 | 
        
           |  |  | 368 |             createNewOption(participantSelect, option.name, option.id);
 | 
        
           |  |  | 369 |         });
 | 
        
           |  |  | 370 |   | 
        
           |  |  | 371 |         if (currentTypeSelect.value === 'all') {
 | 
        
           |  |  | 372 |             createNewOption(participantSelect, '---------------', 'all');
 | 
        
           |  |  | 373 |             participantSelect.disabled = true;
 | 
        
           |  |  | 374 |         } else {
 | 
        
           |  |  | 375 |             participantSelect.disabled = false;
 | 
        
           |  |  | 376 |         }
 | 
        
           |  |  | 377 |     }
 | 
        
           |  |  | 378 | };
 |