mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 08:56:36 +02:00
MDL-75259 tiny_recordrtc: Implement Record RTC plugin for TinyMCE
Part of MDL-75966 Co-authored by Andrew Lyons <andrew@nicols.co.uk> AMOS BEGIN CPY [audioandvideo,atto_recordrtc],[audioandvideo,tiny_recordrtc] CPY [audiobitrate,atto_recordrtc],[audiobitrate,tiny_recordrtc] CPY [attachrecording,atto_recordrtc],[attachrecording,tiny_recordrtc] CPY [allowedtypes,atto_recordrtc],[allowedtypes,tiny_recordrtc] CPY [allowedtypes_desc,atto_recordrtc],[allowedtypes_desc,tiny_recordrtc] CPY [audiobitrate,atto_recordrtc],[audiobitrate,tiny_recordrtc] CPY [audiobitrate_desc,atto_recordrtc],[audiobitrate_desc,tiny_recordrtc] CPY [audiotimelimit,atto_recordrtc],[audiotimelimit,tiny_recordrtc] CPY [audiotimelimit_desc,atto_recordrtc],[audiotimelimit_desc,tiny_recordrtc] CPY [confirm_yes,atto_recordrtc],[yes,core] CPY [gumabort,atto_recordrtc],[gumabort,tiny_recordrtc] CPY [gumabort_title,atto_recordrtc],[gumabort_title,tiny_recordrtc] CPY [gumnotallowed,atto_recordrtc],[gumnotallowed,tiny_recordrtc] CPY [gumnotallowed_title,atto_recordrtc],[gumnotallowed_title,tiny_recordrtc] CPY [gumnotfound,atto_recordrtc],[gumnotfound,tiny_recordrtc] CPY [gumnotfound_title,atto_recordrtc],[gumnotfound_title,tiny_recordrtc] CPY [gumnotreadable,atto_recordrtc],[gumnotreadable,tiny_recordrtc] CPY [gumnotreadable_title,atto_recordrtc],[gumnotreadable_title,tiny_recordrtc] CPY [gumnotsupported,atto_recordrtc],[gumnotsupported,tiny_recordrtc] CPY [gumnotsupported_title,atto_recordrtc],[gumnotsupported_title,tiny_recordrtc] CPY [gumoverconstrained,atto_recordrtc],[gumoverconstrained,tiny_recordrtc] CPY [gumoverconstrained_title,atto_recordrtc],[gumoverconstrained_title,tiny_recordrtc] CPY [gumsecurity,atto_recordrtc],[gumsecurity,tiny_recordrtc] CPY [gumsecurity_title,atto_recordrtc],[gumsecurity_title,tiny_recordrtc] CPY [gumtype,atto_recordrtc],[gumtype,tiny_recordrtc] CPY [gumtype_title,atto_recordrtc],[gumtype_title,tiny_recordrtc] CPY [insecurealert,atto_recordrtc],[insecurealert,tiny_recordrtc] CPY [insecurealert_title,atto_recordrtc],[insecurealert_title,tiny_recordrtc] CPY [insecurealerttitle,atto_recordrtc],[insecurealerttitle,tiny_recordrtc] CPY [insecurealert,atto_recordrtc],[insecurealert,tiny_recordrtc] CPY [nearingmaxsize,atto_recordrtc],[maxfilesizehit,tiny_recordrtc] CPY [nearingmaxsize_title,atto_recordrtc],[maxfilesizehit_title,tiny_recordrtc] CPY [norecordingfound,atto_recordrtc],[norecordingfound,tiny_recordrtc] CPY [norecordingfound_title,atto_recordrtc],[norecordingfound_title,tiny_recordrtc] CPY [nowebrtc,atto_recordrtc],[nowebrtc,tiny_recordrtc] CPY [nowebrtc_title,atto_recordrtc],[nowebrtc_title,tiny_recordrtc] CPY [onlyaudio,atto_recordrtc],[onlyaudio,tiny_recordrtc] CPY [onlyvideo,atto_recordrtc],[onlyvideo,tiny_recordrtc] CPY [recordagain,atto_recordrtc],[recordagain,tiny_recordrtc] CPY [recordinguploaded,atto_recordrtc],[recordinguploaded,tiny_recordrtc] CPY [recordingfailed,atto_recordrtc],[recordingfailed,tiny_recordrtc] CPY [recordrtc:recordaudio,atto_recordrtc],[recordrtc:recordaudio,tiny_recordrtc] CPY [recordrtc:recordvideo,atto_recordrtc],[recordrtc:recordvideo,tiny_recordrtc] CPY [startrecording,atto_recordrtc],[startrecording,tiny_recordrtc] CPY [stoprecording,atto_recordrtc],[stoprecording,tiny_recordrtc] CPY [timelimitwarning,atto_recordrtc],[timelimitwarning,tiny_recordrtc] CPY [uploadaborted,atto_recordrtc],[uploadaborted,tiny_recordrtc] CPY [uploadprogress,atto_recordrtc],[uploadprogress,tiny_recordrtc] CPY [videobitrate,atto_recordrtc],[videobitrate,tiny_recordrtc] CPY [videobitrate_desc,atto_recordrtc],[videobitrate_desc,tiny_recordrtc] CPY [videobuttontitle,atto_recordrtc],[videobuttontitle,tiny_recordrtc] CPY [videotimelimit,atto_recordrtc],[videotimelimit,tiny_recordrtc] CPY [videotimelimit_desc,atto_recordrtc],[videotimelimit_desc,tiny_recordrtc] AMOS END
This commit is contained in:
parent
71046558b1
commit
0cd3b75164
47 changed files with 2308 additions and 0 deletions
|
@ -2032,6 +2032,7 @@ class core_plugin_manager {
|
|||
'autosave',
|
||||
'h5p',
|
||||
'media',
|
||||
'recordrtc',
|
||||
],
|
||||
|
||||
'tinymce' => array(
|
||||
|
|
3
lib/editor/tiny/plugins/recordrtc/amd/build/audio_recorder.min.js
vendored
Normal file
3
lib/editor/tiny/plugins/recordrtc/amd/build/audio_recorder.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
define("tiny_recordrtc/audio_recorder",["exports","./base_recorder","./modal","core/modal_registry","tiny_recordrtc/common"],(function(_exports,_base_recorder,_modal,_modal_registry,_common){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_base_recorder=_interopRequireDefault(_base_recorder),_modal=_interopRequireDefault(_modal),_modal_registry=_interopRequireDefault(_modal_registry);class Audio extends _base_recorder.default{configurePlayer(){return this.modalRoot.querySelector("audio")}getSupportedTypes(){return["audio/webm;codecs=opus","audio/ogg;codecs=opus"]}getParsedRecordingOptions(){return{audioBitsPerSecond:parseInt(this.config.audiobitrate)}}getMediaConstraints(){return{audio:!0}}getRecordingType(){return"audio"}getTimeLimit(){return this.config.audiotimelimit}getEmbedTemplateName(){return"tiny_recordrtc/embed_audio"}getFileName(prefix){return"".concat(prefix,"-audio.ogg")}static getModalClass(){var _class;const modalType="".concat(_common.component,"/audio_recorder"),registration=_modal_registry.default.get(modalType);if(registration)return registration.module;const AudioModal=(_defineProperty(_class=class extends _modal.default{},"TYPE",modalType),_defineProperty(_class,"TEMPLATE","".concat(_common.component,"/audio_recorder")),_class);return _modal_registry.default.register(AudioModal.TYPE,AudioModal,AudioModal.TEMPLATE),AudioModal}}return _exports.default=Audio,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=audio_recorder.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"audio_recorder.min.js","sources":["../src/audio_recorder.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 * Tiny Record RTC - audio recorder configuration.\n *\n * @module tiny_recordrtc/audio\n * @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BaseClass from './base_recorder';\nimport Modal from './modal';\nimport ModalRegistry from 'core/modal_registry';\nimport {component} from 'tiny_recordrtc/common';\n\nexport default class Audio extends BaseClass {\n configurePlayer() {\n return this.modalRoot.querySelector('audio');\n }\n\n getSupportedTypes() {\n return [\n 'audio/webm;codecs=opus',\n 'audio/ogg;codecs=opus',\n ];\n }\n\n getParsedRecordingOptions() {\n return {\n audioBitsPerSecond: parseInt(this.config.audiobitrate),\n };\n }\n\n getMediaConstraints() {\n return {\n audio: true,\n };\n }\n\n getRecordingType() {\n return 'audio';\n }\n\n getTimeLimit() {\n return this.config.audiotimelimit;\n }\n\n getEmbedTemplateName() {\n return 'tiny_recordrtc/embed_audio';\n }\n\n getFileName(prefix) {\n return `${prefix}-audio.ogg`;\n }\n\n static getModalClass() {\n const modalType = `${component}/audio_recorder`;\n const registration = ModalRegistry.get(modalType);\n if (registration) {\n return registration.module;\n }\n\n const AudioModal = class extends Modal {\n static TYPE = modalType;\n static TEMPLATE = `${component}/audio_recorder`;\n };\n\n ModalRegistry.register(AudioModal.TYPE, AudioModal, AudioModal.TEMPLATE);\n return AudioModal;\n }\n}\n"],"names":["Audio","BaseClass","configurePlayer","this","modalRoot","querySelector","getSupportedTypes","getParsedRecordingOptions","audioBitsPerSecond","parseInt","config","audiobitrate","getMediaConstraints","audio","getRecordingType","getTimeLimit","audiotimelimit","getEmbedTemplateName","getFileName","prefix","modalType","component","registration","ModalRegistry","get","module","AudioModal","Modal","register","TYPE","TEMPLATE"],"mappings":"+pBA4BqBA,cAAcC,uBAC/BC,yBACWC,KAAKC,UAAUC,cAAc,SAGxCC,0BACW,CACH,yBACA,yBAIRC,kCACW,CACHC,mBAAoBC,SAASN,KAAKO,OAAOC,eAIjDC,4BACW,CACHC,OAAO,GAIfC,yBACW,QAGXC,sBACWZ,KAAKO,OAAOM,eAGvBC,6BACW,6BAGXC,YAAYC,wBACEA,6DAIJC,oBAAeC,qCACfC,aAAeC,wBAAcC,IAAIJ,cACnCE,oBACOA,aAAaG,aAGlBC,mCAAa,cAAcC,wBACfP,uDACOC,6EAGXO,SAASF,WAAWG,KAAMH,WAAYA,WAAWI,UACxDJ"}
|
3
lib/editor/tiny/plugins/recordrtc/amd/build/base_recorder.min.js
vendored
Normal file
3
lib/editor/tiny/plugins/recordrtc/amd/build/base_recorder.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
10
lib/editor/tiny/plugins/recordrtc/amd/build/commands_audio.min.js
vendored
Normal file
10
lib/editor/tiny/plugins/recordrtc/amd/build/commands_audio.min.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
define("tiny_recordrtc/commands_audio",["exports","core/str","editor_tiny/utils","./common","./audio_recorder"],(function(_exports,_str,_utils,_common,_audio_recorder){var obj;
|
||||
/**
|
||||
* Tiny Record RTC - record audio command.
|
||||
*
|
||||
* @module tiny_recordrtc/recordAudioCommands
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_audio_recorder=(obj=_audio_recorder)&&obj.__esModule?obj:{default:obj};return _exports.default=async()=>{if(!_audio_recorder.default.isBrowserCompatible())return()=>!1;const[audioButtonTitle,audio]=await Promise.all([(0,_str.get_string)("audiobuttontitle",_common.component),(0,_utils.getButtonImage)("audio",_common.component)]);return editor=>{editor.ui.registry.addIcon("audio",audio.html),editor.ui.registry.addButton(_common.audioButtonName,{icon:"audio",tooltip:audioButtonTitle,onAction:()=>_audio_recorder.default.display(editor)}),editor.ui.registry.addMenuItem(_common.audioButtonName,{icon:"audio",text:audioButtonTitle,onAction:()=>_audio_recorder.default.display(editor)})}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=commands_audio.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"commands_audio.min.js","sources":["../src/commands_audio.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 * Tiny Record RTC - record audio command.\n *\n * @module tiny_recordrtc/recordAudioCommands\n * @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {get_string as getString} from 'core/str';\nimport {getButtonImage} from 'editor_tiny/utils';\nimport {\n audioButtonName,\n component\n} from './common';\nimport Recorder from './audio_recorder';\n\nexport default async() => {\n if (!Recorder.isBrowserCompatible()) {\n // The browser doesn't support the plugin, so just don't show it.\n return () => false;\n }\n\n const [\n audioButtonTitle,\n audio,\n ] = await Promise.all([\n getString('audiobuttontitle', component),\n getButtonImage('audio', component),\n ]);\n\n return (editor) => {\n const icon = 'audio';\n editor.ui.registry.addIcon(icon, audio.html);\n\n editor.ui.registry.addButton(audioButtonName, {\n icon,\n tooltip: audioButtonTitle,\n onAction: () => Recorder.display(editor),\n });\n\n editor.ui.registry.addMenuItem(audioButtonName, {\n icon,\n text: audioButtonTitle,\n onAction: () => Recorder.display(editor),\n });\n };\n};\n"],"names":["async","Recorder","isBrowserCompatible","audioButtonTitle","audio","Promise","all","component","editor","ui","registry","addIcon","html","addButton","audioButtonName","icon","tooltip","onAction","display","addMenuItem","text"],"mappings":";;;;;;;qLA+BeA,cACNC,wBAASC,4BAEH,KAAM,QAIbC,iBACAC,aACMC,QAAQC,IAAI,EAClB,mBAAU,mBAAoBC,oBAC9B,yBAAe,QAASA,4BAGpBC,SAEJA,OAAOC,GAAGC,SAASC,QADN,QACoBP,MAAMQ,MAEvCJ,OAAOC,GAAGC,SAASG,UAAUC,wBAAiB,CAC1CC,KAJS,QAKTC,QAASb,iBACTc,SAAU,IAAMhB,wBAASiB,QAAQV,UAGrCA,OAAOC,GAAGC,SAASS,YAAYL,wBAAiB,CAC5CC,KAVS,QAWTK,KAAMjB,iBACNc,SAAU,IAAMhB,wBAASiB,QAAQV"}
|
10
lib/editor/tiny/plugins/recordrtc/amd/build/commands_video.min.js
vendored
Normal file
10
lib/editor/tiny/plugins/recordrtc/amd/build/commands_video.min.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
define("tiny_recordrtc/commands_video",["exports","core/str","editor_tiny/utils","./common","./video_recorder"],(function(_exports,_str,_utils,_common,_video_recorder){var obj;
|
||||
/**
|
||||
* Tiny Record RTC - record video command.
|
||||
*
|
||||
* @module tiny_recordrtc/recordVideoCommands
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_video_recorder=(obj=_video_recorder)&&obj.__esModule?obj:{default:obj};return _exports.default=async()=>{if(!_video_recorder.default.isBrowserCompatible())return()=>!1;const[videoButtonTitle,buttonImage]=await Promise.all([(0,_str.get_string)("videobuttontitle",_common.component),(0,_utils.getButtonImage)("video",_common.component)]);return editor=>{editor.ui.registry.addIcon("video",buttonImage.html),editor.ui.registry.addButton(_common.videoButtonName,{icon:"video",tooltip:videoButtonTitle,onAction:()=>_video_recorder.default.display(editor)}),editor.ui.registry.addMenuItem(_common.videoButtonName,{icon:"video",text:videoButtonTitle,onAction:()=>_video_recorder.default.display(editor)})}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=commands_video.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"commands_video.min.js","sources":["../src/commands_video.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 * Tiny Record RTC - record video command.\n *\n * @module tiny_recordrtc/recordVideoCommands\n * @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {get_string as getString} from 'core/str';\nimport {getButtonImage as getVideoIcon} from 'editor_tiny/utils';\nimport {\n videoButtonName,\n component\n} from './common';\nimport Recorder from './video_recorder';\n\nexport default async() => {\n if (!Recorder.isBrowserCompatible()) {\n // The browser doesn't support the plugin, so just don't show it.\n return () => false;\n }\n\n const [\n videoButtonTitle,\n buttonImage,\n ] = await Promise.all([\n getString('videobuttontitle', component),\n getVideoIcon('video', component),\n ]);\n\n return (editor) => {\n let icon = 'video';\n editor.ui.registry.addIcon(icon, buttonImage.html);\n\n editor.ui.registry.addButton(videoButtonName, {\n icon,\n tooltip: videoButtonTitle,\n onAction: () => Recorder.display(editor),\n });\n\n editor.ui.registry.addMenuItem(videoButtonName, {\n icon,\n text: videoButtonTitle,\n onAction: () => Recorder.display(editor),\n });\n };\n};\n"],"names":["async","Recorder","isBrowserCompatible","videoButtonTitle","buttonImage","Promise","all","component","editor","ui","registry","addIcon","html","addButton","videoButtonName","icon","tooltip","onAction","display","addMenuItem","text"],"mappings":";;;;;;;qLA+BeA,cACNC,wBAASC,4BAEH,KAAM,QAIbC,iBACAC,mBACMC,QAAQC,IAAI,EAClB,mBAAU,mBAAoBC,oBAC9B,yBAAa,QAASA,4BAGlBC,SAEJA,OAAOC,GAAGC,SAASC,QADR,QACsBP,YAAYQ,MAE7CJ,OAAOC,GAAGC,SAASG,UAAUC,wBAAiB,CAC1CC,KAJO,QAKPC,QAASb,iBACTc,SAAU,IAAMhB,wBAASiB,QAAQV,UAGrCA,OAAOC,GAAGC,SAASS,YAAYL,wBAAiB,CAC5CC,KAVO,QAWPK,KAAMjB,iBACNc,SAAU,IAAMhB,wBAASiB,QAAQV"}
|
3
lib/editor/tiny/plugins/recordrtc/amd/build/common.min.js
vendored
Normal file
3
lib/editor/tiny/plugins/recordrtc/amd/build/common.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
define("tiny_recordrtc/common",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={pluginName:"tiny_recordrtc/plugin",component:"tiny_recordrtc",audioButtonName:"tiny_recordrtc_audio",videoButtonName:"tiny_recordrtc_video"},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=common.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"common.min.js","sources":["../src/common.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 * Tiny Record RTC common values.\n *\n * @module tiny_recordrtc/common\n * @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n pluginName: 'tiny_recordrtc/plugin',\n component: 'tiny_recordrtc',\n audioButtonName: 'tiny_recordrtc_audio',\n videoButtonName: 'tiny_recordrtc_video'\n};\n"],"names":["pluginName","component","audioButtonName","videoButtonName"],"mappings":"uKAuBe,CACXA,WAAY,wBACZC,UAAW,iBACXC,gBAAiB,uBACjBC,gBAAiB"}
|
11
lib/editor/tiny/plugins/recordrtc/amd/build/configuration.min.js
vendored
Normal file
11
lib/editor/tiny/plugins/recordrtc/amd/build/configuration.min.js
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
define("tiny_recordrtc/configuration",["exports","./common","editor_tiny/utils"],(function(_exports,_common,_utils){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.configure=void 0;
|
||||
/**
|
||||
* Tiny Record RTC configuration.
|
||||
*
|
||||
* @module tiny_recordrtc/configuration
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const configureMenu=menu=>{const items=menu.insert.items.split(" ");return items.some(((item,index)=>!!item.match(/(media|video)\b/)&&(items.splice(index+1,0,_common.audioButtonName,_common.videoButtonName),!0)))?menu.insert.items=items.join(" "):(0,_utils.addMenubarItem)(menu,"insert","".concat(_common.audioButtonName," ").concat(_common.videoButtonName)),menu};_exports.configure=instanceConfig=>{return{toolbar:(toolbar=instanceConfig.toolbar,toolbar.map((section=>("content"===section.name&&(section.items.some(((item,index)=>!!item.match(/(media|video)\b/)&&(section.items.splice(index+1,0,_common.audioButtonName,_common.videoButtonName),!0)))||section.items.unshift(_common.audioButtonName,_common.videoButtonName)),section)))),menu:configureMenu(instanceConfig.menu)};var toolbar}}));
|
||||
|
||||
//# sourceMappingURL=configuration.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"configuration.min.js","sources":["../src/configuration.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 * Tiny Record RTC configuration.\n *\n * @module tiny_recordrtc/configuration\n * @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {\n audioButtonName,\n videoButtonName\n} from './common';\nimport {\n addMenubarItem,\n} from 'editor_tiny/utils';\n\nconst configureMenu = (menu) => {\n const items = menu.insert.items.split(' ');\n const inserted = items.some((item, index) => {\n // Append after the media or video button.\n if (item.match(/(media|video)\\b/)) {\n items.splice(index + 1, 0, audioButtonName, videoButtonName);\n return true;\n }\n\n return false;\n });\n\n if (inserted) {\n menu.insert.items = items.join(' ');\n } else {\n addMenubarItem(menu, 'insert', `${audioButtonName} ${videoButtonName}`);\n }\n\n return menu;\n};\n\nconst configureToolbar = (toolbar) => {\n // The toolbar contains an array of named sections.\n // The Moodle integration ensures that there is a section called 'content'.\n\n\n return toolbar.map((section) => {\n if (section.name === 'content') {\n const inserted = section.items.some((item, index) => {\n // Append after the media or video button.\n if (item.match(/(media|video)\\b/)) {\n section.items.splice(index + 1, 0, audioButtonName, videoButtonName);\n return true;\n }\n return false;\n });\n\n if (!inserted) {\n section.items.unshift(audioButtonName, videoButtonName);\n }\n }\n\n return section;\n });\n};\n\nexport const configure = (instanceConfig) => {\n // Update the instance configuration to add the Media menu option to the menus and toolbars and upload_handler.\n return {\n toolbar: configureToolbar(instanceConfig.toolbar),\n menu: configureMenu(instanceConfig.menu),\n };\n};\n"],"names":["configureMenu","menu","items","insert","split","some","item","index","match","splice","audioButtonName","videoButtonName","join","instanceConfig","toolbar","map","section","name","unshift"],"mappings":";;;;;;;;MA+BMA,cAAiBC,aACbC,MAAQD,KAAKE,OAAOD,MAAME,MAAM,YACrBF,MAAMG,MAAK,CAACC,KAAMC,UAE3BD,KAAKE,MAAM,qBACXN,MAAMO,OAAOF,MAAQ,EAAG,EAAGG,wBAAiBC,0BACrC,KAOXV,KAAKE,OAAOD,MAAQA,MAAMU,KAAK,+BAEhBX,KAAM,mBAAaS,oCAAmBC,0BAGlDV,yBA4BeY,uBAEf,CACHC,SA5BkBA,QA4BQD,eAAeC,QAvBtCA,QAAQC,KAAKC,UACK,YAAjBA,QAAQC,OACSD,QAAQd,MAAMG,MAAK,CAACC,KAAMC,UAEnCD,KAAKE,MAAM,qBACXQ,QAAQd,MAAMO,OAAOF,MAAQ,EAAG,EAAGG,wBAAiBC,0BAC7C,MAMXK,QAAQd,MAAMgB,QAAQR,wBAAiBC,0BAIxCK,YAQPf,KAAMD,cAAca,eAAeZ,OA7BjBa,IAAAA"}
|
10
lib/editor/tiny/plugins/recordrtc/amd/build/modal.min.js
vendored
Normal file
10
lib/editor/tiny/plugins/recordrtc/amd/build/modal.min.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
define("tiny_recordrtc/modal",["exports","core/modal"],(function(_exports,_modal){var obj;
|
||||
/**
|
||||
* Abstract Recording Modal for TinyMCE's RecordRTC plugin.
|
||||
*
|
||||
* @module tiny_recordrtc/modal
|
||||
* @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal=(obj=_modal)&&obj.__esModule?obj:{default:obj};class _default extends _modal.default{registerEventListeners(){this.setRemoveOnClose(!0),super.registerEventListeners(),this.registerCloseOnSave(),this.registerCloseOnCancel()}}return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=modal.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"modal.min.js","sources":["../src/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 * Abstract Recording Modal for TinyMCE's RecordRTC plugin.\n *\n * @module tiny_recordrtc/modal\n * @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Modal from 'core/modal';\n\nexport default class extends Modal {\n registerEventListeners() {\n // Remove this Modal when it is closed.\n // This must be called before registering any other event listeners.\n this.setRemoveOnClose(true);\n\n // Call the parent registration.\n super.registerEventListeners();\n\n // Register to close on save/cancel.\n this.registerCloseOnSave();\n this.registerCloseOnCancel();\n }\n}\n"],"names":["Modal","registerEventListeners","setRemoveOnClose","registerCloseOnSave","registerCloseOnCancel"],"mappings":";;;;;;;kKAyB6BA,eACzBC,8BAGSC,kBAAiB,SAGhBD,8BAGDE,2BACAC"}
|
11
lib/editor/tiny/plugins/recordrtc/amd/build/options.min.js
vendored
Normal file
11
lib/editor/tiny/plugins/recordrtc/amd/build/options.min.js
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
define("tiny_recordrtc/options",["exports","./common"],(function(_exports,_common){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.register=_exports.getData=void 0;
|
||||
/**
|
||||
* Options helper for Tiny Record RTC plugin.
|
||||
*
|
||||
* @module tiny_recordrtc/options
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const dataName="".concat(_common.pluginName,":data");_exports.register=editor=>{(0,editor.options.register)(dataName,{processor:"object"})};_exports.getData=editor=>editor.options.get(dataName)}));
|
||||
|
||||
//# sourceMappingURL=options.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"options.min.js","sources":["../src/options.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 * Options helper for Tiny Record RTC plugin.\n *\n * @module tiny_recordrtc/options\n * @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {pluginName} from './common';\n\nconst dataName = `${pluginName}:data`;\n\nexport const register = (editor) => {\n const registerOption = editor.options.register;\n\n registerOption(dataName, {\n processor: 'object',\n });\n};\n\nexport const getData = (editor) => editor.options.get(dataName);\n"],"names":["dataName","pluginName","editor","registerOption","options","register","processor","get"],"mappings":";;;;;;;;MAyBMA,mBAAcC,8CAEKC,UAGrBC,EAFuBD,OAAOE,QAAQC,UAEvBL,SAAU,CACrBM,UAAW,6BAIKJ,QAAWA,OAAOE,QAAQG,IAAIP"}
|
10
lib/editor/tiny/plugins/recordrtc/amd/build/plugin.min.js
vendored
Normal file
10
lib/editor/tiny/plugins/recordrtc/amd/build/plugin.min.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
define("tiny_recordrtc/plugin",["exports","editor_tiny/loader","editor_tiny/utils","./commands_audio","./commands_video","./configuration","./options","./common"],(function(_exports,_loader,_utils,_commands_audio,_commands_video,Configuration,Options,_common){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}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Tiny Record RTC plugin for Moodle.
|
||||
*
|
||||
* @module tiny_recordrtc/plugin
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_commands_audio=_interopRequireDefault(_commands_audio),_commands_video=_interopRequireDefault(_commands_video),Configuration=_interopRequireWildcard(Configuration),Options=_interopRequireWildcard(Options);var _default=new Promise((async resolve=>{const[tinyMCE,setupAudioCommands,setupVideoCommands,pluginMetadata]=await Promise.all([(0,_loader.getTinyMCE)(),(0,_commands_audio.default)(),(0,_commands_video.default)(),(0,_utils.getPluginMetadata)(_common.component,_common.pluginName)]);tinyMCE.PluginManager.add("".concat(_common.component,"/plugin"),(editor=>(Options.register(editor),setupVideoCommands(editor),setupAudioCommands(editor),pluginMetadata))),resolve(["".concat(_common.component,"/plugin"),Configuration])}));return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=plugin.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"plugin.min.js","sources":["../src/plugin.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 * Tiny Record RTC plugin for Moodle.\n *\n * @module tiny_recordrtc/plugin\n * @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {getTinyMCE} from 'editor_tiny/loader';\nimport {getPluginMetadata} from 'editor_tiny/utils';\nimport getSetupAudioCommands from './commands_audio';\nimport getSetupVideoCommands from './commands_video';\nimport * as Configuration from './configuration';\nimport * as Options from './options';\nimport {\n component,\n pluginName\n} from './common';\n\nexport default new Promise(async(resolve) => {\n const [\n tinyMCE,\n setupAudioCommands,\n setupVideoCommands,\n pluginMetadata,\n ] = await Promise.all([\n getTinyMCE(),\n getSetupAudioCommands(),\n getSetupVideoCommands(),\n getPluginMetadata(component, pluginName),\n ]);\n\n tinyMCE.PluginManager.add(`${component}/plugin`, (editor) => {\n // Register options.\n Options.register(editor);\n\n // Setup the Commands (buttons, menu items, and so on) for video.\n setupVideoCommands(editor);\n\n // Setup the Commands (buttons, menu items, and so on) for audio.\n setupAudioCommands(editor);\n\n return pluginMetadata;\n });\n\n // Resolve the Media Plugin and include configuration.\n resolve([`${component}/plugin`, Configuration]);\n});\n"],"names":["Promise","async","tinyMCE","setupAudioCommands","setupVideoCommands","pluginMetadata","all","component","pluginName","PluginManager","add","editor","Options","register","resolve","Configuration"],"mappings":";;;;;;;gTAiCe,IAAIA,SAAQC,MAAAA,gBAEnBC,QACAC,mBACAC,mBACAC,sBACML,QAAQM,IAAI,EAClB,yBACA,8BACA,8BACA,4BAAkBC,kBAAWC,sBAGjCN,QAAQO,cAAcC,cAAOH,8BAAqBI,SAE9CC,QAAQC,SAASF,QAGjBP,mBAAmBO,QAGnBR,mBAAmBQ,QAEZN,kBAIXS,QAAQ,WAAIP,6BAAoBQ"}
|
3
lib/editor/tiny/plugins/recordrtc/amd/build/video_recorder.min.js
vendored
Normal file
3
lib/editor/tiny/plugins/recordrtc/amd/build/video_recorder.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
define("tiny_recordrtc/video_recorder",["exports","./base_recorder","tiny_recordrtc/modal","core/modal_registry","tiny_recordrtc/common"],(function(_exports,_base_recorder,_modal,_modal_registry,_common){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_base_recorder=_interopRequireDefault(_base_recorder),_modal=_interopRequireDefault(_modal),_modal_registry=_interopRequireDefault(_modal_registry);class Video extends _base_recorder.default{configurePlayer(){return this.modalRoot.querySelector("video")}getSupportedTypes(){return["video/webm;codecs=vp9,opus","video/webm;codecs=h264,opus","video/webm;codecs=vp8,opus"]}getParsedRecordingOptions(){return{audioBitsPerSecond:parseInt(this.config.audiobitrate),videoBitsPerSecond:parseInt(this.config.videobitrate)}}getMediaConstraints(){return{audio:!0,video:{width:{ideal:640},height:{ideal:480}}}}playOnCapture(){return!0}getRecordingType(){return"video"}getTimeLimit(){return this.config.videotimelimit}getEmbedTemplateName(){return"tiny_recordrtc/embed_video"}getFileName(prefix){return"".concat(prefix,"-video.webm")}static getModalClass(){var _class;const modalType="".concat(_common.component,"/video_recorder"),registration=_modal_registry.default.get(modalType);if(registration)return registration.module;const VideoModal=(_defineProperty(_class=class extends _modal.default{},"TYPE",modalType),_defineProperty(_class,"TEMPLATE","".concat(_common.component,"/video_recorder")),_class);return _modal_registry.default.register(VideoModal.TYPE,VideoModal,VideoModal.TEMPLATE),VideoModal}}return _exports.default=Video,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=video_recorder.min.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"video_recorder.min.js","sources":["../src/video_recorder.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 * Tiny Record RTC - Video recorder configuration.\n *\n * @module tiny_recordrtc/video\n * @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport BaseClass from './base_recorder';\nimport Modal from 'tiny_recordrtc/modal';\nimport ModalRegistry from 'core/modal_registry';\nimport {component} from 'tiny_recordrtc/common';\n\nexport default class Video extends BaseClass {\n configurePlayer() {\n return this.modalRoot.querySelector('video');\n }\n\n getSupportedTypes() {\n return [\n 'video/webm;codecs=vp9,opus',\n 'video/webm;codecs=h264,opus',\n 'video/webm;codecs=vp8,opus',\n ];\n\n }\n\n getParsedRecordingOptions() {\n return {\n audioBitsPerSecond: parseInt(this.config.audiobitrate),\n videoBitsPerSecond: parseInt(this.config.videobitrate)\n };\n }\n\n getMediaConstraints() {\n return {\n audio: true,\n video: {\n width: {\n ideal: 640,\n },\n height: {\n ideal: 480,\n },\n },\n };\n }\n\n playOnCapture() {\n // Play the recording back on capture.\n return true;\n }\n\n getRecordingType() {\n return 'video';\n }\n\n getTimeLimit() {\n return this.config.videotimelimit;\n }\n\n getEmbedTemplateName() {\n return 'tiny_recordrtc/embed_video';\n }\n\n getFileName(prefix) {\n return `${prefix}-video.webm`;\n }\n\n static getModalClass() {\n const modalType = `${component}/video_recorder`;\n const registration = ModalRegistry.get(modalType);\n if (registration) {\n return registration.module;\n }\n\n const VideoModal = class extends Modal {\n static TYPE = modalType;\n static TEMPLATE = `${component}/video_recorder`;\n };\n\n ModalRegistry.register(VideoModal.TYPE, VideoModal, VideoModal.TEMPLATE);\n return VideoModal;\n }\n}\n"],"names":["Video","BaseClass","configurePlayer","this","modalRoot","querySelector","getSupportedTypes","getParsedRecordingOptions","audioBitsPerSecond","parseInt","config","audiobitrate","videoBitsPerSecond","videobitrate","getMediaConstraints","audio","video","width","ideal","height","playOnCapture","getRecordingType","getTimeLimit","videotimelimit","getEmbedTemplateName","getFileName","prefix","modalType","component","registration","ModalRegistry","get","module","VideoModal","Modal","register","TYPE","TEMPLATE"],"mappings":"4qBA4BqBA,cAAcC,uBAC/BC,yBACWC,KAAKC,UAAUC,cAAc,SAGxCC,0BACW,CACH,6BACA,8BACA,8BAKRC,kCACW,CACHC,mBAAoBC,SAASN,KAAKO,OAAOC,cACzCC,mBAAoBH,SAASN,KAAKO,OAAOG,eAIjDC,4BACW,CACHC,OAAO,EACPC,MAAO,CACHC,MAAO,CACHC,MAAO,KAEXC,OAAQ,CACJD,MAAO,OAMvBE,uBAEW,EAGXC,yBACW,QAGXC,sBACWnB,KAAKO,OAAOa,eAGvBC,6BACW,6BAGXC,YAAYC,wBACEA,8DAIJC,oBAAeC,qCACfC,aAAeC,wBAAcC,IAAIJ,cACnCE,oBACOA,aAAaG,aAGlBC,mCAAa,cAAcC,wBACfP,uDACOC,6EAGXO,SAASF,WAAWG,KAAMH,WAAYA,WAAWI,UACxDJ"}
|
84
lib/editor/tiny/plugins/recordrtc/amd/src/audio_recorder.js
Normal file
84
lib/editor/tiny/plugins/recordrtc/amd/src/audio_recorder.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny Record RTC - audio recorder configuration.
|
||||
*
|
||||
* @module tiny_recordrtc/audio
|
||||
* @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BaseClass from './base_recorder';
|
||||
import Modal from './modal';
|
||||
import ModalRegistry from 'core/modal_registry';
|
||||
import {component} from 'tiny_recordrtc/common';
|
||||
|
||||
export default class Audio extends BaseClass {
|
||||
configurePlayer() {
|
||||
return this.modalRoot.querySelector('audio');
|
||||
}
|
||||
|
||||
getSupportedTypes() {
|
||||
return [
|
||||
'audio/webm;codecs=opus',
|
||||
'audio/ogg;codecs=opus',
|
||||
];
|
||||
}
|
||||
|
||||
getParsedRecordingOptions() {
|
||||
return {
|
||||
audioBitsPerSecond: parseInt(this.config.audiobitrate),
|
||||
};
|
||||
}
|
||||
|
||||
getMediaConstraints() {
|
||||
return {
|
||||
audio: true,
|
||||
};
|
||||
}
|
||||
|
||||
getRecordingType() {
|
||||
return 'audio';
|
||||
}
|
||||
|
||||
getTimeLimit() {
|
||||
return this.config.audiotimelimit;
|
||||
}
|
||||
|
||||
getEmbedTemplateName() {
|
||||
return 'tiny_recordrtc/embed_audio';
|
||||
}
|
||||
|
||||
getFileName(prefix) {
|
||||
return `${prefix}-audio.ogg`;
|
||||
}
|
||||
|
||||
static getModalClass() {
|
||||
const modalType = `${component}/audio_recorder`;
|
||||
const registration = ModalRegistry.get(modalType);
|
||||
if (registration) {
|
||||
return registration.module;
|
||||
}
|
||||
|
||||
const AudioModal = class extends Modal {
|
||||
static TYPE = modalType;
|
||||
static TEMPLATE = `${component}/audio_recorder`;
|
||||
};
|
||||
|
||||
ModalRegistry.register(AudioModal.TYPE, AudioModal, AudioModal.TEMPLATE);
|
||||
return AudioModal;
|
||||
}
|
||||
}
|
840
lib/editor/tiny/plugins/recordrtc/amd/src/base_recorder.js
Normal file
840
lib/editor/tiny/plugins/recordrtc/amd/src/base_recorder.js
Normal file
|
@ -0,0 +1,840 @@
|
|||
// 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/>.
|
||||
//
|
||||
|
||||
/**
|
||||
* Tiny Record RTC type.
|
||||
*
|
||||
* @module tiny_recordrtc/recording/base
|
||||
* @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {get_string as getString, get_strings as getStrings} from 'core/str';
|
||||
import {component} from './common';
|
||||
import Pending from 'core/pending';
|
||||
import {getData} from './options';
|
||||
import uploadFile from 'editor_tiny/uploader';
|
||||
import {add as addToast} from 'core/toast';
|
||||
import * as ModalEvents from 'core/modal_events';
|
||||
import * as ModalFactory from 'core/modal_factory';
|
||||
import * as Templates from 'core/templates';
|
||||
import {saveCancelPromise} from 'core/notification';
|
||||
import {prefetchStrings, prefetchTemplates} from 'core/prefetch';
|
||||
|
||||
/**
|
||||
* The RecordRTC base class for audio, video, and any other future types
|
||||
*/
|
||||
export default class {
|
||||
|
||||
stopRequested = false;
|
||||
|
||||
/**
|
||||
* Constructor for the RecordRTC class
|
||||
*
|
||||
* @param {TinyMCE} editor The Editor to which the content will be inserted
|
||||
* @param {Modal} modal The Moodle Modal that contains the interface used for recording
|
||||
*/
|
||||
constructor(editor, modal) {
|
||||
this.ready = false;
|
||||
|
||||
if (!this.checkAndWarnAboutBrowserCompatibility()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.editor = editor;
|
||||
this.config = getData(editor).params;
|
||||
this.modal = modal;
|
||||
this.modalRoot = modal.getRoot()[0];
|
||||
this.startStopButton = this.modalRoot.querySelector('button[data-action="startstop"]');
|
||||
this.uploadButton = this.modalRoot.querySelector('button[data-action="upload"]');
|
||||
|
||||
// Disable the record button untilt he stream is acquired.
|
||||
this.setRecordButtonState(false);
|
||||
|
||||
this.player = this.configurePlayer();
|
||||
this.registerEventListeners();
|
||||
this.ready = true;
|
||||
|
||||
this.captureUserMedia();
|
||||
this.prefetchContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the browser is compatible.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isReady() {
|
||||
return this.ready;
|
||||
}
|
||||
|
||||
// Disable eslint's valid-jsdoc rule as the following methods are abstract and mnust be overridden by the child class.
|
||||
|
||||
/* eslint-disable valid-jsdoc, no-unused-vars */
|
||||
|
||||
/**
|
||||
* Get the Player element for this type.
|
||||
*
|
||||
* @returns {HTMLElement} The player element, typically an audio or video tag.
|
||||
*/
|
||||
configurePlayer() {
|
||||
throw new Error(`configurePlayer() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of supported mimetypes for this recorder.
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/isTypeSupported}
|
||||
*
|
||||
* @returns {string[]} The list of supported mimetypes.
|
||||
*/
|
||||
getSupportedTypes() {
|
||||
throw new Error(`getSupportedTypes() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any recording options passed into the MediaRecorder.
|
||||
* Please note that the mimeType will be fetched from {@link getSupportedTypes()}.
|
||||
*
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder#options}
|
||||
* @returns {Object}
|
||||
*/
|
||||
getRecordingOptions() {
|
||||
throw new Error(`getRecordingOptions() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a filename for the generated file.
|
||||
*
|
||||
* Typically this function will take a prefix and add a type-specific suffix such as the extension to it.
|
||||
*
|
||||
* @param {string} prefix The prefix for the filename generated by the recorder.
|
||||
* @returns {string}
|
||||
*/
|
||||
getFileName(prefix) {
|
||||
throw new Error(`getFileName() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of constraints as required by the getUserMedia() function.
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#constraints}
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
getMediaConstraints() {
|
||||
throw new Error(`getMediaConstraints() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to start playing the recording as it is captured.
|
||||
* @returns {boolean} Whether to start playing the recording as it is captured.
|
||||
*/
|
||||
playOnCapture() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time limit for this recording type.
|
||||
*
|
||||
* @returns {number} The time limit in seconds.
|
||||
*/
|
||||
getTimeLimit() {
|
||||
throw new Error(`getTimeLimit() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the template used when embedding the URL in the editor content.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getEmbedTemplateName() {
|
||||
throw new Error(`getEmbedTemplateName() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the Class of the Modal to be displayed.
|
||||
*
|
||||
* @returns {Modal}
|
||||
*/
|
||||
static getModalClass() {
|
||||
throw new Error(`getModalClass() must be implemented in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
/* eslint-enable valid-jsdoc, no-unused-vars */
|
||||
|
||||
/**
|
||||
* Get the options for the MediaRecorder.
|
||||
*
|
||||
* @returns {object} The options for the MediaRecorder instance.
|
||||
*/
|
||||
getParsedRecordingOptions() {
|
||||
const types = this.getSupportedTypes();
|
||||
const options = this.getParsedRecordingOptions();
|
||||
const compatTypes = types.filter((type) => window.MediaRecorder.isTypeSupported(type));
|
||||
|
||||
if (compatTypes.length !== 0) {
|
||||
options.mimeType = compatTypes[0];
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start capturing the User Media and handle success or failure of the capture.
|
||||
*/
|
||||
async captureUserMedia() {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia(this.getMediaConstraints());
|
||||
this.handleCaptureSuccess(stream);
|
||||
} catch (error) {
|
||||
this.handleCaptureFailure(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch some of the content that will be used in the UI.
|
||||
*
|
||||
* Note: not all of the strings used are pre-fetched.
|
||||
* Some of the strings will be fetched because their template is used.
|
||||
*/
|
||||
prefetchContent() {
|
||||
prefetchStrings(component, [
|
||||
'uploading',
|
||||
'recordagain_title',
|
||||
'recordagain_desc',
|
||||
'discard_title',
|
||||
'discard_desc',
|
||||
'confirm_yes',
|
||||
'recordinguploaded',
|
||||
'maxfilesizehit',
|
||||
'maxfilesizehit_title',
|
||||
'uploadfailed',
|
||||
]);
|
||||
|
||||
prefetchTemplates([
|
||||
this.getEmbedTemplateName(),
|
||||
'tiny_recordrtc/timeremaining',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an error message to the user.
|
||||
*
|
||||
* @param {Promise<string>} title The error title
|
||||
* @param {Promise<string>} content The error message
|
||||
* @returns {Promise<Modal>}
|
||||
*/
|
||||
async displayAlert(title, content) {
|
||||
const pendingPromise = new Pending('core/confirm:alert');
|
||||
const ModalFactory = await import('core/modal_factory');
|
||||
const modal = await ModalFactory.create({
|
||||
type: ModalFactory.types.ALERT,
|
||||
title: title,
|
||||
body: content,
|
||||
removeOnClose: true,
|
||||
});
|
||||
|
||||
modal.show();
|
||||
pendingPromise.resolve();
|
||||
|
||||
return modal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle successful capture of the User Media.
|
||||
*
|
||||
* @param {MediaStream} stream The stream as captured by the User Media.
|
||||
*/
|
||||
handleCaptureSuccess(stream) {
|
||||
// Set audio player source to microphone stream.
|
||||
this.player.srcObject = stream;
|
||||
|
||||
if (this.playOnCapture()) {
|
||||
// Mute audio, distracting while recording.
|
||||
this.player.muted = true;
|
||||
|
||||
this.player.play();
|
||||
}
|
||||
|
||||
this.stream = stream;
|
||||
this.setupPlayerSource();
|
||||
this.setRecordButtonState(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the player to use the stream as a source.
|
||||
*/
|
||||
setupPlayerSource() {
|
||||
if (!this.player.srcObject) {
|
||||
this.player.srcObject = this.stream;
|
||||
|
||||
// Mute audio, distracting while recording.
|
||||
this.player.muted = true;
|
||||
|
||||
this.player.play();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the record button.
|
||||
*
|
||||
* @param {boolean|null} enabled Set the button state
|
||||
*/
|
||||
setRecordButtonState(enabled) {
|
||||
this.startStopButton.disabled = !enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure button visibility for the record button.
|
||||
*
|
||||
* @param {boolean} visible Set the visibility of the button.
|
||||
*/
|
||||
setRecordButtonVisibility(visible) {
|
||||
const container = this.getButtonContainer('start-stop');
|
||||
container.classList.toggle('hide', !visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the upload button.
|
||||
*
|
||||
* @param {boolean|null} enabled Set the button state
|
||||
*/
|
||||
setUploadButtonState(enabled) {
|
||||
this.uploadButton.disabled = !enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure button visibility for the upload button.
|
||||
*
|
||||
* @param {boolean} visible Set the visibility of the button.
|
||||
*/
|
||||
setUploadButtonVisibility(visible) {
|
||||
const container = this.getButtonContainer('upload');
|
||||
container.classList.toggle('hide', !visible);
|
||||
}
|
||||
/**
|
||||
* Handle failure to capture the User Media.
|
||||
*
|
||||
* @param {Error} error
|
||||
*/
|
||||
handleCaptureFailure(error) {
|
||||
// Changes 'CertainError' -> 'gumcertain' to match language string names.
|
||||
var subject = `gum${error.name.replace('Error', '').toLowerCase()}`;
|
||||
this.displayAlert(
|
||||
getString(`${subject}_title`, component),
|
||||
getString(subject, component)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the modal and stop recording.
|
||||
*/
|
||||
close() {
|
||||
// Closing the modal will destroy it and remove it from the DOM.
|
||||
// It will also stop the recording via the hidden Modal Event.
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register event listeners for the modal.
|
||||
*/
|
||||
registerEventListeners() {
|
||||
this.modalRoot.addEventListener('click', this.handleModalClick.bind(this));
|
||||
this.modal.getRoot().on(ModalEvents.outsideClick, this.outsideClickHandler.bind(this));
|
||||
this.modal.getRoot().on(ModalEvents.hidden, () => {
|
||||
this.cleanupStream();
|
||||
this.requestRecordingStop();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent the Modal from closing when recording is on process.
|
||||
*
|
||||
* @param {MouseEvent} event The click event
|
||||
*/
|
||||
async outsideClickHandler(event) {
|
||||
if (this.isRecording()) {
|
||||
// The user is recording.
|
||||
// Do not distract with a confirmation, just prevent closing.
|
||||
event.preventDefault();
|
||||
} else if (this.hasData()) {
|
||||
// If there is a blobsize then there is data that may be lost.
|
||||
// Ask the user to confirm they want to close the modal.
|
||||
// We prevent default here, and then close the modal if they confirm.
|
||||
event.preventDefault();
|
||||
|
||||
try {
|
||||
await saveCancelPromise(
|
||||
await getString("discard_title", component),
|
||||
await getString("discard_desc", component),
|
||||
await getString("confirm_yes", component),
|
||||
);
|
||||
this.modal.hide();
|
||||
} catch (error) {
|
||||
// Do nothing, the modal will not close.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a click within the Modal.
|
||||
*
|
||||
* @param {MouseEvent} event The click event
|
||||
*/
|
||||
handleModalClick(event) {
|
||||
const button = event.target.closest('button');
|
||||
if (button && button.dataset.action) {
|
||||
const action = button.dataset.action;
|
||||
if (action === 'startstop') {
|
||||
this.handleRecordingStartStopRequested();
|
||||
}
|
||||
|
||||
if (action === 'upload') {
|
||||
this.uploadRecording();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the click event for the recording start/stop button.
|
||||
*/
|
||||
handleRecordingStartStopRequested() {
|
||||
if (this.mediaRecorder?.state === 'recording') {
|
||||
this.requestRecordingStop();
|
||||
} else {
|
||||
this.startRecording();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the media stream after it has finished.
|
||||
*/
|
||||
async onMediaStopped() {
|
||||
// Set source of audio player.
|
||||
this.blob = new Blob(this.data.chunks, {
|
||||
type: this.mediaRecorder.mimeType
|
||||
});
|
||||
this.player.srcObject = null;
|
||||
this.player.src = URL.createObjectURL(this.blob);
|
||||
|
||||
// Change the label to "Record again".
|
||||
this.setRecordButtonTextFromString('recordagain');
|
||||
|
||||
// Show audio player with controls enabled, and unmute.
|
||||
this.player.muted = false;
|
||||
this.player.controls = true;
|
||||
this.getButtonContainer('player')?.classList.toggle('hide', false);
|
||||
|
||||
// Show upload button.
|
||||
this.setUploadButtonVisibility(true);
|
||||
this.setUploadButtonState(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the recording and insert it into the editor content.
|
||||
*/
|
||||
async uploadRecording() {
|
||||
// Trigger error if no recording has been made.
|
||||
if (this.data.chunks.length === 0) {
|
||||
this.displayAlert('norecordingfound');
|
||||
return;
|
||||
}
|
||||
|
||||
const fileName = this.getFileName((Math.random() * 1000).toString().replace('.', ''));
|
||||
|
||||
// Upload recording to server.
|
||||
try {
|
||||
// Once uploading starts, do not allow any further changes to the recording.
|
||||
this.setRecordButtonVisibility(false);
|
||||
|
||||
// Disable the upload button.
|
||||
this.setUploadButtonState(false);
|
||||
|
||||
// Upload the recording.
|
||||
const fileURL = await uploadFile(this.editor, 'media', this.blob, fileName, (progress) => {
|
||||
this.setUploadButtonTextProgress(progress);
|
||||
});
|
||||
this.insertMedia(fileURL);
|
||||
this.close();
|
||||
addToast(await getString('recordinguploaded', component));
|
||||
} catch (error) {
|
||||
// Show a toast and unhide the button.
|
||||
this.setUploadButtonState(true);
|
||||
|
||||
addToast(await getString('uploadfailed', component, {error}), {
|
||||
type: 'error',
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the container that a button is in.
|
||||
*
|
||||
* @param {string} purpose The button purpose
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
getButtonContainer(purpose) {
|
||||
return this.modalRoot.querySelector(`[data-purpose="${purpose}-container"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the browser is compatible with capturing media.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isBrowserCompatible() {
|
||||
return this.checkSecure() && this.hasUserMedia();
|
||||
}
|
||||
|
||||
static async display(editor) {
|
||||
const ModalClass = this.getModalClass();
|
||||
const modal = await ModalFactory.create({
|
||||
type: ModalClass.TYPE,
|
||||
templateContext: {},
|
||||
large: true,
|
||||
});
|
||||
|
||||
// Set up the VideoRecorder.
|
||||
const recorder = new this(editor, modal);
|
||||
if (recorder.isReady()) {
|
||||
modal.show();
|
||||
}
|
||||
return modal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the browser is compatible with capturing media, and display a warning if not.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
checkAndWarnAboutBrowserCompatibility() {
|
||||
if (!this.constructor.checkSecure()) {
|
||||
getStrings(['insecurealert_title', 'insecurealert'].map((key) => ({key, component})))
|
||||
.then(([title, message]) => addToast(message, {title, type: 'error'}))
|
||||
.catch();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.constructor.hasUserMedia) {
|
||||
getStrings(['nowebrtc_title', 'nowebrtc'].map((key) => ({key, component})))
|
||||
.then(([title, message]) => addToast(message, {title, type: 'error'}))
|
||||
.catch();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the browser supports WebRTC.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static hasUserMedia() {
|
||||
return (navigator.mediaDevices && window.MediaRecorder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the hostname is either hosted over SSL, or from a valid localhost hostname.
|
||||
*
|
||||
* The UserMedia API can only be used in secure contexts as noted.
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#privacy_and_security}
|
||||
*
|
||||
* @returns {boolean} Whether the plugin can be loaded.
|
||||
*/
|
||||
static checkSecure() {
|
||||
// Note: We can now use window.isSecureContext.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#feature_detection
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/isSecureContext
|
||||
return window.isSecureContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the content of the stop recording button timer.
|
||||
*/
|
||||
async setStopRecordingButton() {
|
||||
const {html, js} = await Templates.renderForPromise('tiny_recordrtc/timeremaining', this.getTimeRemaining());
|
||||
Templates.replaceNodeContents(this.startStopButton, html, js);
|
||||
this.buttonTimer = setInterval(this.updateRecordButtonTime.bind(this), 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the time on the stop recording button.
|
||||
*/
|
||||
updateRecordButtonTime() {
|
||||
const {remaining, minutes, seconds} = this.getTimeRemaining();
|
||||
if (remaining < 0) {
|
||||
this.requestRecordingStop();
|
||||
} else {
|
||||
this.startStopButton.querySelector('[data-type="minutes"]').textContent = minutes;
|
||||
this.startStopButton.querySelector('[data-type="seconds"]').textContent = seconds;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text of the record button using a language string.
|
||||
*
|
||||
* @param {string} string The string identifier
|
||||
*/
|
||||
async setRecordButtonTextFromString(string) {
|
||||
this.startStopButton.textContent = await getString(string, component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upload button text progress.
|
||||
*
|
||||
* @param {number} progress The progress
|
||||
*/
|
||||
async setUploadButtonTextProgress(progress) {
|
||||
this.uploadButton.textContent = await getString('uploading', component, {
|
||||
progress: Math.round(progress * 100) / 100,
|
||||
});
|
||||
}
|
||||
|
||||
async resetUploadButtonText() {
|
||||
this.uploadButton.textContent = await getString('upload', component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the timer for the stop recording button.
|
||||
*/
|
||||
clearButtonTimer() {
|
||||
if (this.buttonTimer) {
|
||||
clearInterval(this.buttonTimer);
|
||||
}
|
||||
this.buttonTimer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time remaining for the recording.
|
||||
*
|
||||
* @returns {Object} The minutes and seconds remaining.
|
||||
*/
|
||||
getTimeRemaining() {
|
||||
// All times are in milliseconds
|
||||
const now = new Date().getTime();
|
||||
const remaining = Math.floor(this.getTimeLimit() - ((now - this.startTime) / 1000));
|
||||
|
||||
const formatter = new Intl.NumberFormat(navigator.language, {minimumIntegerDigits: 2});
|
||||
const seconds = formatter.format(remaining % 60);
|
||||
const minutes = formatter.format(Math.floor((remaining - seconds) / 60));
|
||||
return {
|
||||
remaining,
|
||||
minutes,
|
||||
seconds,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum file size that can be uploaded.
|
||||
*
|
||||
* @returns {number} The max byte size
|
||||
*/
|
||||
getMaxUploadSize() {
|
||||
return this.config.maxrecsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the recording.
|
||||
* Please note that this should only stop the recording.
|
||||
* Anything related to processing the recording should be handled by the
|
||||
* mediaRecorder's stopped event handler which is processed after it has stopped.
|
||||
*/
|
||||
requestRecordingStop() {
|
||||
if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
|
||||
this.stopRequested = true;
|
||||
} else {
|
||||
// There is no recording to stop, but the stream must still be cleaned up.
|
||||
this.cleanupStream();
|
||||
}
|
||||
}
|
||||
|
||||
stopRecorder() {
|
||||
this.mediaRecorder.stop();
|
||||
|
||||
// Unmute the player so that the audio is heard during playback.
|
||||
this.player.muted = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the stream.
|
||||
*
|
||||
* This involves stopping any track which is still active.
|
||||
*/
|
||||
cleanupStream() {
|
||||
if (this.stream) {
|
||||
this.stream.getTracks()
|
||||
.filter((track) => track.readyState !== 'ended')
|
||||
.forEach((track) => track.stop());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the mediaRecorder `stop` event.
|
||||
*/
|
||||
handleStopped() {
|
||||
// Handle the stream data.
|
||||
this.onMediaStopped();
|
||||
|
||||
// Clear the button timer.
|
||||
this.clearButtonTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the mediaRecorder `start` event.
|
||||
*
|
||||
* This event is called when the recording starts.
|
||||
*/
|
||||
handleStarted() {
|
||||
this.startTime = new Date().getTime();
|
||||
this.setStopRecordingButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the mediaRecorder `dataavailable` event.
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
handleDataAvailable(event) {
|
||||
if (this.isRecording()) {
|
||||
const newSize = this.data.blobSize + event.data.size;
|
||||
// Recording stops when either the maximum upload size is reached, or the time limit expires.
|
||||
// The time limit is checked in the `updateButtonTime` function.
|
||||
if (newSize >= this.getMaxUploadSize()) {
|
||||
this.stopRecorder();
|
||||
this.displayFileLimitHitMessage();
|
||||
} else {
|
||||
// Push recording slice to array.
|
||||
this.data.chunks.push(event.data);
|
||||
|
||||
// Size of all recorded data so far.
|
||||
this.data.blobSize = newSize;
|
||||
|
||||
if (this.stopRequested) {
|
||||
this.stopRecorder();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async displayFileLimitHitMessage() {
|
||||
addToast(await getString('maxfilesizehit', component), {
|
||||
title: await getString('maxfilesizehit_title', component),
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the recording is in progress.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isRecording() {
|
||||
return this.mediaRecorder?.state === 'recording';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether any data has been recorded.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasData() {
|
||||
return !!this.data?.blobSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the recording
|
||||
*/
|
||||
async startRecording() {
|
||||
if (this.mediaRecorder) {
|
||||
// Stop the existing recorder if it exists.
|
||||
if (this.isRecording()) {
|
||||
this.mediaRecorder.stop();
|
||||
}
|
||||
|
||||
if (this.hasData()) {
|
||||
const resetRecording = await this.recordAgainConfirmation();
|
||||
if (!resetRecording) {
|
||||
// User cancelled at the confirmation to reset the data, so exit early.
|
||||
return;
|
||||
}
|
||||
this.setUploadButtonVisibility(false);
|
||||
}
|
||||
|
||||
this.mediaRecorder = null;
|
||||
}
|
||||
|
||||
// The options for the recording codecs and bitrates.
|
||||
this.mediaRecorder = new MediaRecorder(this.stream, this.getParsedRecordingOptions());
|
||||
|
||||
this.mediaRecorder.addEventListener('dataavailable', this.handleDataAvailable.bind(this));
|
||||
this.mediaRecorder.addEventListener('stop', this.handleStopped.bind(this));
|
||||
this.mediaRecorder.addEventListener('start', this.handleStarted.bind(this));
|
||||
|
||||
this.data = {
|
||||
chunks: [],
|
||||
blobSize: 0
|
||||
};
|
||||
this.setupPlayerSource();
|
||||
this.stopRequested = false;
|
||||
|
||||
// Capture in 50ms chunks.
|
||||
this.mediaRecorder.start(50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm whether the user wants to reset the existing recoring.
|
||||
*
|
||||
* @returns {Promise<boolean>} Whether the user confirmed the reset.
|
||||
*/
|
||||
async recordAgainConfirmation() {
|
||||
try {
|
||||
await saveCancelPromise(
|
||||
await getString("recordagain_title", component),
|
||||
await getString("recordagain_desc", component),
|
||||
await getString("confirm_yes", component)
|
||||
);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the HTML to embed the recording into the editor content.
|
||||
*
|
||||
* @param {string} source The URL to view the media.
|
||||
*/
|
||||
async insertMedia(source) {
|
||||
const {html} = await Templates.renderForPromise(
|
||||
this.getEmbedTemplateName(),
|
||||
this.getEmbedTemplateContext({
|
||||
source,
|
||||
})
|
||||
);
|
||||
this.editor.insertContent(html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or modify the template parameters for the specified type.
|
||||
*
|
||||
* @param {Object} templateContext The Tempalte context to use
|
||||
* @returns {Object} The finalised template context
|
||||
*/
|
||||
getEmbedTemplateContext(templateContext) {
|
||||
return templateContext;
|
||||
}
|
||||
}
|
62
lib/editor/tiny/plugins/recordrtc/amd/src/commands_audio.js
Normal file
62
lib/editor/tiny/plugins/recordrtc/amd/src/commands_audio.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny Record RTC - record audio command.
|
||||
*
|
||||
* @module tiny_recordrtc/recordAudioCommands
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {get_string as getString} from 'core/str';
|
||||
import {getButtonImage} from 'editor_tiny/utils';
|
||||
import {
|
||||
audioButtonName,
|
||||
component
|
||||
} from './common';
|
||||
import Recorder from './audio_recorder';
|
||||
|
||||
export default async() => {
|
||||
if (!Recorder.isBrowserCompatible()) {
|
||||
// The browser doesn't support the plugin, so just don't show it.
|
||||
return () => false;
|
||||
}
|
||||
|
||||
const [
|
||||
audioButtonTitle,
|
||||
audio,
|
||||
] = await Promise.all([
|
||||
getString('audiobuttontitle', component),
|
||||
getButtonImage('audio', component),
|
||||
]);
|
||||
|
||||
return (editor) => {
|
||||
const icon = 'audio';
|
||||
editor.ui.registry.addIcon(icon, audio.html);
|
||||
|
||||
editor.ui.registry.addButton(audioButtonName, {
|
||||
icon,
|
||||
tooltip: audioButtonTitle,
|
||||
onAction: () => Recorder.display(editor),
|
||||
});
|
||||
|
||||
editor.ui.registry.addMenuItem(audioButtonName, {
|
||||
icon,
|
||||
text: audioButtonTitle,
|
||||
onAction: () => Recorder.display(editor),
|
||||
});
|
||||
};
|
||||
};
|
62
lib/editor/tiny/plugins/recordrtc/amd/src/commands_video.js
Normal file
62
lib/editor/tiny/plugins/recordrtc/amd/src/commands_video.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny Record RTC - record video command.
|
||||
*
|
||||
* @module tiny_recordrtc/recordVideoCommands
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {get_string as getString} from 'core/str';
|
||||
import {getButtonImage as getVideoIcon} from 'editor_tiny/utils';
|
||||
import {
|
||||
videoButtonName,
|
||||
component
|
||||
} from './common';
|
||||
import Recorder from './video_recorder';
|
||||
|
||||
export default async() => {
|
||||
if (!Recorder.isBrowserCompatible()) {
|
||||
// The browser doesn't support the plugin, so just don't show it.
|
||||
return () => false;
|
||||
}
|
||||
|
||||
const [
|
||||
videoButtonTitle,
|
||||
buttonImage,
|
||||
] = await Promise.all([
|
||||
getString('videobuttontitle', component),
|
||||
getVideoIcon('video', component),
|
||||
]);
|
||||
|
||||
return (editor) => {
|
||||
let icon = 'video';
|
||||
editor.ui.registry.addIcon(icon, buttonImage.html);
|
||||
|
||||
editor.ui.registry.addButton(videoButtonName, {
|
||||
icon,
|
||||
tooltip: videoButtonTitle,
|
||||
onAction: () => Recorder.display(editor),
|
||||
});
|
||||
|
||||
editor.ui.registry.addMenuItem(videoButtonName, {
|
||||
icon,
|
||||
text: videoButtonTitle,
|
||||
onAction: () => Recorder.display(editor),
|
||||
});
|
||||
};
|
||||
};
|
29
lib/editor/tiny/plugins/recordrtc/amd/src/common.js
Normal file
29
lib/editor/tiny/plugins/recordrtc/amd/src/common.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny Record RTC common values.
|
||||
*
|
||||
* @module tiny_recordrtc/common
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
export default {
|
||||
pluginName: 'tiny_recordrtc/plugin',
|
||||
component: 'tiny_recordrtc',
|
||||
audioButtonName: 'tiny_recordrtc_audio',
|
||||
videoButtonName: 'tiny_recordrtc_video'
|
||||
};
|
84
lib/editor/tiny/plugins/recordrtc/amd/src/configuration.js
Normal file
84
lib/editor/tiny/plugins/recordrtc/amd/src/configuration.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny Record RTC configuration.
|
||||
*
|
||||
* @module tiny_recordrtc/configuration
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {
|
||||
audioButtonName,
|
||||
videoButtonName
|
||||
} from './common';
|
||||
import {
|
||||
addMenubarItem,
|
||||
} from 'editor_tiny/utils';
|
||||
|
||||
const configureMenu = (menu) => {
|
||||
const items = menu.insert.items.split(' ');
|
||||
const inserted = items.some((item, index) => {
|
||||
// Append after the media or video button.
|
||||
if (item.match(/(media|video)\b/)) {
|
||||
items.splice(index + 1, 0, audioButtonName, videoButtonName);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (inserted) {
|
||||
menu.insert.items = items.join(' ');
|
||||
} else {
|
||||
addMenubarItem(menu, 'insert', `${audioButtonName} ${videoButtonName}`);
|
||||
}
|
||||
|
||||
return menu;
|
||||
};
|
||||
|
||||
const configureToolbar = (toolbar) => {
|
||||
// The toolbar contains an array of named sections.
|
||||
// The Moodle integration ensures that there is a section called 'content'.
|
||||
|
||||
|
||||
return toolbar.map((section) => {
|
||||
if (section.name === 'content') {
|
||||
const inserted = section.items.some((item, index) => {
|
||||
// Append after the media or video button.
|
||||
if (item.match(/(media|video)\b/)) {
|
||||
section.items.splice(index + 1, 0, audioButtonName, videoButtonName);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!inserted) {
|
||||
section.items.unshift(audioButtonName, videoButtonName);
|
||||
}
|
||||
}
|
||||
|
||||
return section;
|
||||
});
|
||||
};
|
||||
|
||||
export const configure = (instanceConfig) => {
|
||||
// Update the instance configuration to add the Media menu option to the menus and toolbars and upload_handler.
|
||||
return {
|
||||
toolbar: configureToolbar(instanceConfig.toolbar),
|
||||
menu: configureMenu(instanceConfig.menu),
|
||||
};
|
||||
};
|
39
lib/editor/tiny/plugins/recordrtc/amd/src/modal.js
Normal file
39
lib/editor/tiny/plugins/recordrtc/amd/src/modal.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Abstract Recording Modal for TinyMCE's RecordRTC plugin.
|
||||
*
|
||||
* @module tiny_recordrtc/modal
|
||||
* @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import Modal from 'core/modal';
|
||||
|
||||
export default class extends Modal {
|
||||
registerEventListeners() {
|
||||
// Remove this Modal when it is closed.
|
||||
// This must be called before registering any other event listeners.
|
||||
this.setRemoveOnClose(true);
|
||||
|
||||
// Call the parent registration.
|
||||
super.registerEventListeners();
|
||||
|
||||
// Register to close on save/cancel.
|
||||
this.registerCloseOnSave();
|
||||
this.registerCloseOnCancel();
|
||||
}
|
||||
}
|
36
lib/editor/tiny/plugins/recordrtc/amd/src/options.js
Normal file
36
lib/editor/tiny/plugins/recordrtc/amd/src/options.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Options helper for Tiny Record RTC plugin.
|
||||
*
|
||||
* @module tiny_recordrtc/options
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {pluginName} from './common';
|
||||
|
||||
const dataName = `${pluginName}:data`;
|
||||
|
||||
export const register = (editor) => {
|
||||
const registerOption = editor.options.register;
|
||||
|
||||
registerOption(dataName, {
|
||||
processor: 'object',
|
||||
});
|
||||
};
|
||||
|
||||
export const getData = (editor) => editor.options.get(dataName);
|
62
lib/editor/tiny/plugins/recordrtc/amd/src/plugin.js
Normal file
62
lib/editor/tiny/plugins/recordrtc/amd/src/plugin.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny Record RTC plugin for Moodle.
|
||||
*
|
||||
* @module tiny_recordrtc/plugin
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
import {getTinyMCE} from 'editor_tiny/loader';
|
||||
import {getPluginMetadata} from 'editor_tiny/utils';
|
||||
import getSetupAudioCommands from './commands_audio';
|
||||
import getSetupVideoCommands from './commands_video';
|
||||
import * as Configuration from './configuration';
|
||||
import * as Options from './options';
|
||||
import {
|
||||
component,
|
||||
pluginName
|
||||
} from './common';
|
||||
|
||||
export default new Promise(async(resolve) => {
|
||||
const [
|
||||
tinyMCE,
|
||||
setupAudioCommands,
|
||||
setupVideoCommands,
|
||||
pluginMetadata,
|
||||
] = await Promise.all([
|
||||
getTinyMCE(),
|
||||
getSetupAudioCommands(),
|
||||
getSetupVideoCommands(),
|
||||
getPluginMetadata(component, pluginName),
|
||||
]);
|
||||
|
||||
tinyMCE.PluginManager.add(`${component}/plugin`, (editor) => {
|
||||
// Register options.
|
||||
Options.register(editor);
|
||||
|
||||
// Setup the Commands (buttons, menu items, and so on) for video.
|
||||
setupVideoCommands(editor);
|
||||
|
||||
// Setup the Commands (buttons, menu items, and so on) for audio.
|
||||
setupAudioCommands(editor);
|
||||
|
||||
return pluginMetadata;
|
||||
});
|
||||
|
||||
// Resolve the Media Plugin and include configuration.
|
||||
resolve([`${component}/plugin`, Configuration]);
|
||||
});
|
100
lib/editor/tiny/plugins/recordrtc/amd/src/video_recorder.js
Normal file
100
lib/editor/tiny/plugins/recordrtc/amd/src/video_recorder.js
Normal 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/>.
|
||||
|
||||
/**
|
||||
* Tiny Record RTC - Video recorder configuration.
|
||||
*
|
||||
* @module tiny_recordrtc/video
|
||||
* @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import BaseClass from './base_recorder';
|
||||
import Modal from 'tiny_recordrtc/modal';
|
||||
import ModalRegistry from 'core/modal_registry';
|
||||
import {component} from 'tiny_recordrtc/common';
|
||||
|
||||
export default class Video extends BaseClass {
|
||||
configurePlayer() {
|
||||
return this.modalRoot.querySelector('video');
|
||||
}
|
||||
|
||||
getSupportedTypes() {
|
||||
return [
|
||||
'video/webm;codecs=vp9,opus',
|
||||
'video/webm;codecs=h264,opus',
|
||||
'video/webm;codecs=vp8,opus',
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
getParsedRecordingOptions() {
|
||||
return {
|
||||
audioBitsPerSecond: parseInt(this.config.audiobitrate),
|
||||
videoBitsPerSecond: parseInt(this.config.videobitrate)
|
||||
};
|
||||
}
|
||||
|
||||
getMediaConstraints() {
|
||||
return {
|
||||
audio: true,
|
||||
video: {
|
||||
width: {
|
||||
ideal: 640,
|
||||
},
|
||||
height: {
|
||||
ideal: 480,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
playOnCapture() {
|
||||
// Play the recording back on capture.
|
||||
return true;
|
||||
}
|
||||
|
||||
getRecordingType() {
|
||||
return 'video';
|
||||
}
|
||||
|
||||
getTimeLimit() {
|
||||
return this.config.videotimelimit;
|
||||
}
|
||||
|
||||
getEmbedTemplateName() {
|
||||
return 'tiny_recordrtc/embed_video';
|
||||
}
|
||||
|
||||
getFileName(prefix) {
|
||||
return `${prefix}-video.webm`;
|
||||
}
|
||||
|
||||
static getModalClass() {
|
||||
const modalType = `${component}/video_recorder`;
|
||||
const registration = ModalRegistry.get(modalType);
|
||||
if (registration) {
|
||||
return registration.module;
|
||||
}
|
||||
|
||||
const VideoModal = class extends Modal {
|
||||
static TYPE = modalType;
|
||||
static TEMPLATE = `${component}/video_recorder`;
|
||||
};
|
||||
|
||||
ModalRegistry.register(VideoModal.TYPE, VideoModal, VideoModal.TEMPLATE);
|
||||
return VideoModal;
|
||||
}
|
||||
}
|
122
lib/editor/tiny/plugins/recordrtc/classes/plugininfo.php
Normal file
122
lib/editor/tiny/plugins/recordrtc/classes/plugininfo.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
namespace tiny_recordrtc;
|
||||
|
||||
use context;
|
||||
use editor_tiny\editor;
|
||||
use editor_tiny\plugin;
|
||||
use editor_tiny\plugin_with_buttons;
|
||||
use editor_tiny\plugin_with_configuration;
|
||||
use editor_tiny\plugin_with_menuitems;
|
||||
|
||||
/**
|
||||
* Tiny RecordRTC plugin.
|
||||
*
|
||||
* @package tiny_recordrtc
|
||||
* @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class plugininfo extends plugin implements plugin_with_buttons, plugin_with_menuitems, plugin_with_configuration {
|
||||
/**
|
||||
* Whether the plugin is enabled
|
||||
*
|
||||
* @param context $context The context that the editor is used within
|
||||
* @param array $options The options passed in when requesting the editor
|
||||
* @param array $fpoptions The filepicker options passed in when requesting the editor
|
||||
* @param editor $editor The editor instance in which the plugin is initialised
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_enabled(
|
||||
context $context,
|
||||
array $options,
|
||||
array $fpoptions,
|
||||
?editor $editor = null
|
||||
): bool {
|
||||
// Disabled if:
|
||||
// - Not logged in or guest.
|
||||
// - Files are not allowed.
|
||||
// - Only URL are supported.
|
||||
$canhavefiles = !empty($options['maxfiles']);
|
||||
$canhaveexternalfiles = !empty($options['return_types']) && ($options['return_types'] & FILE_EXTERNAL);
|
||||
return isloggedin() && !isguestuser() && $canhavefiles && $canhaveexternalfiles;
|
||||
}
|
||||
|
||||
public static function get_available_buttons(): array {
|
||||
return [
|
||||
'tiny_recordrtc/tiny_recordrtc_image',
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_available_menuitems(): array {
|
||||
return [
|
||||
'tiny_recordrtc/tiny_recordrtc_image',
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_plugin_configuration_for_context(
|
||||
context $context,
|
||||
array $options,
|
||||
array $fpoptions,
|
||||
?editor $editor = null
|
||||
): array {
|
||||
$sesskey = sesskey();
|
||||
$allowedtypes = get_config('tiny_recordrtc', 'allowedtypes');
|
||||
$audiobitrate = get_config('tiny_recordrtc', 'audiobitrate');
|
||||
$videobitrate = get_config('tiny_recordrtc', 'videobitrate');
|
||||
$audiotimelimit = get_config('tiny_recordrtc', 'audiotimelimit');
|
||||
$videotimelimit = get_config('tiny_recordrtc', 'videotimelimit');
|
||||
|
||||
// Update $allowedtypes to account for capabilities.
|
||||
$audioallowed = $allowedtypes === 'audio' || $allowedtypes === 'both';
|
||||
$videoallowed = $allowedtypes === 'video' || $allowedtypes === 'both';
|
||||
$audioallowed = $audioallowed && has_capability('tiny/recordrtc:recordaudio', $context);
|
||||
$videoallowed = $videoallowed && has_capability('tiny/recordrtc:recordvideo', $context);
|
||||
if ($audioallowed && $videoallowed) {
|
||||
$allowedtypes = 'both';
|
||||
} else if ($audioallowed) {
|
||||
$allowedtypes = 'audio';
|
||||
} else if ($videoallowed) {
|
||||
$allowedtypes = 'video';
|
||||
} else {
|
||||
$allowedtypes = '';
|
||||
}
|
||||
|
||||
$maxrecsize = get_max_upload_file_size();
|
||||
if (!empty($options['maxbytes'])) {
|
||||
$maxrecsize = min($maxrecsize, $options['maxbytes']);
|
||||
}
|
||||
$params = [
|
||||
'contextid' => $context->id,
|
||||
'sesskey' => $sesskey,
|
||||
'allowedtypes' => $allowedtypes,
|
||||
'audiobitrate' => $audiobitrate,
|
||||
'videobitrate' => $videobitrate,
|
||||
'audiotimelimit' => $audiotimelimit,
|
||||
'videotimelimit' => $videotimelimit,
|
||||
'maxrecsize' => $maxrecsize
|
||||
];
|
||||
|
||||
$data = [
|
||||
'params' => $params,
|
||||
'fpoptions' => $fpoptions
|
||||
];
|
||||
|
||||
return [
|
||||
'data' => $data
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
namespace tiny_recordrtc\privacy;
|
||||
|
||||
/**
|
||||
* Privacy Subsystem implementation for the recordrtc plugin for TinyMCE.
|
||||
*
|
||||
* @package tiny_recordrtc
|
||||
* @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements \core_privacy\local\metadata\null_provider {
|
||||
public static function get_reason(): string {
|
||||
return 'privacy:metadata';
|
||||
}
|
||||
}
|
44
lib/editor/tiny/plugins/recordrtc/db/access.php
Normal file
44
lib/editor/tiny/plugins/recordrtc/db/access.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny text editor recordrtc capabilities.
|
||||
*
|
||||
* @package tiny_recordrtc
|
||||
* @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$capabilities = [
|
||||
// Capability to record audio using this plugin.
|
||||
'tiny/recordrtc:recordaudio' => [
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'archetypes' => [
|
||||
'user' => CAP_ALLOW,
|
||||
],
|
||||
],
|
||||
// Capability to record video using this plugin.
|
||||
'tiny/recordrtc:recordvideo' => [
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'archetypes' => [
|
||||
'user' => CAP_ALLOW,
|
||||
],
|
||||
],
|
||||
];
|
87
lib/editor/tiny/plugins/recordrtc/lang/en/tiny_recordrtc.php
Normal file
87
lib/editor/tiny/plugins/recordrtc/lang/en/tiny_recordrtc.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'tiny_recordrtc', language 'en'.
|
||||
*
|
||||
* @package tiny_recordrtc
|
||||
* @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['allowedtypes'] = 'Allowed types';
|
||||
$string['allowedtypes_desc'] = 'Which recording buttons should appear in Atto. In addition to this setting, there are also capabilities which can control access to the buttons to particular users in particular contexts.';
|
||||
$string['attachrecording'] = 'Attach recording';
|
||||
$string['audioandvideo'] = 'Audio and video';
|
||||
$string['audiobitrate'] = 'Audio bitrate';
|
||||
$string['audiobitrate_desc'] = 'Quality of audio recording (larger number means higher quality)';
|
||||
$string['audiobuttontitle'] = 'Record audio';
|
||||
$string['audiotimelimit'] = 'Audio time limit in seconds';
|
||||
$string['audiotimelimit_desc'] = 'Maximum recording length allowed for the audio clips';
|
||||
$string['audiotitle'] = 'Record Audio';
|
||||
$string['confirm_yes'] = 'Yes';
|
||||
$string['discard_desc'] = 'There is a reacording data or the recording is in process.<br>Do you want to close the recording?';
|
||||
$string['discard_title'] = 'Close confirmation';
|
||||
$string['gumabort'] = 'Something strange happened which prevented the webcam/microphone from being used';
|
||||
$string['gumabort_title'] = 'Something happened';
|
||||
$string['gumnotallowed'] = 'The user must allow the browser access to the webcam/microphone';
|
||||
$string['gumnotallowed_title'] = 'Wrong permissions';
|
||||
$string['gumnotfound'] = 'There is no input device connected or enabled';
|
||||
$string['gumnotfound_title'] = 'Device missing';
|
||||
$string['gumnotreadable'] = 'Something is preventing the browser from accessing the webcam/microphone';
|
||||
$string['gumnotreadable_title'] = 'Hardware error';
|
||||
$string['gumnotsupported'] = 'Your browser does not support recording over an insecure connection and must close the plugin';
|
||||
$string['gumnotsupported_title'] = 'No support for insecure connection';
|
||||
$string['gumoverconstrained'] = 'The current webcam/microphone can not produce a stream with the required constraints';
|
||||
$string['gumoverconstrained_title'] = 'Problem with constraints';
|
||||
$string['gumsecurity'] = 'Your browser does not support recording over an insecure connection and must close the plugin';
|
||||
$string['gumsecurity_title'] = 'No support for insecure connection';
|
||||
$string['gumtype'] = 'Tried to get stream from the webcam/microphone, but no constraints were specified';
|
||||
$string['gumtype_title'] = 'No constraints specified';
|
||||
$string['insecurealert'] = 'Your browser might not allow this plugin to work unless it is used either over HTTPS or from localhost';
|
||||
$string['insecurealert_title'] = 'Insecure connection!';
|
||||
$string['maxfilesizehit'] = 'You have attained the maximum size limit for file uploads';
|
||||
$string['maxfilesizehit_title'] = 'Recording stopped';
|
||||
$string['norecordingfound'] = 'Something appears to have gone wrong, it seems nothing has been recorded';
|
||||
$string['norecordingfound_title'] = 'No recording found';
|
||||
$string['nowebrtc'] = 'Your browser offers limited or no support for WebRTC technologies yet, and cannot be used with this plugin. Please switch or upgrade your browser';
|
||||
$string['nowebrtc_title'] = 'WebRTC not supported';
|
||||
$string['onlyaudio'] = 'Audio only';
|
||||
$string['onlyvideo'] = 'Video only';
|
||||
$string['pluginname'] = 'Tiny Record RTC plugin for Moodle';
|
||||
$string['privacy:metadata'] = 'The RecordRTC plugin does not store any personal data.';
|
||||
$string['recordagain'] = 'Record again';
|
||||
$string['recordagain_desc'] = 'You have already recorded some content. Recording again will remove this content.<br>Are you sure you want to reset the recording?';
|
||||
$string['recordagain_title'] = 'Record again confirmation';
|
||||
$string['recordingfailed'] = 'Recording failed, try again';
|
||||
$string['recordinguploaded'] = 'Recording uploaded';
|
||||
$string['recordrtc:recordaudio'] = 'Record audio directly into the text editor';
|
||||
$string['recordrtc:recordvideo'] = 'Record video directly into the text editor';
|
||||
$string['startrecording'] = 'Start recording';
|
||||
$string['stoprecording'] = 'Stop recording';
|
||||
$string['timelimitwarning'] = 'You must enter a number that is greater than 0.';
|
||||
$string['uploadaborted'] = 'Upload aborted:';
|
||||
$string['uploadfailed'] = 'Upload failed with error: {$a->error}';
|
||||
$string['uploadfailed404'] = 'Upload failed: file too large';
|
||||
$string['uploading'] = 'Uploading - {$a->progress}%';
|
||||
$string['uploadprogress'] = 'completed';
|
||||
$string['videobitrate'] = 'Video bitrate';
|
||||
$string['videobitrate_desc'] = 'Quality of video recording (larger number means higher quality)';
|
||||
$string['videobuttontitle'] = 'Record video';
|
||||
$string['videotimelimit'] = 'Video time limit in seconds';
|
||||
$string['videotimelimit_desc'] = 'Maximum recording length allowed for the video clips';
|
||||
$string['videotitle'] = 'Record Video';
|
||||
$string['helplinktext'] = 'Moodle RecordRTC';
|
15
lib/editor/tiny/plugins/recordrtc/pix/audio.svg
Normal file
15
lib/editor/tiny/plugins/recordrtc/pix/audio.svg
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="-50 0 608 500" style="enable-background:new 100 0 608 500;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M394,196.1c0-11.9-9.7-21.6-21.6-21.6s-21.6,9.7-21.6,21.6c0,61.7-50.2,111.8-111.8,111.8
|
||||
s-111.8-50.2-111.8-111.8c0-11.9-9.7-21.6-21.6-21.6S84,184.2,84,196.1c0,78.2,58.1,143,133.4,153.5v85.2h-55.6
|
||||
c-11.9,0-21.6,9.7-21.6,21.6s9.7,21.6,21.6,21.6h154.5c11.9,0,21.6-9.7,21.6-21.6s-9.7-21.6-21.6-21.6h-55.6v-85.2
|
||||
C335.9,339.1,394,274.2,394,196.1z"/>
|
||||
|
||||
<path d="M239,0L239,0c-46.4,0-84,37.6-84,84v110.7c0,46.4,37.6,84,84,84l0,0c46.4,0,84-37.6,84-84V84
|
||||
C323,37.6,285.4,0,239,0z M239.1,55.9c-15.1,0-27.4,12.3-27.4,27.4c0,6.9-5.6,12.5-12.5,12.5s-12.5-5.6-12.5-12.5
|
||||
c0-28.9,23.5-52.4,52.4-52.4c6.9,0,12.5,5.6,12.5,12.5S246,55.9,239.1,55.9z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1 KiB |
BIN
lib/editor/tiny/plugins/recordrtc/pix/icon.png
Normal file
BIN
lib/editor/tiny/plugins/recordrtc/pix/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
46
lib/editor/tiny/plugins/recordrtc/pix/video.svg
Normal file
46
lib/editor/tiny/plugins/recordrtc/pix/video.svg
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 458.317 458.317" style="enable-background:new 0 0 458.317 458.317;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M450.237,109.509c-4.964-2.582-10.953-2.187-15.534,1.026l-68.72,48.19V98.933c0-18.121-14.743-32.864-32.865-32.864
|
||||
H32.865C14.743,66.068,0,80.811,0,98.933v260.452c0,18.121,14.743,32.864,32.865,32.864h300.254
|
||||
c18.122,0,32.865-14.743,32.865-32.864V299.59l68.72,48.191c4.573,3.206,10.561,3.613,15.534,1.026
|
||||
c4.964-2.582,8.079-7.712,8.079-13.308V122.816C458.315,117.222,455.201,112.092,450.237,109.509z M95.621,125.816
|
||||
c20.745,0,37.622,16.877,37.622,37.622s-16.877,37.623-37.622,37.623s-37.623-16.878-37.623-37.623S74.875,125.816,95.621,125.816
|
||||
z M297.095,326.817H68.889c-8.284,0-15-6.716-15-15s6.716-15,15-15h228.206c8.284,0,15,6.716,15,15
|
||||
S305.379,326.817,297.095,326.817z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
97
lib/editor/tiny/plugins/recordrtc/settings.php
Normal file
97
lib/editor/tiny/plugins/recordrtc/settings.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Settings that allow turning on and off recordrtc features
|
||||
*
|
||||
* @package tiny_recordrtc
|
||||
* @copyright 2022, Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// Needed for constants.
|
||||
require_once($CFG->dirroot . '/lib/editor/tiny/plugins/recordrtc/classes/plugininfo.php');
|
||||
|
||||
$ADMIN->add('editortiny', new admin_category('tiny_recordrtc', new lang_string('pluginname', 'tiny_recordrtc')));
|
||||
|
||||
if ($ADMIN->fulltree) {
|
||||
$defaulttimelimit = 120;
|
||||
|
||||
$url = parse_url($CFG->wwwroot);
|
||||
$hostname = parse_url($CFG->wwwroot, PHP_URL_HOST);
|
||||
$isvalid = in_array($hostname, ['localhost', '127.0.0.1', '::1']);
|
||||
$isvalid = $isvalid || preg_match("/^.*\.localhost$/", $hostname);
|
||||
|
||||
if (!$isvalid && $url['scheme'] !== 'https') {
|
||||
$warning = html_writer::div(get_string('insecurealert', 'tiny_recordrtc'), 'box py-3 generalbox alert alert-danger');
|
||||
$setting = new admin_setting_description('tiny_recordrtc/warning', null, $warning);
|
||||
$settings->add($setting);
|
||||
}
|
||||
|
||||
// Types allowed.
|
||||
$options = [
|
||||
'both' => new lang_string('audioandvideo', 'tiny_recordrtc'),
|
||||
'audio' => new lang_string('onlyaudio', 'tiny_recordrtc'),
|
||||
'video' => new lang_string('onlyvideo', 'tiny_recordrtc')
|
||||
];
|
||||
$name = get_string('allowedtypes', 'tiny_recordrtc');
|
||||
$desc = get_string('allowedtypes_desc', 'tiny_recordrtc');
|
||||
$default = 'both';
|
||||
$setting = new admin_setting_configselect('tiny_recordrtc/allowedtypes', $name, $desc, $default, $options);
|
||||
$settings->add($setting);
|
||||
|
||||
// Audio bitrate.
|
||||
$name = get_string('audiobitrate', 'tiny_recordrtc');
|
||||
$desc = get_string('audiobitrate_desc', 'tiny_recordrtc');
|
||||
$default = '128000';
|
||||
$setting = new admin_setting_configtext('tiny_recordrtc/audiobitrate', $name, $desc, $default, PARAM_INT, 8);
|
||||
$settings->add($setting);
|
||||
|
||||
// Video bitrate.
|
||||
$name = get_string('videobitrate', 'tiny_recordrtc');
|
||||
$desc = get_string('videobitrate_desc', 'tiny_recordrtc');
|
||||
$default = '2500000';
|
||||
$setting = new admin_setting_configtext('tiny_recordrtc/videobitrate', $name, $desc, $default, PARAM_INT, 8);
|
||||
$settings->add($setting);
|
||||
|
||||
// Audio recording time limit.
|
||||
$name = get_string('audiotimelimit', 'tiny_recordrtc');
|
||||
$desc = get_string('audiotimelimit_desc', 'tiny_recordrtc');
|
||||
// Validate audiotimelimit greater than 0.
|
||||
$setting = new admin_setting_configduration('tiny_recordrtc/audiotimelimit', $name, $desc, $defaulttimelimit);
|
||||
$setting->set_validate_function(function(int $value): string {
|
||||
if ($value <= 0) {
|
||||
return get_string('timelimitwarning', 'tiny_recordrtc');
|
||||
}
|
||||
return '';
|
||||
});
|
||||
$settings->add($setting);
|
||||
|
||||
// Video recording time limit.
|
||||
$name = get_string('videotimelimit', 'tiny_recordrtc');
|
||||
$desc = get_string('videotimelimit_desc', 'tiny_recordrtc');
|
||||
// Validate videotimelimit greater than 0.
|
||||
$setting = new admin_setting_configduration('tiny_recordrtc/videotimelimit', $name, $desc, $defaulttimelimit);
|
||||
$setting->set_validate_function(function(int $value): string {
|
||||
if ($value <= 0) {
|
||||
return get_string('timelimitwarning', 'tiny_recordrtc');
|
||||
}
|
||||
return '';
|
||||
});
|
||||
$settings->add($setting);
|
||||
}
|
43
lib/editor/tiny/plugins/recordrtc/styles.css
Normal file
43
lib/editor/tiny/plugins/recordrtc/styles.css
Normal file
|
@ -0,0 +1,43 @@
|
|||
.tiny_recordrtc,
|
||||
.tiny_recordrtc div {
|
||||
font-weight: normal;
|
||||
line-height: 40px;
|
||||
padding: 3px 0 3px 0;
|
||||
}
|
||||
|
||||
.tiny_recordrtc .alert {
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tiny_recordrtc audio {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 670px) {
|
||||
.tiny_recordrtc video {
|
||||
display: block;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 671px) {
|
||||
.tiny_recordrtc video {
|
||||
display: block;
|
||||
height: 480px;
|
||||
margin: 0 auto;
|
||||
width: 640px;
|
||||
}
|
||||
}
|
||||
|
||||
.tiny_recordrtc #start-stop,
|
||||
.tiny_recordrtc #upload {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.tiny_recordrtc video {
|
||||
border-radius: 8px;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template tiny_recordrtc/audio_recorder
|
||||
|
||||
Audio recorder template.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Note:
|
||||
The content of this template should ideally be shared with the video recorder by using a block template.
|
||||
Unfortunately it is not possible to have nested block templates due to MDL-51145.
|
||||
Once this issue is resolved, this template should be refactored to use a block template.
|
||||
}}
|
||||
{{< core/modal }}
|
||||
{{$title}}{{#str}} audiotitle, tiny_recordrtc {{/str}}{{/title}}
|
||||
{{$body}}
|
||||
{{> core/local/toast/wrapper }}
|
||||
<div class="tiny_recordrtc container-fluid">
|
||||
<div data-purpose="security-warning" class="row hide">
|
||||
<div class="col-12">
|
||||
<div id="alert-danger" class="alert alert-danger">
|
||||
<strong>
|
||||
{{#str}} insecurealerttitle, tiny_recordrtc {{/str}}
|
||||
</strong>
|
||||
{{#str}} insecurealert, tiny_recordrtc {{/str}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-purpose="player-container" class="row">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-10">
|
||||
<audio></audio>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
</div>
|
||||
<div data-purpose="start-stop-container" class="row">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-10">
|
||||
<button class="btn btn-lg btn-outline-danger btn-block" data-action="startstop">
|
||||
{{#str}} startrecording, tiny_recordrtc {{/str}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
</div>
|
||||
<div data-purpose="upload-container" class="row hide">
|
||||
<div class="col-3"></div>
|
||||
<div class="col-6">
|
||||
<button class="btn btn-primary btn-block" data-action="upload">
|
||||
{{#str}} attachrecording, tiny_recordrtc {{/str}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{/body}}
|
||||
|
||||
{{$footer}}
|
||||
<button type="button" class="btn btn-secondary" data-action="cancel">{{#str}} cancel {{/str}}</button>
|
||||
{{/footer}}
|
||||
{{/ core/modal }}
|
|
@ -0,0 +1,29 @@
|
|||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template tiny_recordrtc/embed_audio
|
||||
|
||||
Insert recording template.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"source": "https://example.com/someaudio.mp3"
|
||||
}
|
||||
}}
|
||||
<audio controls="true">
|
||||
<source src="{{ source }}">{{ source }}</source>}}
|
||||
</audio>
|
|
@ -0,0 +1,29 @@
|
|||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template tiny_recordrtc/embed_video
|
||||
|
||||
Insert recording template.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"source": "https://example.com/someaudio.mp3"
|
||||
}
|
||||
}}
|
||||
<video controls="true">
|
||||
<source src="{{ source }}">{{ source }}</source>}}
|
||||
</video>
|
|
@ -0,0 +1,70 @@
|
|||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template tiny_recordrtc/insert_recording
|
||||
|
||||
Insert recording template.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
|
||||
}
|
||||
}}
|
||||
<div class="tiny_recordrtc container-fluid">
|
||||
<div data-purpose="security-warning" class="row hide">
|
||||
<div class="col-12">
|
||||
<div id="alert-danger" class="alert alert-danger">
|
||||
<strong>
|
||||
{{#str}} insecurealerttitle, tiny_recordrtc {{/str}}
|
||||
</strong>
|
||||
{{#str}} insecurealert, tiny_recordrtc {{/str}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-purpose="player-container" class="row hide">
|
||||
{{#isaudio}}
|
||||
<div class="col-1"></div>
|
||||
<div class="col-10">
|
||||
<audio id="player"></audio>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
{{/isaudio}}
|
||||
{{^isaudio}}
|
||||
<div class="col-12">
|
||||
<video id="player"></video>
|
||||
</div>
|
||||
{{/isaudio}}
|
||||
</div>
|
||||
<div data-purpose="start-stop-container" class="row">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-10">
|
||||
<button id="start-stop" class="btn btn-lg btn-outline-danger btn-block" data-action-"startstop">
|
||||
{{#str}} startrecording, tiny_recordrtc {{/str}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
</div>
|
||||
<div data-purpose="attach-container" class="row hide">
|
||||
<div class="col-3"></div>
|
||||
<div class="col-6">
|
||||
<button id="upload" class="btn btn-primary btn-block" data-action-"attach">
|
||||
{{#str}} attachrecording, tiny_recordrtc {{/str}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,28 @@
|
|||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template tiny_recordrtc/timeremaining
|
||||
|
||||
Insert recording template.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<span>
|
||||
{{#str}}stoprecording, tiny_recordrtc{{/str}} (<span data-type="minutes">{{minutes}}</span>:<span data-type="seconds">{{seconds}}</span>)
|
||||
</span>
|
|
@ -0,0 +1,78 @@
|
|||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template tiny_recordrtc/video_recorder
|
||||
|
||||
Audio recorder template.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Note:
|
||||
The content of this template should ideally be shared with the video recorder by using a block template.
|
||||
Unfortunately it is not possible to have nested block templates due to MDL-51145.
|
||||
Once this issue is resolved, this template should be refactored to use a block template.
|
||||
}}
|
||||
{{< core/modal }}
|
||||
{{$title}}{{#str}} videotitle, tiny_recordrtc {{/str}}{{/title}}
|
||||
{{$body}}
|
||||
{{> core/local/toast/wrapper }}
|
||||
<div class="tiny_recordrtc container-fluid">
|
||||
<div data-purpose="security-warning" class="row hide">
|
||||
<div class="col-12">
|
||||
<div id="alert-danger" class="alert alert-danger">
|
||||
<strong>
|
||||
{{#str}} insecurealerttitle, tiny_recordrtc {{/str}}
|
||||
</strong>
|
||||
{{#str}} insecurealert, tiny_recordrtc {{/str}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-purpose="player-container" class="row">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-10">
|
||||
<video></video>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
</div>
|
||||
<div data-purpose="start-stop-container" class="row">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-10">
|
||||
<button class="btn btn-lg btn-outline-danger btn-block" data-action="startstop">
|
||||
{{#str}} startrecording, tiny_recordrtc {{/str}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
</div>
|
||||
<div data-purpose="upload-container" class="row hide">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-10">
|
||||
<button class="btn btn-lg btn-primary btn-block" data-action="upload">
|
||||
{{#str}} attachrecording, tiny_recordrtc {{/str}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{/body}}
|
||||
|
||||
{{$footer}}
|
||||
<button type="button" class="btn btn-secondary" data-action="cancel">{{#str}} cancel {{/str}}</button>
|
||||
{{/footer}}
|
||||
{{/ core/modal }}
|
29
lib/editor/tiny/plugins/recordrtc/version.php
Normal file
29
lib/editor/tiny/plugins/recordrtc/version.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Tiny media plugin version details.
|
||||
*
|
||||
* @package tiny_recordrtc
|
||||
* @copyright 2022 Stevani Andolo <stevani@hotmail.com.au>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2022081800;
|
||||
$plugin->requires = 2020061500;
|
||||
$plugin->component = 'tiny_recordrtc';
|
Loading…
Add table
Add a link
Reference in a new issue