first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
define("mod_bigbluebuttonbn/actions",["./repository","core/notification","./events","core/str"],(function(_repository,_notification,_events,_str){let listening=!1;listening||((()=>{document.addEventListener("click",(e=>{const actionButton=e.target.closest('.bbb-btn-action[data-action="end"]');if(!actionButton)return;e.preventDefault();const bbbId=actionButton.dataset.bbbId,groupId=actionButton.dataset.groupId?actionButton.dataset.groupId:0;var title,question,saveLabel;(title=(0,_str.getString)("end_session_confirm_title","mod_bigbluebuttonbn"),question=(0,_str.getString)("end_session_confirm","mod_bigbluebuttonbn"),saveLabel=(0,_str.getString)("yes","moodle"),new Promise((resolve=>{(0,_notification.saveCancel)(title,question,saveLabel,resolve)}))).then((()=>(0,_repository.endMeeting)(bbbId,groupId))).then((()=>{(0,_events.notifySessionEnded)(bbbId,groupId)})).catch(_notification.exception)}))})(),listening=!0)}));
//# sourceMappingURL=actions.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"actions.min.js","sources":["../src/actions.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 <http://www.gnu.org/licenses/>.\n/**\n * JS actions.\n *\n * @module mod_bigbluebuttonbn/actions\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {endMeeting as requestEndMeeting} from './repository';\nimport {\n exception as displayException,\n saveCancel,\n} from 'core/notification';\nimport {notifySessionEnded} from './events';\nimport {getString} from 'core/str';\n\nconst confirmedPromise = (title, question, saveLabel) => new Promise(resolve => {\n saveCancel(title, question, saveLabel, resolve);\n});\n\nconst registerEventListeners = () => {\n document.addEventListener('click', e => {\n const actionButton = e.target.closest('.bbb-btn-action[data-action=\"end\"]');\n if (!actionButton) {\n return;\n }\n\n e.preventDefault();\n\n const bbbId = actionButton.dataset.bbbId;\n const groupId = actionButton.dataset.groupId ? actionButton.dataset.groupId : 0;\n\n confirmedPromise(\n getString('end_session_confirm_title', 'mod_bigbluebuttonbn'),\n getString('end_session_confirm', 'mod_bigbluebuttonbn'),\n getString('yes', 'moodle')\n )\n .then(() => requestEndMeeting(bbbId, groupId))\n .then(() => {\n notifySessionEnded(bbbId, groupId);\n\n return;\n })\n .catch(displayException);\n });\n};\n\nlet listening = false;\nif (!listening) {\n registerEventListeners();\n listening = true;\n}\n"],"names":["listening","document","addEventListener","e","actionButton","target","closest","preventDefault","bbbId","dataset","groupId","title","question","saveLabel","Promise","resolve","then","catch","displayException","registerEventListeners"],"mappings":"sJA6DIA,WAAY,EACXA,YA5B0B,MAC3BC,SAASC,iBAAiB,SAASC,UACzBC,aAAeD,EAAEE,OAAOC,QAAQ,0CACjCF,oBAILD,EAAEI,uBAEIC,MAAQJ,aAAaK,QAAQD,MAC7BE,QAAUN,aAAaK,QAAQC,QAAUN,aAAaK,QAAQC,QAAU,EAd7D,IAACC,MAAOC,SAAUC,WAAjBF,OAiBd,kBAAU,4BAA6B,uBAjBlBC,UAkBrB,kBAAU,sBAAuB,uBAlBFC,WAmB/B,kBAAU,MAAO,UAnB4B,IAAIC,SAAQC,uCACtDJ,MAAOC,SAAUC,UAAWE,aAoBlCC,MAAK,KAAM,0BAAkBR,MAAOE,WACpCM,MAAK,oCACiBR,MAAOE,YAI7BO,MAAMC,6BAMXC,GACAnB,WAAY"}
+11
View File
@@ -0,0 +1,11 @@
define("mod_bigbluebuttonbn/events",["exports","core/event_dispatcher"],(function(_exports,_event_dispatcher){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.notifySessionEnded=_exports.notifyCurrentSessionEnded=_exports.eventTypes=void 0;
/**
* Events for the mod_bigbluebuttonbn plugin.
*
* @module mod_bigbluebuttonbn/events
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
const eventTypes={sessionEnded:"mod_bigbluebuttonbn/sessionEnded",currentSessionEnded:"mod_bigbluebuttonbn/currentSessionEnded"};_exports.eventTypes=eventTypes;_exports.notifySessionEnded=(bbbId,groupId)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.sessionEnded,{bbbId:bbbId,groupId:groupId});_exports.notifyCurrentSessionEnded=container=>(0,_event_dispatcher.dispatchEvent)(eventTypes.currentSessionEnded,{},container)}));
//# sourceMappingURL=events.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events.min.js","sources":["../src/events.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Events for the mod_bigbluebuttonbn plugin.\n *\n * @module mod_bigbluebuttonbn/events\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {dispatchEvent} from 'core/event_dispatcher';\n\nexport const eventTypes = {\n /**\n * Fired when a session has been ended.\n *\n * @event mod_bigbluebuttonbn/sessionEnded\n * @type CustomEvent\n * @property {object} detail\n * @property {number} detail.bbbId\n * @property {number} detail.groupId\n */\n sessionEnded: 'mod_bigbluebuttonbn/sessionEnded',\n\n /**\n * Fired when the current session has been ended.\n *\n * @event mod_bigbluebuttonbn/currentSessionEnded\n * @type CustomEvent\n * @property {object} detail\n */\n currentSessionEnded: 'mod_bigbluebuttonbn/currentSessionEnded',\n};\n\n/**\n * Trigger the sessionEnded event.\n *\n * @param {number} bbbId\n * @param {number} groupId\n * @returns {CustomEvent}\n * @fires event:mod_bigbluebuttonbn/sessionEnded\n */\nexport const notifySessionEnded = (bbbId, groupId) => dispatchEvent(eventTypes.sessionEnded, {\n bbbId,\n groupId,\n});\n\n/**\n * Trigger the currentSessionEnded event.\n *\n * @param {Element} container\n * @returns {CustomEvent}\n * @fires event:mod_bigbluebuttonbn/currentSessionEnded\n */\nexport const notifyCurrentSessionEnded = container => dispatchEvent(\n eventTypes.currentSessionEnded,\n {},\n container\n);\n"],"names":["eventTypes","sessionEnded","currentSessionEnded","bbbId","groupId","container"],"mappings":";;;;;;;;MAyBaA,WAAa,CAUtBC,aAAc,mCASdC,oBAAqB,sGAWS,CAACC,MAAOC,WAAY,mCAAcJ,WAAWC,aAAc,CACzFE,MAAAA,MACAC,QAAAA,6CAUqCC,YAAa,mCAClDL,WAAWE,oBACX,GACAG"}
+10
View File
@@ -0,0 +1,10 @@
define("mod_bigbluebuttonbn/guest_access_modal",["exports","core/str","core_form/modalform","core/toast","core/notification"],(function(_exports,_str,_modalform,_toast,_notification){var obj;
/**
* Javascript module for importing presets.
*
* @module mod_bigbluebuttonbn/guest_access_modal
* @copyright 2022 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modalform=(obj=_modalform)&&obj.__esModule?obj:{default:obj};const selectors_showGuestAccessButton='[data-action="show-guest-access"]';_exports.init=guestInfo=>{const showGuestAccessButton=document.querySelector(selectors_showGuestAccessButton);if(null===showGuestAccessButton)return;const modalForm=new _modalform.default({modalConfig:{title:(0,_str.getString)("guestaccess_title","mod_bigbluebuttonbn"),large:!0},args:guestInfo,saveButtonText:(0,_str.getString)("ok","core_moodle"),formClass:"mod_bigbluebuttonbn\\form\\guest_add"});showGuestAccessButton.addEventListener("click",(event=>{modalForm.show().then((()=>((0,_toast.addToastRegion)(modalForm.modal.getRoot()[0]),!0))).catch(_notification.exception),modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(e=>{modalForm.modal.getRoot()[0].querySelectorAll(".toast-wrapper").forEach((reg=>reg.remove())),e.detail.result?e.detail.emailcount>0&&(0,_toast.add)((0,_str.getString)("guestaccess_invite_success","mod_bigbluebuttonbn",e.detail),{type:"success"}):(0,_toast.add)((0,_str.getString)("guestaccess_invite_failure","mod_bigbluebuttonbn",e.detail),{type:"warning"})}),{once:!0}),event.stopPropagation()}))}}));
//# sourceMappingURL=guest_access_modal.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"guest_access_modal.min.js","sources":["../src/guest_access_modal.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript module for importing presets.\n *\n * @module mod_bigbluebuttonbn/guest_access_modal\n * @copyright 2022 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {getString} from 'core/str';\nimport ModalForm from 'core_form/modalform';\nimport {add as toastAdd, addToastRegion} from 'core/toast';\nimport {\n exception as displayException,\n} from 'core/notification';\nconst selectors = {\n showGuestAccessButton: '[data-action=\"show-guest-access\"]',\n};\n\n/**\n * Intialise the object and click event to show the popup form\n *\n * @param {object} guestInfo\n * @param {string} guestInfo.id\n * @param {string} guestInfo.groupid\n * @param {string} guestInfo.guestjoinurl\n * @param {string} guestInfo.guestpassword\n */\nexport const init = (guestInfo) => {\n const showGuestAccessButton = document.querySelector(selectors.showGuestAccessButton);\n if (showGuestAccessButton === null) {\n return;\n }\n\n const modalForm = new ModalForm({\n modalConfig: {\n title: getString('guestaccess_title', 'mod_bigbluebuttonbn'),\n large: true,\n },\n args: guestInfo,\n saveButtonText: getString('ok', 'core_moodle'),\n formClass: 'mod_bigbluebuttonbn\\\\form\\\\guest_add',\n });\n showGuestAccessButton.addEventListener('click', event => {\n modalForm.show().then(() => {\n addToastRegion(modalForm.modal.getRoot()[0]);\n return true;\n }).catch(displayException);\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (e) => {\n // Remove toast region as if not it will be displayed on the closed modal.\n const modalElement = modalForm.modal.getRoot()[0];\n const regions = modalElement.querySelectorAll('.toast-wrapper');\n regions.forEach((reg) => reg.remove());\n if (e.detail.result) {\n if (e.detail.emailcount > 0) {\n toastAdd(getString('guestaccess_invite_success', 'mod_bigbluebuttonbn', e.detail),\n {\n type: 'success',\n }\n );\n }\n } else {\n toastAdd(getString('guestaccess_invite_failure', 'mod_bigbluebuttonbn', e.detail),\n {\n type: 'warning',\n }\n );\n }\n }, {once: true});\n event.stopPropagation();\n });\n};\n"],"names":["selectors","guestInfo","showGuestAccessButton","document","querySelector","modalForm","ModalForm","modalConfig","title","large","args","saveButtonText","formClass","addEventListener","event","show","then","modal","getRoot","catch","displayException","events","FORM_SUBMITTED","e","querySelectorAll","forEach","reg","remove","detail","result","emailcount","type","once","stopPropagation"],"mappings":";;;;;;;sJA4BMA,gCACqB,kDAYNC,kBACXC,sBAAwBC,SAASC,cAAcJ,oCACvB,OAA1BE,mCAIEG,UAAY,IAAIC,mBAAU,CAC5BC,YAAa,CACTC,OAAO,kBAAU,oBAAqB,uBACtCC,OAAO,GAEXC,KAAMT,UACNU,gBAAgB,kBAAU,KAAM,eAChCC,UAAW,yCAEfV,sBAAsBW,iBAAiB,SAASC,QAC5CT,UAAUU,OAAOC,MAAK,+BACHX,UAAUY,MAAMC,UAAU,KAClC,KACRC,MAAMC,yBACTf,UAAUQ,iBAAiBR,UAAUgB,OAAOC,gBAAiBC,IAEpClB,UAAUY,MAAMC,UAAU,GAClBM,iBAAiB,kBACtCC,SAASC,KAAQA,IAAIC,WACzBJ,EAAEK,OAAOC,OACLN,EAAEK,OAAOE,WAAa,mBACb,kBAAU,6BAA8B,sBAAuBP,EAAEK,QACtE,CACIG,KAAM,4BAKT,kBAAU,6BAA8B,sBAAuBR,EAAEK,QACtE,CACIG,KAAM,cAInB,CAACC,MAAM,IACVlB,MAAMmB"}
+3
View File
@@ -0,0 +1,3 @@
define("mod_bigbluebuttonbn/index",["exports","./actions","./events"],(function(_exports,_actions,_events){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;_exports.init=()=>{document.addEventListener(_events.eventTypes.sessionEnded,(()=>{window.location.reload()}))}}));
//# sourceMappingURL=index.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.min.js","sources":["../src/index.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Index page for the mod_bigbluebuttonbn plugin.\n *\n * @module mod_bigbluebuttonbn/index\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport './actions';\nimport {eventTypes} from './events';\n\nexport const init = () => {\n document.addEventListener(eventTypes.sessionEnded, () => {\n window.location.reload();\n });\n};\n"],"names":["document","addEventListener","eventTypes","sessionEnded","window","location","reload"],"mappings":"sMA0BoB,KAChBA,SAASC,iBAAiBC,mBAAWC,cAAc,KAC/CC,OAAOC,SAASC"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
define("mod_bigbluebuttonbn/repository",["exports","core/ajax"],(function(_exports,_ajax){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.updateRecording=_exports.getMeetingInfo=_exports.fetchRecordingsToImport=_exports.fetchRecordings=_exports.endMeeting=_exports.completionValidate=void 0;_exports.fetchRecordings=(bigbluebuttonbnid,tools,groupid)=>{const args={bigbluebuttonbnid:bigbluebuttonbnid,tools:tools};return groupid&&(args.groupid=groupid),(0,_ajax.call)([{methodname:"mod_bigbluebuttonbn_get_recordings",args:args}])[0]};_exports.fetchRecordingsToImport=(destinationinstanceid,sourcebigbluebuttonbnid,sourcecourseid,tools,groupid)=>{const args={destinationinstanceid:destinationinstanceid,sourcebigbluebuttonbnid:sourcebigbluebuttonbnid,sourcecourseid:sourcecourseid,tools:tools};return groupid&&(args.groupid=groupid),(0,_ajax.call)([{methodname:"mod_bigbluebuttonbn_get_recordings_to_import",args:args}])[0]};_exports.updateRecording=args=>(0,_ajax.call)([{methodname:"mod_bigbluebuttonbn_update_recording",args:args}])[0];_exports.endMeeting=(bigbluebuttonbnid,groupid)=>(0,_ajax.call)([{methodname:"mod_bigbluebuttonbn_end_meeting",args:{bigbluebuttonbnid:bigbluebuttonbnid,groupid:groupid}}])[0];_exports.completionValidate=bigbluebuttonbnid=>(0,_ajax.call)([{methodname:"mod_bigbluebuttonbn_completion_validate",args:{bigbluebuttonbnid:bigbluebuttonbnid}}])[0];_exports.getMeetingInfo=function(bigbluebuttonbnid,groupid){let updatecache=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return(0,_ajax.call)([{methodname:"mod_bigbluebuttonbn_meeting_info",args:{bigbluebuttonbnid:bigbluebuttonbnid,groupid:groupid,updatecache:updatecache}}])[0]}}));
//# sourceMappingURL=repository.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"repository.min.js","sources":["../src/repository.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Repository to perform WS calls for mod_bigbluebuttonbn.\n *\n * @module mod_bigbluebuttonbn/repository\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\n\n/**\n * Fetch the list of recordings from the server.\n *\n * @param {Number} bigbluebuttonbnid The instance ID\n * @param {String} tools the set of tools to display\n * @param {number} groupid\n * @returns {Promise}\n */\nexport const fetchRecordings = (bigbluebuttonbnid, tools, groupid) => {\n const args = {\n bigbluebuttonbnid,\n tools,\n };\n\n if (groupid) {\n args.groupid = groupid;\n }\n\n return fetchMany([{methodname: 'mod_bigbluebuttonbn_get_recordings', args}])[0];\n};\n\n/**\n * Fetch the list of recordings from the server that can be imported.\n *\n * @param {Number} destinationinstanceid The destination instance ID\n * @param {Number} sourcebigbluebuttonbnid The original instance ID\n * @param {Number} sourcecourseid The destination instance ID\n * @param {String} tools the set of tools to display\n * @param {number} groupid\n * @returns {Promise}\n */\nexport const fetchRecordingsToImport = (\n destinationinstanceid,\n sourcebigbluebuttonbnid,\n sourcecourseid,\n tools,\n groupid\n) => {\n const args = {\n destinationinstanceid,\n sourcebigbluebuttonbnid,\n sourcecourseid,\n tools,\n };\n\n if (groupid) {\n args.groupid = groupid;\n }\n\n return fetchMany([{methodname: 'mod_bigbluebuttonbn_get_recordings_to_import', args}])[0];\n};\n\n/**\n * Perform an update on a single recording.\n *\n * @param {object} args The instance ID\n * @returns {Promise}\n */\nexport const updateRecording = args => fetchMany([\n {\n methodname: 'mod_bigbluebuttonbn_update_recording',\n args,\n }\n])[0];\n\n/**\n * End the Meeting\n *\n * @param {number} bigbluebuttonbnid\n * @param {number} groupid\n * @returns {Promise}\n */\nexport const endMeeting = (bigbluebuttonbnid, groupid) => fetchMany([\n {\n methodname: 'mod_bigbluebuttonbn_end_meeting',\n args: {\n bigbluebuttonbnid,\n groupid\n },\n }\n])[0];\n\n/**\n * Validate completion.\n *\n * @param {number} bigbluebuttonbnid\n * @returns {Promise}\n */\nexport const completionValidate = (bigbluebuttonbnid) => fetchMany([\n {\n methodname: 'mod_bigbluebuttonbn_completion_validate',\n args: {\n bigbluebuttonbnid\n },\n }\n])[0];\n\n\n/**\n * Fetch meeting info for the specified meeting.\n *\n * @param {number} bigbluebuttonbnid\n * @param {number} groupid\n * @param {boolean} [updatecache=false]\n * @returns {Promise}\n */\nexport const getMeetingInfo = (bigbluebuttonbnid, groupid, updatecache = false) => fetchMany([\n {\n methodname: 'mod_bigbluebuttonbn_meeting_info',\n args: {\n bigbluebuttonbnid,\n groupid,\n updatecache,\n },\n }\n])[0];\n"],"names":["bigbluebuttonbnid","tools","groupid","args","methodname","destinationinstanceid","sourcebigbluebuttonbnid","sourcecourseid","updatecache"],"mappings":"6UAiC+B,CAACA,kBAAmBC,MAAOC,iBAChDC,KAAO,CACTH,kBAAAA,kBACAC,MAAAA,cAGAC,UACAC,KAAKD,QAAUA,UAGZ,cAAU,CAAC,CAACE,WAAY,qCAAsCD,KAAAA,QAAQ,qCAa1C,CACnCE,sBACAC,wBACAC,eACAN,MACAC,iBAEMC,KAAO,CACTE,sBAAAA,sBACAC,wBAAAA,wBACAC,eAAAA,eACAN,MAAAA,cAGAC,UACAC,KAAKD,QAAUA,UAGZ,cAAU,CAAC,CAACE,WAAY,+CAAgDD,KAAAA,QAAQ,6BAS5DA,OAAQ,cAAU,CAC7C,CACIC,WAAY,uCACZD,KAAAA,QAEL,uBASuB,CAACH,kBAAmBE,WAAY,cAAU,CAChE,CACIE,WAAY,kCACZD,KAAM,CACFH,kBAAAA,kBACAE,QAAAA,YAGT,+BAQgCF,oBAAsB,cAAU,CAC/D,CACII,WAAY,0CACZD,KAAM,CACFH,kBAAAA,sBAGT,2BAW2B,SAACA,kBAAmBE,aAASM,2EAAwB,cAAU,CACzF,CACIJ,WAAY,mCACZD,KAAM,CACFH,kBAAAA,kBACAE,QAAAA,QACAM,YAAAA,gBAGT"}
+10
View File
@@ -0,0 +1,10 @@
define("mod_bigbluebuttonbn/rooms",["exports","./actions","./repository","./roomupdater","core/notification","core/pending","core/str","core/toast","./events"],(function(_exports,_actions,repository,roomUpdater,_notification,_pending,_str,_toast,_events){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}
/**
* JS actions for the rooms page for mod_bigbluebuttonbn.
*
* @module mod_bigbluebuttonbn/rooms
* @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.setupWindowAutoClose=_exports.init=void 0,repository=_interopRequireWildcard(repository),roomUpdater=_interopRequireWildcard(roomUpdater),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};_exports.init=(bigbluebuttonbnid,pollInterval)=>{const completionElement=document.querySelector("a[href*=completion_validate]");completionElement&&completionElement.addEventListener("click",(event=>{event.preventDefault();const pendingPromise=new _pending.default("mod_bigbluebuttonbn/completion:validate");repository.completionValidate(bigbluebuttonbnid).then((()=>(0,_str.getString)("completionvalidatestatetriggered","mod_bigbluebuttonbn"))).then((str=>(0,_toast.add)(str))).then((()=>pendingPromise.resolve())).catch(_notification.exception)})),document.addEventListener("click",(e=>{const joinButton=e.target.closest('[data-action="join"]');joinButton&&(window.open(joinButton.href,"bigbluebutton_conference"),e.preventDefault(),setTimeout((()=>{roomUpdater.updateRoom(!0)}),pollInterval))})),document.addEventListener(_events.eventTypes.sessionEnded,(()=>{roomUpdater.stop(),roomUpdater.updateRoom(),(0,_notification.fetchNotifications)()})),window.addEventListener(_events.eventTypes.currentSessionEnded,(()=>{roomUpdater.stop(),roomUpdater.updateRoom(),(0,_notification.fetchNotifications)()})),roomUpdater.start(pollInterval)};_exports.setupWindowAutoClose=function(){let closeDelay=arguments.length>0&&void 0!==arguments[0]?arguments[0]:2e3;(0,_events.notifyCurrentSessionEnded)(window.opener),window.addEventListener("onbeforeunload",(()=>{window.opener.setTimeout((()=>{roomUpdater.updateRoom(!0)}),closeDelay)}),{once:!0}),window.close()}}));
//# sourceMappingURL=rooms.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"rooms.min.js","sources":["../src/rooms.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 <http://www.gnu.org/licenses/>.\n\n/**\n * JS actions for the rooms page for mod_bigbluebuttonbn.\n *\n * @module mod_bigbluebuttonbn/rooms\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport './actions';\nimport * as repository from './repository';\nimport * as roomUpdater from './roomupdater';\nimport {\n exception as displayException,\n fetchNotifications,\n} from 'core/notification';\nimport Pending from 'core/pending';\nimport {getString} from 'core/str';\nimport {add as addToast} from 'core/toast';\nimport {eventTypes, notifyCurrentSessionEnded} from './events';\n\n/**\n * Init the room\n *\n * @param {Number} bigbluebuttonbnid bigblubeutton identifier\n * @param {Number} pollInterval poll interval in miliseconds\n */\nexport const init = (bigbluebuttonbnid, pollInterval) => {\n const completionElement = document.querySelector('a[href*=completion_validate]');\n if (completionElement) {\n completionElement.addEventListener(\"click\", event => {\n event.preventDefault();\n\n const pendingPromise = new Pending('mod_bigbluebuttonbn/completion:validate');\n\n repository.completionValidate(bigbluebuttonbnid)\n .then(() => getString('completionvalidatestatetriggered', 'mod_bigbluebuttonbn'))\n .then(str => addToast(str))\n .then(() => pendingPromise.resolve())\n .catch(displayException);\n });\n }\n\n document.addEventListener('click', e => {\n const joinButton = e.target.closest('[data-action=\"join\"]');\n if (joinButton) {\n window.open(joinButton.href, 'bigbluebutton_conference');\n e.preventDefault();\n // Gives the user a bit of time to go into the meeting before polling the room.\n setTimeout(() => {\n roomUpdater.updateRoom(true);\n }, pollInterval);\n }\n });\n\n document.addEventListener(eventTypes.sessionEnded, () => {\n roomUpdater.stop();\n roomUpdater.updateRoom();\n fetchNotifications();\n });\n\n window.addEventListener(eventTypes.currentSessionEnded, () => {\n roomUpdater.stop();\n roomUpdater.updateRoom();\n fetchNotifications();\n });\n // Room update.\n roomUpdater.start(pollInterval);\n};\n\n/**\n * Auto close child windows when clicking the End meeting button.\n * @param {Number} closeDelay time to wait in miliseconds before closing the window\n */\nexport const setupWindowAutoClose = (closeDelay = 2000) => {\n notifyCurrentSessionEnded(window.opener);\n window.addEventListener('onbeforeunload', () => {\n window.opener.setTimeout(() => {\n roomUpdater.updateRoom(true);\n }, closeDelay);\n },\n {\n once: true\n });\n window.close(); // This does not work as scripts can only close windows that are opened by themselves.\n};\n"],"names":["bigbluebuttonbnid","pollInterval","completionElement","document","querySelector","addEventListener","event","preventDefault","pendingPromise","Pending","repository","completionValidate","then","str","resolve","catch","displayException","e","joinButton","target","closest","window","open","href","setTimeout","roomUpdater","updateRoom","eventTypes","sessionEnded","stop","currentSessionEnded","start","closeDelay","opener","once","close"],"mappings":";;;;;;;wRAyCoB,CAACA,kBAAmBC,sBAC9BC,kBAAoBC,SAASC,cAAc,gCAC7CF,mBACAA,kBAAkBG,iBAAiB,SAASC,QACxCA,MAAMC,uBAEAC,eAAiB,IAAIC,iBAAQ,2CAEnCC,WAAWC,mBAAmBX,mBACzBY,MAAK,KAAM,kBAAU,mCAAoC,yBACzDA,MAAKC,MAAO,cAASA,OACrBD,MAAK,IAAMJ,eAAeM,YAC1BC,MAAMC,4BAInBb,SAASE,iBAAiB,SAASY,UACzBC,WAAaD,EAAEE,OAAOC,QAAQ,wBAChCF,aACAG,OAAOC,KAAKJ,WAAWK,KAAM,4BAC7BN,EAAEV,iBAEFiB,YAAW,KACPC,YAAYC,YAAW,KACxBzB,kBAIXE,SAASE,iBAAiBsB,mBAAWC,cAAc,KAC/CH,YAAYI,OACZJ,YAAYC,uDAIhBL,OAAOhB,iBAAiBsB,mBAAWG,qBAAqB,KACpDL,YAAYI,OACZJ,YAAYC,uDAIhBD,YAAYM,MAAM9B,6CAOc,eAAC+B,kEAAa,0CACpBX,OAAOY,QACjCZ,OAAOhB,iBAAiB,kBAAkB,KAClCgB,OAAOY,OAAOT,YAAW,KACrBC,YAAYC,YAAW,KACxBM,cAEP,CACIE,MAAM,IAEdb,OAAOc"}
+10
View File
@@ -0,0 +1,10 @@
define("mod_bigbluebuttonbn/roomupdater",["exports","core/pending","core/templates","core/notification","./repository"],(function(_exports,_pending,_templates,_notification,_repository){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* JS room updater.
*
* @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,_pending=_interopRequireDefault(_pending),_templates=_interopRequireDefault(_templates);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");if(null===bbbRoomViewElement)return Promise.resolve(!1);const bbbId=bbbRoomViewElement.dataset.bbbId,groupId=bbbRoomViewElement.dataset.groupId,pendingPromise=new _pending.default("mod_bigbluebuttonbn/roomupdater:updateRoom");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((()=>pendingPromise.resolve())).catch(_notification.exception)};_exports.updateRoom=updateRoom}));
//# sourceMappingURL=roomupdater.min.js.map
@@ -0,0 +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 <http://www.gnu.org/licenses/>.\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 Pending from 'core/pending';\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 if (bbbRoomViewElement === null) {\n return Promise.resolve(false);\n }\n\n const bbbId = bbbRoomViewElement.dataset.bbbId;\n const groupId = bbbRoomViewElement.dataset.groupId;\n\n const pendingPromise = new Pending('mod_bigbluebuttonbn/roomupdater:updateRoom');\n\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(() => pendingPromise.resolve())\n .catch(displayException);\n};\n"],"names":["timerReference","timerRunning","pollInterval","pollIntervalFactor","resetValues","interval","poll","clearTimeout","updateRoom","then","updateOk","setTimeout","catch","updatecache","bbbRoomViewElement","document","getElementById","Promise","resolve","bbbId","dataset","groupId","pendingPromise","Pending","data","haspresentations","presentations","length","Templates","renderForPromise","_ref","html","js","replaceNode","displayException"],"mappings":";;;;;;;iNA4BIA,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,gCACxB,OAAvBF,0BACOG,QAAQC,SAAQ,SAGrBC,MAAQL,mBAAmBM,QAAQD,MACnCE,QAAUP,mBAAmBM,QAAQC,QAErCC,eAAiB,IAAIC,iBAAQ,qDAE5B,8BAAeJ,MAAOE,QAASR,aACjCJ,MAAKe,OAEFA,KAAKC,oBAAsBD,KAAKE,gBAAiBF,KAAKE,cAAcC,QAC7DC,mBAAUC,iBAAiB,gCAAiCL,SAEtEf,MAAKqB,WAACC,KAACA,KAADC,GAAOA,gBAAQJ,mBAAUK,YAAYnB,mBAAoBiB,KAAMC,OACrEvB,MAAK,IAAMa,eAAeJ,YAC1BN,MAAMsB"}
+66
View File
@@ -0,0 +1,66 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* JS actions.
*
* @module mod_bigbluebuttonbn/actions
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {endMeeting as requestEndMeeting} from './repository';
import {
exception as displayException,
saveCancel,
} from 'core/notification';
import {notifySessionEnded} from './events';
import {getString} from 'core/str';
const confirmedPromise = (title, question, saveLabel) => new Promise(resolve => {
saveCancel(title, question, saveLabel, resolve);
});
const registerEventListeners = () => {
document.addEventListener('click', e => {
const actionButton = e.target.closest('.bbb-btn-action[data-action="end"]');
if (!actionButton) {
return;
}
e.preventDefault();
const bbbId = actionButton.dataset.bbbId;
const groupId = actionButton.dataset.groupId ? actionButton.dataset.groupId : 0;
confirmedPromise(
getString('end_session_confirm_title', 'mod_bigbluebuttonbn'),
getString('end_session_confirm', 'mod_bigbluebuttonbn'),
getString('yes', 'moodle')
)
.then(() => requestEndMeeting(bbbId, groupId))
.then(() => {
notifySessionEnded(bbbId, groupId);
return;
})
.catch(displayException);
});
};
let listening = false;
if (!listening) {
registerEventListeners();
listening = true;
}
+72
View File
@@ -0,0 +1,72 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Events for the mod_bigbluebuttonbn plugin.
*
* @module mod_bigbluebuttonbn/events
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {dispatchEvent} from 'core/event_dispatcher';
export const eventTypes = {
/**
* Fired when a session has been ended.
*
* @event mod_bigbluebuttonbn/sessionEnded
* @type CustomEvent
* @property {object} detail
* @property {number} detail.bbbId
* @property {number} detail.groupId
*/
sessionEnded: 'mod_bigbluebuttonbn/sessionEnded',
/**
* Fired when the current session has been ended.
*
* @event mod_bigbluebuttonbn/currentSessionEnded
* @type CustomEvent
* @property {object} detail
*/
currentSessionEnded: 'mod_bigbluebuttonbn/currentSessionEnded',
};
/**
* Trigger the sessionEnded event.
*
* @param {number} bbbId
* @param {number} groupId
* @returns {CustomEvent}
* @fires event:mod_bigbluebuttonbn/sessionEnded
*/
export const notifySessionEnded = (bbbId, groupId) => dispatchEvent(eventTypes.sessionEnded, {
bbbId,
groupId,
});
/**
* Trigger the currentSessionEnded event.
*
* @param {Element} container
* @returns {CustomEvent}
* @fires event:mod_bigbluebuttonbn/currentSessionEnded
*/
export const notifyCurrentSessionEnded = container => dispatchEvent(
eventTypes.currentSessionEnded,
{},
container
);
@@ -0,0 +1,85 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Javascript module for importing presets.
*
* @module mod_bigbluebuttonbn/guest_access_modal
* @copyright 2022 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {getString} from 'core/str';
import ModalForm from 'core_form/modalform';
import {add as toastAdd, addToastRegion} from 'core/toast';
import {
exception as displayException,
} from 'core/notification';
const selectors = {
showGuestAccessButton: '[data-action="show-guest-access"]',
};
/**
* Intialise the object and click event to show the popup form
*
* @param {object} guestInfo
* @param {string} guestInfo.id
* @param {string} guestInfo.groupid
* @param {string} guestInfo.guestjoinurl
* @param {string} guestInfo.guestpassword
*/
export const init = (guestInfo) => {
const showGuestAccessButton = document.querySelector(selectors.showGuestAccessButton);
if (showGuestAccessButton === null) {
return;
}
const modalForm = new ModalForm({
modalConfig: {
title: getString('guestaccess_title', 'mod_bigbluebuttonbn'),
large: true,
},
args: guestInfo,
saveButtonText: getString('ok', 'core_moodle'),
formClass: 'mod_bigbluebuttonbn\\form\\guest_add',
});
showGuestAccessButton.addEventListener('click', event => {
modalForm.show().then(() => {
addToastRegion(modalForm.modal.getRoot()[0]);
return true;
}).catch(displayException);
modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (e) => {
// Remove toast region as if not it will be displayed on the closed modal.
const modalElement = modalForm.modal.getRoot()[0];
const regions = modalElement.querySelectorAll('.toast-wrapper');
regions.forEach((reg) => reg.remove());
if (e.detail.result) {
if (e.detail.emailcount > 0) {
toastAdd(getString('guestaccess_invite_success', 'mod_bigbluebuttonbn', e.detail),
{
type: 'success',
}
);
}
} else {
toastAdd(getString('guestaccess_invite_failure', 'mod_bigbluebuttonbn', e.detail),
{
type: 'warning',
}
);
}
}, {once: true});
event.stopPropagation();
});
};
+31
View File
@@ -0,0 +1,31 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Index page for the mod_bigbluebuttonbn plugin.
*
* @module mod_bigbluebuttonbn/index
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import './actions';
import {eventTypes} from './events';
export const init = () => {
document.addEventListener(eventTypes.sessionEnded, () => {
window.location.reload();
});
};
+372
View File
@@ -0,0 +1,372 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* JS for the mod_form page on mod_bigbluebuttonbn plugin.
*
* @module mod_bigbluebuttonbn/modform
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {getString} from 'core/str';
import Notification from 'core/notification';
import Templates from "core/templates";
/**
* Get all selectors in one place.
*
*/
const ELEMENT_SELECTOR = {
instanceTypeSelection: () => document.querySelector('select#id_type'),
instanceTypeProfiles: () => document.querySelector('[data-profile-types]'),
participantData: () => document.querySelector('[data-participant-data]'),
participantList: () => document.getElementsByName('participants')[0],
participantTable: () => document.getElementById('participant_list_table'),
participantSelectionType: () => document.getElementsByName('bigbluebuttonbn_participant_selection_type')[0],
participantSelection: () => document.getElementsByName('bigbluebuttonbn_participant_selection')[0],
participantAddButton: () => document.getElementsByName('bigbluebuttonbn_participant_selection_add')[0],
};
/**
* Initialise the moodle form code.
*
* This will help hide or show items depending on the selection of the instance type.
*
* @method init
* @param {object} info
*/
export const init = (info) => {
const selectedType = ELEMENT_SELECTOR.instanceTypeSelection();
const instanceTypeProfiles = JSON.parse(ELEMENT_SELECTOR.instanceTypeProfiles().dataset.profileTypes);
let profileType = info.instanceTypeDefault;
if (selectedType !== null && selectedType.selectedIndex !== -1) {
profileType = selectedType.options[selectedType.selectedIndex].value;
}
const isFeatureEnabled = (profileType, feature) => {
const features = instanceTypeProfiles[profileType].features;
return (features.indexOf(feature) !== -1);
};
applyInstanceTypeProfile(profileType, isFeatureEnabled);
// Change form visible fields depending on the selection.
selectedType.addEventListener('change', (e) => {
applyInstanceTypeProfile(e.target.value, isFeatureEnabled);
});
ELEMENT_SELECTOR.participantSelectionType().addEventListener('change', (e) => {
const currentTypeSelect = e.target;
updateSelectionFromType(currentTypeSelect);
});
ELEMENT_SELECTOR.participantAddButton().addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
participantAddFromCurrentSelection();
});
participantListInit();
};
/**
* Show or hide form element depending on the selected profile
*
* @param {string} profileType
* @param {function} isFeatureEnabled
*/
const applyInstanceTypeProfile = (profileType, isFeatureEnabled) => {
let showAll = isFeatureEnabled(profileType, 'all');
const showFieldset = (id, show) => {
// Show room settings validation.
const node = document.querySelector('#' + id);
if (!node) {
return;
}
if (show) {
node.style.display = 'block';
return;
}
node.style.display = 'none';
};
const showInput = (id, show) => {
// Show room settings validation.
const node = document.querySelector('#' + id);
if (!node) {
return;
}
var ancestor = node.closest('div').closest('div');
if (show) {
ancestor.style.display = 'block';
return;
}
ancestor.style.display = 'none';
};
const showFormGroup = (id, show) => {
// Show room settings validation.
const node = document.querySelector('#fgroup_id_' + id);
if (!node) {
return;
}
if (show) {
node.classList.remove('hidden');
return;
}
node.classList.add('hidden');
};
// Show room settings validation.
showFieldset('id_room', showAll ||
isFeatureEnabled(profileType, 'showroom'));
showInput('id_record', showAll ||
isFeatureEnabled(profileType, 'showroom'));
// Show recordings settings validation.
showFieldset('id_recordings', showAll ||
isFeatureEnabled(profileType, 'showrecordings'));
// Show recordings imported settings validation.
showInput('id_recordings_imported', showAll ||
isFeatureEnabled(profileType, 'showrecordings'));
// Show lock settings validation.
showFieldset('id_lock', showAll ||
isFeatureEnabled(profileType, 'lock'));
// Show guest settings validation.
showFieldset('id_guestaccess', showAll ||
isFeatureEnabled(profileType, 'showroom'));
// Preuploadpresentation feature validation.
showFieldset('id_preuploadpresentation', showAll ||
isFeatureEnabled(profileType, 'preuploadpresentation'));
// Participants feature validation.
showFieldset('id_permissions', showAll ||
isFeatureEnabled(profileType, 'permissions'));
// Schedule feature validation.
showFieldset('id_schedule', showAll ||
isFeatureEnabled(profileType, 'schedule'));
// Common module settings validation.
showFieldset('id_modstandardelshdr', showAll ||
isFeatureEnabled(profileType, 'modstandardelshdr'));
// Restrict access validation.
showFieldset('id_availabilityconditionsheader', showAll ||
isFeatureEnabled(profileType, 'availabilityconditionsheader'));
// Tags validation.
showFieldset('id_tagshdr', showAll || isFeatureEnabled(profileType, 'tagshdr'));
// Competencies validation.
showFieldset('id_competenciessection', showAll ||
isFeatureEnabled(profileType, 'competenciessection'));
// Completion validation.
showFormGroup('completionattendancegroup', showAll ||
isFeatureEnabled(profileType, 'completionattendance'));
// Completion validation.
showFormGroup('completionengagementgroup', showAll ||
isFeatureEnabled(profileType, 'completionengagement'));
};
/**
* Init the participant list
*/
const participantListInit = () => {
const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
const participantList = getParticipantList();
participantList.forEach(participant => {
const selectionTypeValue = participant.selectiontype;
const selectionValue = participant.selectionid;
const selectionRole = participant.role;
if (participant.selectiontype === 'all' ||
typeof participantData[participant.selectiontype].children[participant.selectionid] !== 'undefined') {
// Add it to the form, but don't add the delete button if it is the first item.
participantAddToForm(selectionTypeValue, selectionValue, selectionRole, true).then();
}
});
};
/**
* Add rows to the participant list depending on the current selection.
*
* @param {string} selectionTypeValue
* @param {string} selectionValue
* @param {string} selectedRole
* @param {boolean} canRemove
* @returns {Promise<void>}
*/
const participantAddToForm = async(selectionTypeValue, selectionValue, selectedRole, canRemove) => {
const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
const sviewer = await getString('mod_form_field_participant_bbb_role_viewer', 'mod_bigbluebuttonbn');
const smoderator = await getString('mod_form_field_participant_bbb_role_moderator', 'mod_bigbluebuttonbn');
let roles = {
viewer: {'id': 'viewer', label: sviewer},
moderator: {'id': 'moderator', label: smoderator}
};
roles[selectedRole].isselected = true;
try {
const listTable = document.querySelector('#participant_list_table tbody');
const templateContext = {
'selectiontypevalue': selectionTypeValue,
'selectionvalue': selectionValue,
'participanttype': participantData[selectionTypeValue].name,
'participantvalue':
(selectionTypeValue !== 'all') ?
participantData[selectionTypeValue].children[selectionValue].name : null,
'roles': Object.values(roles),
'canRemove': canRemove
};
const {html, js} = await Templates.renderForPromise('mod_bigbluebuttonbn/participant_form_add', templateContext);
const newNode = Templates.appendNodeContents(listTable, html, js)[0];
newNode.querySelector('.participant-select').addEventListener('change', () => {
participantListRoleUpdate(selectionTypeValue, selectionValue);
});
// Now add the callbacks: participantListRoleUpdate() and participantRemove().
const removeNode = newNode.querySelector('.remove-button');
if (removeNode) {
removeNode
.addEventListener('click', () => {
participantRemove(selectionTypeValue, selectionValue);
});
}
} catch (e) {
Notification.exception(e);
}
};
/*
*/
/**
* Update the related form element with the list value.
*
* @param {object} list
*/
const participantListUpdate = (list) => {
const participantList = ELEMENT_SELECTOR.participantList();
participantList.value = JSON.stringify(list);
};
/**
*
* @returns {any}
*/
const getParticipantList = () => {
const participantListValue = ELEMENT_SELECTOR.participantList().value;
if (participantListValue) {
return JSON.parse(participantListValue);
}
return [];
};
/**
* Remove participant both in the table/form and in the form element.
*
* @param {string} selectionTypeValue
* @param {string} selectionValue
*/
const participantRemove = (selectionTypeValue, selectionValue) => {
const pList = getParticipantList();
const id = 'participant_list_tr_' + selectionTypeValue + '-' + selectionValue;
const participantListTable = ELEMENT_SELECTOR.participantTable();
const selectionid = (selectionValue === '' ? null : selectionValue);
for (let i = 0; i < pList.length; i++) {
if (pList[i].selectiontype === selectionTypeValue &&
pList[i].selectionid === selectionid) {
pList.splice(i, 1);
}
}
// Remove from the form.
for (let i = 0; i < participantListTable.rows.length; i++) {
if (participantListTable.rows[i].id === id) {
participantListTable.deleteRow(i);
}
}
// Update value in the form.
participantListUpdate(pList);
};
/**
* Role update
*
* @param {string} type
* @param {string} id
*/
const participantListRoleUpdate = (type, id) => {
// Update in memory.
const participantListRoleSelection = document.querySelector(`#participant_list_tr_${type}-${id} .participant-select`);
const pList = getParticipantList();
for (var i = 0; i < pList.length; i++) {
if (pList[i].selectiontype === type && pList[i].selectionid === id) {
pList[i].role = participantListRoleSelection.value;
}
}
// Update in the form.
participantListUpdate(pList);
};
/**
* Add participant from the currently selected options
*/
const participantAddFromCurrentSelection = () => {
let selectionType = ELEMENT_SELECTOR.participantSelectionType();
let selection = ELEMENT_SELECTOR.participantSelection();
const pList = getParticipantList();
// Lookup to see if it has been added already.
for (var i = 0; i < pList.length; i++) {
if (pList[i].selectiontype === selectionType.value &&
pList[i].selectionid === selection.value) {
return;
}
}
pList.push({
"selectiontype": selectionType.value,
"selectionid": selection.value,
"role": "viewer"
});
// Add it to the form.
participantAddToForm(selectionType.value, selection.value, 'viewer', true).then();
// Update in the form.
participantListUpdate(pList);
};
/**
* Update selectable options when changing types
*
* @param {HTMLNode} currentTypeSelect
*/
const updateSelectionFromType = (currentTypeSelect) => {
const createNewOption = (selectItem, label, value) => {
const option = document.createElement('option');
option.text = label;
option.value = value;
selectItem.add(option);
};
const participantData = JSON.parse(ELEMENT_SELECTOR.participantData().dataset.participantData);
// Clear all selection items.
const participantSelect = ELEMENT_SELECTOR.participantSelection();
while (participantSelect.firstChild) {
participantSelect.removeChild(participantSelect.firstChild);
}
// Add options depending on the selection.
if (currentTypeSelect.selectedIndex !== -1) {
const options = Object.values(participantData[currentTypeSelect.value].children);
options.forEach(option => {
createNewOption(participantSelect, option.name, option.id);
});
if (currentTypeSelect.value === 'all') {
createNewOption(participantSelect, '---------------', 'all');
participantSelect.disabled = true;
} else {
participantSelect.disabled = false;
}
}
};
+400
View File
@@ -0,0 +1,400 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* JS for the recordings page on mod_bigbluebuttonbn plugin.
*
* @module mod_bigbluebuttonbn/recordings
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import * as repository from './repository';
import {exception as displayException, saveCancelPromise} from 'core/notification';
import {prefetchStrings} from 'core/prefetch';
import {getString, getStrings} from 'core/str';
import {addIconToContainerWithPromise} from 'core/loadingicon';
import Pending from 'core/pending';
const stringsWithKeys = {
first: 'view_recording_yui_first',
prev: 'view_recording_yui_prev',
next: 'view_recording_yui_next',
last: 'view_recording_yui_last',
goToLabel: 'view_recording_yui_page',
goToAction: 'view_recording_yui_go',
perPage: 'view_recording_yui_rows',
showAll: 'view_recording_yui_show_all',
};
// Load global strings.
prefetchStrings('bigbluebuttonbn', Object.entries(stringsWithKeys).map((entry) => entry[1]));
const getStringsForYui = () => {
const stringMap = Object.keys(stringsWithKeys).map(key => {
return {
key: stringsWithKeys[key],
component: 'mod_bigbluebuttonbn',
};
});
// Return an object with the matching string keys (we want an object with {<stringkey>: <stringvalue>...}).
return getStrings(stringMap)
.then((stringArray) => Object.assign(
{},
...Object.keys(stringsWithKeys).map(
(key, index) => ({[key]: stringArray[index]})
)
));
};
const getYuiInstance = lang => new Promise(resolve => {
// eslint-disable-next-line
YUI({
lang,
}).use('intl', 'datatable', 'datatable-sort', 'datatable-paginator', 'datatype-number', Y => {
resolve(Y);
});
});
/**
* Format the supplied date per the specified locale.
*
* @param {string} locale
* @param {number} date
* @returns {array}
*/
const formatDate = (locale, date) => {
const realDate = new Date(date);
return realDate.toLocaleDateString(locale, {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
});
};
/**
* Format response data for the table.
*
* @param {string} response JSON-encoded table data
* @returns {array}
*/
const getFormattedData = response => {
const recordingData = response.tabledata;
return JSON.parse(recordingData.data);
};
const getTableNode = tableSelector => document.querySelector(tableSelector);
const fetchRecordingData = tableSelector => {
const tableNode = getTableNode(tableSelector);
if (tableNode === null) {
return Promise.resolve(false);
}
if (tableNode.dataset.importMode) {
return repository.fetchRecordingsToImport(
tableNode.dataset.bbbid,
tableNode.dataset.bbbSourceInstanceId,
tableNode.dataset.bbbSourceCourseId,
tableNode.dataset.tools,
tableNode.dataset.groupId
);
} else {
return repository.fetchRecordings(
tableNode.dataset.bbbid,
tableNode.dataset.tools,
tableNode.dataset.groupId
);
}
};
/**
* Fetch the data table functinos for the specified table.
*
* @param {String} tableId in which we will display the table
* @param {String} searchFormId The Id of the relate.
* @param {Object} dataTable
* @returns {Object}
* @private
*/
const getDataTableFunctions = (tableId, searchFormId, dataTable) => {
const tableNode = getTableNode(tableId);
const bbbid = tableNode.dataset.bbbid;
const updateTableFromResponse = response => {
if (!response || !response.status) {
// There was no output at all.
return;
}
dataTable.get('data').reset(getFormattedData(response));
dataTable.set(
'currentData',
dataTable.get('data')
);
const currentFilter = dataTable.get('currentFilter');
if (currentFilter) {
filterByText(currentFilter);
}
};
const refreshTableData = () => fetchRecordingData(tableId).then(updateTableFromResponse);
const filterByText = value => {
const dataModel = dataTable.get('currentData');
dataTable.set('currentFilter', value);
const escapedRegex = value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
const rsearch = new RegExp(`<span>.*?${escapedRegex}.*?</span>`, 'i');
dataTable.set('data', dataModel.filter({asList: true}, item => {
const name = item.get('recording');
if (name && rsearch.test(name)) {
return true;
}
const description = item.get('description');
return description && rsearch.test(description);
}));
};
const requestAction = async(element) => {
const getDataFromAction = (element, dataType) => {
const dataElement = element.closest(`[data-${dataType}]`);
if (dataElement) {
return dataElement.dataset[dataType];
}
return null;
};
const elementData = element.dataset;
const payload = {
bigbluebuttonbnid: bbbid,
recordingid: getDataFromAction(element, 'recordingid'),
additionaloptions: getDataFromAction(element, 'additionaloptions'),
action: elementData.action,
};
// Slight change for import, for additional options.
if (!payload.additionaloptions) {
payload.additionaloptions = {};
}
if (elementData.action === 'import') {
const bbbsourceid = getDataFromAction(element, 'source-instance-id');
const bbbcourseid = getDataFromAction(element, 'source-course-id');
if (!payload.additionaloptions) {
payload.additionaloptions = {};
}
payload.additionaloptions.sourceid = bbbsourceid ? bbbsourceid : 0;
payload.additionaloptions.bbbcourseid = bbbcourseid ? bbbcourseid : 0;
}
// Now additional options should be a json string.
payload.additionaloptions = JSON.stringify(payload.additionaloptions);
if (element.dataset.requireConfirmation === "1") {
// Create the confirmation dialogue.
try {
await saveCancelPromise(
getString('confirm'),
recordingConfirmationMessage(payload),
getString('ok', 'moodle'),
);
} catch {
// User cancelled the dialogue.
return;
}
}
return repository.updateRecording(payload);
};
const recordingConfirmationMessage = async(data) => {
const playbackElement = document.querySelector(`#playbacks-${data.recordingid}`);
const recordingType = await getString(
playbackElement.dataset.imported === 'true' ? 'view_recording_link' : 'view_recording',
'bigbluebuttonbn'
);
const confirmation = await getString(`view_recording_${data.action}_confirmation`, 'bigbluebuttonbn', recordingType);
if (data.action === 'import') {
return confirmation;
}
// If it has associated links imported in a different course/activity, show that in confirmation dialog.
const associatedLinkCount = document.querySelector(`a#recording-${data.action}-${data.recordingid}`)?.dataset?.links;
if (!associatedLinkCount || associatedLinkCount === 0) {
return confirmation;
}
const confirmationWarning = await getString(
associatedLinkCount === 1
? `view_recording_${data.action}_confirmation_warning_p`
: `view_recording_${data.action}_confirmation_warning_s`,
'bigbluebuttonbn',
associatedLinkCount
);
return confirmationWarning + '\n\n' + confirmation;
};
/**
* Process an action event.
*
* @param {Event} e
*/
const processAction = e => {
const popoutLink = e.target.closest('[data-action="play"]');
if (popoutLink) {
e.preventDefault();
const videoPlayer = window.open('', '_blank');
videoPlayer.opener = null;
videoPlayer.location.href = popoutLink.href;
// TODO send a recording viewed event when this event will be implemented.
return;
}
// Fetch any clicked anchor.
const clickedLink = e.target.closest('a[data-action]');
if (clickedLink && !clickedLink.classList.contains('disabled')) {
e.preventDefault();
// Create a spinning icon on the table.
const iconPromise = addIconToContainerWithPromise(dataTable.get('boundingBox').getDOMNode());
requestAction(clickedLink)
.then(refreshTableData)
.then(iconPromise.resolve)
.catch(displayException);
}
};
const processSearchSubmission = e => {
// Prevent the default action.
e.preventDefault();
const parentNode = e.target.closest('div[role=search]');
const searchInput = parentNode.querySelector('input[name=search]');
filterByText(searchInput.value);
};
const registerEventListeners = () => {
// Add event listeners to the table boundingBox.
const boundingBox = dataTable.get('boundingBox').getDOMNode();
boundingBox.addEventListener('click', processAction);
// Setup the search from handlers.
const searchForm = document.querySelector(searchFormId);
if (searchForm) {
const searchButton = document.querySelector(searchFormId + ' button');
searchButton.addEventListener('click', processSearchSubmission);
}
};
return {
filterByText,
refreshTableData,
registerEventListeners,
};
};
/**
* Setup the data table for the specified BBB instance.
*
* @param {String} tableId in which we will display the table
* @param {String} searchFormId The Id of the relate.
* @param {object} response The response from the data request
* @returns {Promise}
*/
const setupDatatable = (tableId, searchFormId, response) => {
if (!response) {
return Promise.resolve();
}
if (!response.status) {
// Something failed. Continue to show the plain output.
return Promise.resolve();
}
const recordingData = response.tabledata;
const pendingPromise = new Pending('mod_bigbluebuttonbn/recordings/setupDatatable');
return Promise.all([getYuiInstance(recordingData.locale), getStringsForYui()])
.then(([yuiInstance, strings]) => {
// Here we use a custom formatter for date.
// See https://clarle.github.io/yui3/yui/docs/api/classes/DataTable.BodyView.Formatters.html
// Inspired from examples here: https://clarle.github.io/yui3/yui/docs/datatable/
// Normally formatter have the prototype: (col) => (cell) => <computed value>, see:
// https://clarle.github.io/yui3/yui/docs/api/files/datatable_js_formatters.js.html#l100 .
const dateCustomFormatter = () => (cell) => formatDate(recordingData.locale, cell.value);
// Add the fetched strings to the YUI Instance.
yuiInstance.Intl.add('datatable-paginator', yuiInstance.config.lang, {...strings});
yuiInstance.DataTable.BodyView.Formatters.customDate = dateCustomFormatter;
return yuiInstance;
})
.then(yuiInstance => {
const tableData = getFormattedData(response);
yuiInstance.RecordsPaginatorView = Y.Base.create('my-paginator-view', yuiInstance.DataTable.Paginator.View, [], {
_modelChange: function(e) {
var changed = e.changed,
totalItems = (changed && changed.totalItems);
if (totalItems) {
this._updateControlsUI(e.target.get('page'));
}
}
});
return new yuiInstance.DataTable({
paginatorView: "RecordsPaginatorView",
width: "1195px",
columns: recordingData.columns,
data: tableData,
rowsPerPage: 10,
paginatorLocation: ['header', 'footer'],
autoSync: true
});
})
.then(dataTable => {
dataTable.render(tableId);
const {registerEventListeners} = getDataTableFunctions(
tableId,
searchFormId,
dataTable);
registerEventListeners();
return dataTable;
})
.then(dataTable => {
pendingPromise.resolve();
return dataTable;
});
};
/**
* Initialise recordings code.
*
* @method init
* @param {String} tableId in which we will display the table
* @param {String} searchFormId The Id of the relate.
*/
export const init = (tableId, searchFormId) => {
const pendingPromise = new Pending('mod_bigbluebuttonbn/recordings:init');
fetchRecordingData(tableId)
.then(response => setupDatatable(tableId, searchFormId, response))
.then(() => pendingPromise.resolve())
.catch(displayException);
};
+141
View File
@@ -0,0 +1,141 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Repository to perform WS calls for mod_bigbluebuttonbn.
*
* @module mod_bigbluebuttonbn/repository
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {call as fetchMany} from 'core/ajax';
/**
* Fetch the list of recordings from the server.
*
* @param {Number} bigbluebuttonbnid The instance ID
* @param {String} tools the set of tools to display
* @param {number} groupid
* @returns {Promise}
*/
export const fetchRecordings = (bigbluebuttonbnid, tools, groupid) => {
const args = {
bigbluebuttonbnid,
tools,
};
if (groupid) {
args.groupid = groupid;
}
return fetchMany([{methodname: 'mod_bigbluebuttonbn_get_recordings', args}])[0];
};
/**
* Fetch the list of recordings from the server that can be imported.
*
* @param {Number} destinationinstanceid The destination instance ID
* @param {Number} sourcebigbluebuttonbnid The original instance ID
* @param {Number} sourcecourseid The destination instance ID
* @param {String} tools the set of tools to display
* @param {number} groupid
* @returns {Promise}
*/
export const fetchRecordingsToImport = (
destinationinstanceid,
sourcebigbluebuttonbnid,
sourcecourseid,
tools,
groupid
) => {
const args = {
destinationinstanceid,
sourcebigbluebuttonbnid,
sourcecourseid,
tools,
};
if (groupid) {
args.groupid = groupid;
}
return fetchMany([{methodname: 'mod_bigbluebuttonbn_get_recordings_to_import', args}])[0];
};
/**
* Perform an update on a single recording.
*
* @param {object} args The instance ID
* @returns {Promise}
*/
export const updateRecording = args => fetchMany([
{
methodname: 'mod_bigbluebuttonbn_update_recording',
args,
}
])[0];
/**
* End the Meeting
*
* @param {number} bigbluebuttonbnid
* @param {number} groupid
* @returns {Promise}
*/
export const endMeeting = (bigbluebuttonbnid, groupid) => fetchMany([
{
methodname: 'mod_bigbluebuttonbn_end_meeting',
args: {
bigbluebuttonbnid,
groupid
},
}
])[0];
/**
* Validate completion.
*
* @param {number} bigbluebuttonbnid
* @returns {Promise}
*/
export const completionValidate = (bigbluebuttonbnid) => fetchMany([
{
methodname: 'mod_bigbluebuttonbn_completion_validate',
args: {
bigbluebuttonbnid
},
}
])[0];
/**
* Fetch meeting info for the specified meeting.
*
* @param {number} bigbluebuttonbnid
* @param {number} groupid
* @param {boolean} [updatecache=false]
* @returns {Promise}
*/
export const getMeetingInfo = (bigbluebuttonbnid, groupid, updatecache = false) => fetchMany([
{
methodname: 'mod_bigbluebuttonbn_meeting_info',
args: {
bigbluebuttonbnid,
groupid,
updatecache,
},
}
])[0];
+100
View File
@@ -0,0 +1,100 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* JS actions for the rooms page for mod_bigbluebuttonbn.
*
* @module mod_bigbluebuttonbn/rooms
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import './actions';
import * as repository from './repository';
import * as roomUpdater from './roomupdater';
import {
exception as displayException,
fetchNotifications,
} from 'core/notification';
import Pending from 'core/pending';
import {getString} from 'core/str';
import {add as addToast} from 'core/toast';
import {eventTypes, notifyCurrentSessionEnded} from './events';
/**
* Init the room
*
* @param {Number} bigbluebuttonbnid bigblubeutton identifier
* @param {Number} pollInterval poll interval in miliseconds
*/
export const init = (bigbluebuttonbnid, pollInterval) => {
const completionElement = document.querySelector('a[href*=completion_validate]');
if (completionElement) {
completionElement.addEventListener("click", event => {
event.preventDefault();
const pendingPromise = new Pending('mod_bigbluebuttonbn/completion:validate');
repository.completionValidate(bigbluebuttonbnid)
.then(() => getString('completionvalidatestatetriggered', 'mod_bigbluebuttonbn'))
.then(str => addToast(str))
.then(() => pendingPromise.resolve())
.catch(displayException);
});
}
document.addEventListener('click', e => {
const joinButton = e.target.closest('[data-action="join"]');
if (joinButton) {
window.open(joinButton.href, 'bigbluebutton_conference');
e.preventDefault();
// Gives the user a bit of time to go into the meeting before polling the room.
setTimeout(() => {
roomUpdater.updateRoom(true);
}, pollInterval);
}
});
document.addEventListener(eventTypes.sessionEnded, () => {
roomUpdater.stop();
roomUpdater.updateRoom();
fetchNotifications();
});
window.addEventListener(eventTypes.currentSessionEnded, () => {
roomUpdater.stop();
roomUpdater.updateRoom();
fetchNotifications();
});
// Room update.
roomUpdater.start(pollInterval);
};
/**
* Auto close child windows when clicking the End meeting button.
* @param {Number} closeDelay time to wait in miliseconds before closing the window
*/
export const setupWindowAutoClose = (closeDelay = 2000) => {
notifyCurrentSessionEnded(window.opener);
window.addEventListener('onbeforeunload', () => {
window.opener.setTimeout(() => {
roomUpdater.updateRoom(true);
}, closeDelay);
},
{
once: true
});
window.close(); // This does not work as scripts can only close windows that are opened by themselves.
};
+110
View File
@@ -0,0 +1,110 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* JS room updater.
*
* @module mod_bigbluebuttonbn/roomupdater
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Pending from 'core/pending';
import Templates from "core/templates";
import {exception as displayException} from 'core/notification';
import {getMeetingInfo} from './repository';
let timerReference = null;
let timerRunning = false;
let pollInterval = 0;
let pollIntervalFactor = 1;
const MAX_POLL_INTERVAL_FACTOR = 10;
const resetValues = () => {
timerRunning = false;
timerReference = null;
pollInterval = 0;
pollIntervalFactor = 1;
};
/**
* Start the information poller.
* @param {Number} interval interval in miliseconds between each poll action.
*/
export const start = (interval) => {
resetValues();
timerRunning = true;
pollInterval = interval;
poll();
};
/**
* Stop the room updater.
*/
export const stop = () => {
if (timerReference) {
clearTimeout(timerReference);
}
resetValues();
};
/**
* Start the information poller.
*/
const poll = () => {
if (!timerRunning || !pollInterval) {
// The poller has been stopped.
return;
}
updateRoom()
.then((updateOk) => {
if (!updateOk) {
pollIntervalFactor = (pollIntervalFactor < MAX_POLL_INTERVAL_FACTOR) ?
pollIntervalFactor + 1 : MAX_POLL_INTERVAL_FACTOR;
// We make sure if there is an error that we do not try too often.
}
timerReference = setTimeout(() => poll(), pollInterval * pollIntervalFactor);
return true;
})
.catch();
};
/**
* Update the room information.
*
* @param {boolean} [updatecache=false] should we update cache
* @returns {Promise}
*/
export const updateRoom = (updatecache = false) => {
const bbbRoomViewElement = document.getElementById('bigbluebuttonbn-room-view');
if (bbbRoomViewElement === null) {
return Promise.resolve(false);
}
const bbbId = bbbRoomViewElement.dataset.bbbId;
const groupId = bbbRoomViewElement.dataset.groupId;
const pendingPromise = new Pending('mod_bigbluebuttonbn/roomupdater:updateRoom');
return getMeetingInfo(bbbId, groupId, updatecache)
.then(data => {
// Just make sure we have the right information for the template.
data.haspresentations = !!(data.presentations && data.presentations.length);
return Templates.renderForPromise('mod_bigbluebuttonbn/room_view', data);
})
.then(({html, js}) => Templates.replaceNode(bbbRoomViewElement, html, js))
.then(() => pendingPromise.resolve())
.catch(displayException);
};