From 7de01c97c2ef6ce5c36186b9e3ee8a624e339e05 Mon Sep 17 00:00:00 2001 From: Laurent David Date: Thu, 20 Oct 2022 19:36:38 +0200 Subject: [PATCH] MDL-74638 mod_bigbluebutton: Multiple fixes to room layout * In preparation for the guest access trigger button, move the join session button to the right * Fix id in the templates to be more consistent * Fix issue with room refreshing process so it replaces the node instead of node content. --- .../amd/build/roomupdater.min.js | 2 +- .../amd/build/roomupdater.min.js.map | 2 +- mod/bigbluebuttonbn/amd/src/roomupdater.js | 4 +- .../classes/external/meeting_info.php | 1 + .../lang/en/bigbluebuttonbn.php | 14 +- .../templates/end_session_button.mustache | 2 +- .../templates/room_view.mustache | 120 ++++++++++-------- 7 files changed, 80 insertions(+), 65 deletions(-) diff --git a/mod/bigbluebuttonbn/amd/build/roomupdater.min.js b/mod/bigbluebuttonbn/amd/build/roomupdater.min.js index 4825735118e..579c5887ec7 100644 --- a/mod/bigbluebuttonbn/amd/build/roomupdater.min.js +++ b/mod/bigbluebuttonbn/amd/build/roomupdater.min.js @@ -5,6 +5,6 @@ define("mod_bigbluebuttonbn/roomupdater",["exports","core/templates","core/notif * @module mod_bigbluebuttonbn/roomupdater * @copyright 2021 Blindside Networks Inc * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.updateRoom=_exports.stop=_exports.start=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};let timerReference=null,timerRunning=!1,pollInterval=0,pollIntervalFactor=1;const resetValues=()=>{timerRunning=!1,timerReference=null,pollInterval=0,pollIntervalFactor=1};_exports.start=interval=>{resetValues(),timerRunning=!0,pollInterval=interval,poll()};_exports.stop=()=>{timerReference&&clearTimeout(timerReference),resetValues()};const poll=()=>{timerRunning&&pollInterval&&updateRoom().then((updateOk=>(updateOk||(pollIntervalFactor=pollIntervalFactor<10?pollIntervalFactor+1:10),timerReference=setTimeout((()=>poll()),pollInterval*pollIntervalFactor),!0))).catch()},updateRoom=function(){let updatecache=arguments.length>0&&void 0!==arguments[0]&&arguments[0];const bbbRoomViewElement=document.getElementById("bbb-room-view"),bbbId=bbbRoomViewElement.dataset.bbbId,groupId=bbbRoomViewElement.dataset.groupId;return(0,_repository.getMeetingInfo)(bbbId,groupId,updatecache).then((data=>(data.haspresentations=!(!data.presentations||!data.presentations.length),_templates.default.renderForPromise("mod_bigbluebuttonbn/room_view",data)))).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.replaceNodeContents(bbbRoomViewElement,html,js)})).then((()=>!0)).catch((ex=>((0,_notification.exception)(ex),!1)))};_exports.updateRoom=updateRoom})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.updateRoom=_exports.stop=_exports.start=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};let timerReference=null,timerRunning=!1,pollInterval=0,pollIntervalFactor=1;const resetValues=()=>{timerRunning=!1,timerReference=null,pollInterval=0,pollIntervalFactor=1};_exports.start=interval=>{resetValues(),timerRunning=!0,pollInterval=interval,poll()};_exports.stop=()=>{timerReference&&clearTimeout(timerReference),resetValues()};const poll=()=>{timerRunning&&pollInterval&&updateRoom().then((updateOk=>(updateOk||(pollIntervalFactor=pollIntervalFactor<10?pollIntervalFactor+1:10),timerReference=setTimeout((()=>poll()),pollInterval*pollIntervalFactor),!0))).catch()},updateRoom=function(){let updatecache=arguments.length>0&&void 0!==arguments[0]&&arguments[0];const bbbRoomViewElement=document.getElementById("bigbluebuttonbn-room-view"),bbbId=bbbRoomViewElement.dataset.bbbId,groupId=bbbRoomViewElement.dataset.groupId;return(0,_repository.getMeetingInfo)(bbbId,groupId,updatecache).then((data=>(data.haspresentations=!(!data.presentations||!data.presentations.length),_templates.default.renderForPromise("mod_bigbluebuttonbn/room_view",data)))).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.replaceNode(bbbRoomViewElement,html,js)})).then((()=>!0)).catch((ex=>((0,_notification.exception)(ex),!1)))};_exports.updateRoom=updateRoom})); //# sourceMappingURL=roomupdater.min.js.map \ No newline at end of file diff --git a/mod/bigbluebuttonbn/amd/build/roomupdater.min.js.map b/mod/bigbluebuttonbn/amd/build/roomupdater.min.js.map index 8e4f5469e4b..f09538072c3 100644 --- a/mod/bigbluebuttonbn/amd/build/roomupdater.min.js.map +++ b/mod/bigbluebuttonbn/amd/build/roomupdater.min.js.map @@ -1 +1 @@ -{"version":3,"file":"roomupdater.min.js","sources":["../src/roomupdater.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * JS room updater.\n *\n * @module mod_bigbluebuttonbn/roomupdater\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Templates from \"core/templates\";\nimport {exception as displayException} from 'core/notification';\nimport {getMeetingInfo} from './repository';\n\nlet timerReference = null;\nlet timerRunning = false;\nlet pollInterval = 0;\nlet pollIntervalFactor = 1;\nconst MAX_POLL_INTERVAL_FACTOR = 10;\n\nconst resetValues = () => {\n timerRunning = false;\n timerReference = null;\n pollInterval = 0;\n pollIntervalFactor = 1;\n};\n\n/**\n * Start the information poller.\n * @param {Number} interval interval in miliseconds between each poll action.\n */\nexport const start = (interval) => {\n resetValues();\n timerRunning = true;\n pollInterval = interval;\n poll();\n};\n\n/**\n * Stop the room updater.\n */\nexport const stop = () => {\n if (timerReference) {\n clearTimeout(timerReference);\n }\n resetValues();\n};\n\n/**\n * Start the information poller.\n */\nconst poll = () => {\n if (!timerRunning || !pollInterval) {\n // The poller has been stopped.\n return;\n }\n updateRoom()\n .then((updateOk) => {\n if (!updateOk) {\n pollIntervalFactor = (pollIntervalFactor < MAX_POLL_INTERVAL_FACTOR) ?\n pollIntervalFactor + 1 : MAX_POLL_INTERVAL_FACTOR;\n // We make sure if there is an error that we do not try too often.\n }\n timerReference = setTimeout(() => poll(), pollInterval * pollIntervalFactor);\n return true;\n })\n .catch();\n};\n\n/**\n * Update the room information.\n *\n * @param {boolean} [updatecache=false] should we update cache\n * @returns {Promise}\n */\nexport const updateRoom = (updatecache = false) => {\n const bbbRoomViewElement = document.getElementById('bbb-room-view');\n const bbbId = bbbRoomViewElement.dataset.bbbId;\n const groupId = bbbRoomViewElement.dataset.groupId;\n return getMeetingInfo(bbbId, groupId, updatecache)\n .then(data => {\n // Just make sure we have the right information for the template.\n data.haspresentations = !!(data.presentations && data.presentations.length);\n return Templates.renderForPromise('mod_bigbluebuttonbn/room_view', data);\n })\n .then(({html, js}) => Templates.replaceNodeContents(bbbRoomViewElement, html, js))\n .then(() => true)\n .catch((ex) => {\n displayException(ex);\n return false;\n });\n};\n"],"names":["timerReference","timerRunning","pollInterval","pollIntervalFactor","resetValues","interval","poll","clearTimeout","updateRoom","then","updateOk","setTimeout","catch","updatecache","bbbRoomViewElement","document","getElementById","bbbId","dataset","groupId","data","haspresentations","presentations","length","Templates","renderForPromise","_ref","html","js","replaceNodeContents","ex"],"mappings":";;;;;;;uLA2BIA,eAAiB,KACjBC,cAAe,EACfC,aAAe,EACfC,mBAAqB,QAGnBC,YAAc,KAChBH,cAAe,EACfD,eAAiB,KACjBE,aAAe,EACfC,mBAAqB,kBAOHE,WAClBD,cACAH,cAAe,EACfC,aAAeG,SACfC,sBAMgB,KACZN,gBACAO,aAAaP,gBAEjBI,qBAMEE,KAAO,KACJL,cAAiBC,cAItBM,aACKC,MAAMC,WACEA,WACDP,mBAAsBA,mBAzCL,GA0CbA,mBAAqB,EA1CR,IA6CrBH,eAAiBW,YAAW,IAAML,QAAQJ,aAAeC,qBAClD,KAEVS,SASIJ,WAAa,eAACK,0EACjBC,mBAAqBC,SAASC,eAAe,iBAC7CC,MAAQH,mBAAmBI,QAAQD,MACnCE,QAAUL,mBAAmBI,QAAQC,eACpC,8BAAeF,MAAOE,QAASN,aACjCJ,MAAKW,OAEFA,KAAKC,oBAAsBD,KAAKE,gBAAiBF,KAAKE,cAAcC,QAC7DC,mBAAUC,iBAAiB,gCAAiCL,SAEtEX,MAAKiB,WAACC,KAACA,KAADC,GAAOA,gBAAQJ,mBAAUK,oBAAoBf,mBAAoBa,KAAMC,OAC7EnB,MAAK,KAAM,IACXG,OAAOkB,iCACaA,KACV"} \ No newline at end of file +{"version":3,"file":"roomupdater.min.js","sources":["../src/roomupdater.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * JS room updater.\n *\n * @module mod_bigbluebuttonbn/roomupdater\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Templates from \"core/templates\";\nimport {exception as displayException} from 'core/notification';\nimport {getMeetingInfo} from './repository';\n\nlet timerReference = null;\nlet timerRunning = false;\nlet pollInterval = 0;\nlet pollIntervalFactor = 1;\nconst MAX_POLL_INTERVAL_FACTOR = 10;\n\nconst resetValues = () => {\n timerRunning = false;\n timerReference = null;\n pollInterval = 0;\n pollIntervalFactor = 1;\n};\n\n/**\n * Start the information poller.\n * @param {Number} interval interval in miliseconds between each poll action.\n */\nexport const start = (interval) => {\n resetValues();\n timerRunning = true;\n pollInterval = interval;\n poll();\n};\n\n/**\n * Stop the room updater.\n */\nexport const stop = () => {\n if (timerReference) {\n clearTimeout(timerReference);\n }\n resetValues();\n};\n\n/**\n * Start the information poller.\n */\nconst poll = () => {\n if (!timerRunning || !pollInterval) {\n // The poller has been stopped.\n return;\n }\n updateRoom()\n .then((updateOk) => {\n if (!updateOk) {\n pollIntervalFactor = (pollIntervalFactor < MAX_POLL_INTERVAL_FACTOR) ?\n pollIntervalFactor + 1 : MAX_POLL_INTERVAL_FACTOR;\n // We make sure if there is an error that we do not try too often.\n }\n timerReference = setTimeout(() => poll(), pollInterval * pollIntervalFactor);\n return true;\n })\n .catch();\n};\n\n/**\n * Update the room information.\n *\n * @param {boolean} [updatecache=false] should we update cache\n * @returns {Promise}\n */\nexport const updateRoom = (updatecache = false) => {\n const bbbRoomViewElement = document.getElementById('bigbluebuttonbn-room-view');\n const bbbId = bbbRoomViewElement.dataset.bbbId;\n const groupId = bbbRoomViewElement.dataset.groupId;\n return getMeetingInfo(bbbId, groupId, updatecache)\n .then(data => {\n // Just make sure we have the right information for the template.\n data.haspresentations = !!(data.presentations && data.presentations.length);\n return Templates.renderForPromise('mod_bigbluebuttonbn/room_view', data);\n })\n .then(({html, js}) => Templates.replaceNode(bbbRoomViewElement, html, js))\n .then(() => true)\n .catch((ex) => {\n displayException(ex);\n return false;\n });\n};\n"],"names":["timerReference","timerRunning","pollInterval","pollIntervalFactor","resetValues","interval","poll","clearTimeout","updateRoom","then","updateOk","setTimeout","catch","updatecache","bbbRoomViewElement","document","getElementById","bbbId","dataset","groupId","data","haspresentations","presentations","length","Templates","renderForPromise","_ref","html","js","replaceNode","ex"],"mappings":";;;;;;;uLA2BIA,eAAiB,KACjBC,cAAe,EACfC,aAAe,EACfC,mBAAqB,QAGnBC,YAAc,KAChBH,cAAe,EACfD,eAAiB,KACjBE,aAAe,EACfC,mBAAqB,kBAOHE,WAClBD,cACAH,cAAe,EACfC,aAAeG,SACfC,sBAMgB,KACZN,gBACAO,aAAaP,gBAEjBI,qBAMEE,KAAO,KACJL,cAAiBC,cAItBM,aACKC,MAAMC,WACEA,WACDP,mBAAsBA,mBAzCL,GA0CbA,mBAAqB,EA1CR,IA6CrBH,eAAiBW,YAAW,IAAML,QAAQJ,aAAeC,qBAClD,KAEVS,SASIJ,WAAa,eAACK,0EACjBC,mBAAqBC,SAASC,eAAe,6BAC7CC,MAAQH,mBAAmBI,QAAQD,MACnCE,QAAUL,mBAAmBI,QAAQC,eACpC,8BAAeF,MAAOE,QAASN,aACjCJ,MAAKW,OAEFA,KAAKC,oBAAsBD,KAAKE,gBAAiBF,KAAKE,cAAcC,QAC7DC,mBAAUC,iBAAiB,gCAAiCL,SAEtEX,MAAKiB,WAACC,KAACA,KAADC,GAAOA,gBAAQJ,mBAAUK,YAAYf,mBAAoBa,KAAMC,OACrEnB,MAAK,KAAM,IACXG,OAAOkB,iCACaA,KACV"} \ No newline at end of file diff --git a/mod/bigbluebuttonbn/amd/src/roomupdater.js b/mod/bigbluebuttonbn/amd/src/roomupdater.js index 4792c8aba90..420f847cee6 100644 --- a/mod/bigbluebuttonbn/amd/src/roomupdater.js +++ b/mod/bigbluebuttonbn/amd/src/roomupdater.js @@ -87,7 +87,7 @@ const poll = () => { * @returns {Promise} */ export const updateRoom = (updatecache = false) => { - const bbbRoomViewElement = document.getElementById('bbb-room-view'); + const bbbRoomViewElement = document.getElementById('bigbluebuttonbn-room-view'); const bbbId = bbbRoomViewElement.dataset.bbbId; const groupId = bbbRoomViewElement.dataset.groupId; return getMeetingInfo(bbbId, groupId, updatecache) @@ -96,7 +96,7 @@ export const updateRoom = (updatecache = false) => { data.haspresentations = !!(data.presentations && data.presentations.length); return Templates.renderForPromise('mod_bigbluebuttonbn/room_view', data); }) - .then(({html, js}) => Templates.replaceNodeContents(bbbRoomViewElement, html, js)) + .then(({html, js}) => Templates.replaceNode(bbbRoomViewElement, html, js)) .then(() => true) .catch((ex) => { displayException(ex); diff --git a/mod/bigbluebuttonbn/classes/external/meeting_info.php b/mod/bigbluebuttonbn/classes/external/meeting_info.php index e486ac27b8d..0848f8eaf90 100644 --- a/mod/bigbluebuttonbn/classes/external/meeting_info.php +++ b/mod/bigbluebuttonbn/classes/external/meeting_info.php @@ -117,6 +117,7 @@ class meeting_info extends external_api { 'cmid' => new external_value(PARAM_INT, 'CM id'), 'userlimit' => new external_value(PARAM_INT, 'User limit'), 'bigbluebuttonbnid' => new external_value(PARAM_RAW, 'bigbluebuttonbn instance id'), + 'groupid' => new external_value(PARAM_INT, 'bigbluebuttonbn group id', VALUE_DEFAULT, 0), 'meetingid' => new external_value(PARAM_RAW, 'Meeting id'), 'openingtime' => new external_value(PARAM_INT, 'Opening time', VALUE_OPTIONAL), 'closingtime' => new external_value(PARAM_INT, 'Closing time', VALUE_OPTIONAL), diff --git a/mod/bigbluebuttonbn/lang/en/bigbluebuttonbn.php b/mod/bigbluebuttonbn/lang/en/bigbluebuttonbn.php index 94b1cce0044..eca3fed18e9 100644 --- a/mod/bigbluebuttonbn/lang/en/bigbluebuttonbn.php +++ b/mod/bigbluebuttonbn/lang/en/bigbluebuttonbn.php @@ -443,18 +443,18 @@ $string['view_message_notavailableyet'] = 'This session is not yet available.'; $string['view_recording_select_course'] = 'Select a course first in the drop down menu'; -$string['view_message_session_started_at'] = 'This session started at'; +$string['view_message_session_started_at'] = 'Session started at'; $string['view_message_session_running_for'] = 'This session has been running for'; $string['view_message_hour'] = 'hour'; $string['view_message_hours'] = 'hours'; $string['view_message_minute'] = 'minute'; $string['view_message_minutes'] = 'minutes'; -$string['view_message_moderator'] = 'moderator'; -$string['view_message_moderators'] = 'moderators'; -$string['view_message_viewer'] = 'viewer'; -$string['view_message_viewers'] = 'viewers'; -$string['view_message_user'] = 'user'; -$string['view_message_users'] = 'users'; +$string['view_message_moderator'] = 'Moderator'; +$string['view_message_moderators'] = 'Moderators'; +$string['view_message_viewer'] = 'Viewer'; +$string['view_message_viewers'] = 'Viewers'; +$string['view_message_user'] = 'User'; +$string['view_message_users'] = 'Users'; $string['view_message_has_joined'] = 'has joined'; $string['view_message_have_joined'] = 'have joined'; $string['view_message_session_no_users'] = 'There are no users in this session'; diff --git a/mod/bigbluebuttonbn/templates/end_session_button.mustache b/mod/bigbluebuttonbn/templates/end_session_button.mustache index 9e9ae452d42..dbab4077951 100644 --- a/mod/bigbluebuttonbn/templates/end_session_button.mustache +++ b/mod/bigbluebuttonbn/templates/end_session_button.mustache @@ -34,7 +34,7 @@ }} data-action="end"{{! }} data-bbb-id="{{bigbluebuttonbnid}}"{{! }} data-group-id="{{groupid}}"{{! - }} class="btn btn-secondary bbb-btn-action"{{! + }} class="btn btn-outline-dark bbb-btn-action m-1"{{! }}> {{#str}}view_conference_action_end, mod_bigbluebuttonbn{{/str}} diff --git a/mod/bigbluebuttonbn/templates/room_view.mustache b/mod/bigbluebuttonbn/templates/room_view.mustache index a6465fdcf4a..c81cfd0f913 100644 --- a/mod/bigbluebuttonbn/templates/room_view.mustache +++ b/mod/bigbluebuttonbn/templates/room_view.mustache @@ -21,6 +21,8 @@ Example context (json): { + "bigbluebuttonbnid": 1, + "groupid": 0, "statusclosed": true, "statusclosed": false, "openingtime": 123456789, @@ -28,71 +30,83 @@ } }} -
- - {{statusmessage}} - - {{#openingtime}} - - {{#str}}mod_form_field_openingtime, bigbluebuttonbn{{/str}}: - {{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}} - - {{/openingtime}} - {{#closingtime}} - - {{#str}}mod_form_field_closingtime, bigbluebuttonbn{{/str}}: - {{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}} - - {{/closingtime}} - - {{#statusrunning}} -
- {{#str}}view_message_session_started_at, mod_bigbluebuttonbn{{/str}} - {{#userdate}} {{startedat}}, {{#str}} strftimetime, core_langconfig{{/str}} {{/userdate}} - - {{#moderatorplural}}{{#str}}view_message_moderators, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}} - {{^moderatorplural}}{{#str}}view_message_moderator, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}} - {{moderatorcount}} - - - {{#viewerplural}}{{#str}}view_message_viewers, mod_bigbluebuttonbn{{/str}}{{/viewerplural}} - {{^viewerplural}}{{#str}}view_message_viewer, mod_bigbluebuttonbn{{/str}}{{/viewerplural}} - {{participantcount}}. - -
- {{/statusrunning}} -
- -
- {{#haspresentations}} -

{{#str}}view_section_title_presentation, mod_bigbluebuttonbn{{/str}}

-
- {{#presentations}} - - {{#pix}}{{iconname}},core, {{icondesc}}{{/pix}} - {{name}} - - {{/presentations}} +
+
+ {{#statusrunning}} +
+ {{#str}}view_message_session_started_at, mod_bigbluebuttonbn{{/str}}: + {{#userdate}} {{startedat}}, {{#str}} strftimetime, core_langconfig{{/str}} {{/userdate}}. + {{statusmessage}} +
+ {{/statusrunning}} + {{^statusrunning}} +
{{statusmessage}}
+ {{/statusrunning}} +
+ {{#openingtime}} + + {{#str}}mod_form_field_openingtime, bigbluebuttonbn{{/str}}: + {{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}} + + {{/openingtime}} + {{#closingtime}} +
+ {{#str}}mod_form_field_closingtime, bigbluebuttonbn{{/str}}: + {{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}} +
+ {{/closingtime}}
- {{/haspresentations}} + {{#statusrunning}} +
+ + {{#moderatorplural}}{{#str}}view_message_moderators, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}} + {{^moderatorplural}}{{#str}}view_message_moderator, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}}: + + {{moderatorcount}} +
+
+ + {{#viewerplural}}{{#str}}view_message_viewers, mod_bigbluebuttonbn{{/str}}{{/viewerplural}} + {{^viewerplural}}{{#str}}view_message_viewer, mod_bigbluebuttonbn{{/str}}{{/viewerplural}}: + + {{participantcount}} +
+ {{/statusrunning}} +
+ +
+ {{#haspresentations}} +
{{#str}}view_section_title_presentation, mod_bigbluebuttonbn{{/str}}
+
+ {{#presentations}} + + {{#pix}}{{iconname}},core, {{icondesc}}{{/pix}} + {{name}} + + {{/presentations}} +
+ {{/haspresentations}} +
-
-
+
+
+ {{#ismoderator}} + {{> mod_bigbluebuttonbn/end_session_button}} + {{/ismoderator}} + {{#canjoin}} {{#str}}view_conference_action_join, mod_bigbluebuttonbn{{/str}} {{/canjoin}} - - {{#ismoderator}} - {{> mod_bigbluebuttonbn/end_session_button}} - {{/ismoderator}}