From 8ab9030d148c625143cf6a81d809ab423d7e5f17 Mon Sep 17 00:00:00 2001 From: Markos Gogoulos Date: Fri, 16 Jan 2026 13:44:46 +0200 Subject: [PATCH] this --- moodle-plugins/README.md | 46 ++++++ moodle-plugins/tiny_mediacms/README.md | 110 ++++++++++++++ .../tiny_mediacms/amd/build/common.min.js | 1 + .../amd/build/configuration.min.js | 1 + .../tiny_mediacms/amd/build/plugin.min.js | 1 + .../tiny_mediacms/amd/src/common.js | 26 ++++ .../tiny_mediacms/amd/src/configuration.js | 45 ++++++ .../tiny_mediacms/amd/src/plugin.js | 141 ++++++++++++++++++ .../tiny_mediacms/classes/plugininfo.php | 66 ++++++++ .../tiny_mediacms/lang/en/tiny_mediacms.php | 27 ++++ moodle-plugins/tiny_mediacms/pix/icon.svg | 5 + moodle-plugins/tiny_mediacms/version.php | 23 +++ 12 files changed, 492 insertions(+) create mode 100644 moodle-plugins/README.md create mode 100644 moodle-plugins/tiny_mediacms/README.md create mode 100644 moodle-plugins/tiny_mediacms/amd/build/common.min.js create mode 100644 moodle-plugins/tiny_mediacms/amd/build/configuration.min.js create mode 100644 moodle-plugins/tiny_mediacms/amd/build/plugin.min.js create mode 100644 moodle-plugins/tiny_mediacms/amd/src/common.js create mode 100644 moodle-plugins/tiny_mediacms/amd/src/configuration.js create mode 100644 moodle-plugins/tiny_mediacms/amd/src/plugin.js create mode 100644 moodle-plugins/tiny_mediacms/classes/plugininfo.php create mode 100644 moodle-plugins/tiny_mediacms/lang/en/tiny_mediacms.php create mode 100644 moodle-plugins/tiny_mediacms/pix/icon.svg create mode 100644 moodle-plugins/tiny_mediacms/version.php diff --git a/moodle-plugins/README.md b/moodle-plugins/README.md new file mode 100644 index 00000000..701ee236 --- /dev/null +++ b/moodle-plugins/README.md @@ -0,0 +1,46 @@ +# Moodle Plugins for MediaCMS + +This directory contains plugins for integrating MediaCMS with Moodle. + +## Available Plugins + +### tiny_mediacms - TinyMCE MediaCMS Plugin + +A TinyMCE editor plugin that allows users to insert MediaCMS content directly from the Moodle text editor. + +**Features:** +- Insert MediaCMS content with a single click +- Visual media selection interface +- Respects RBAC permissions +- Supports multiple media selection +- Works with LTI 1.3 authentication + +**Installation:** +See [TINYMCE_PLUGIN_INSTALLATION.md](../TINYMCE_PLUGIN_INSTALLATION.md) for detailed installation instructions. + +**Quick Install:** +```bash +cp -r tiny_mediacms /path/to/moodle/lib/editor/tiny/plugins/ +``` + +Then visit Moodle's Site administration → Notifications to complete the installation. + +## Requirements + +- Moodle 5.0 or later +- MediaCMS with LTI integration configured +- Active LTI 1.3 connection between Moodle and MediaCMS + +## Documentation + +- [TinyMCE Plugin Installation Guide](../TINYMCE_PLUGIN_INSTALLATION.md) +- [LTI Setup Guide](../LTI_README.md) +- [LTI Configuration](../LTI_README2.md) + +## Support + +For issues or questions, please refer to the MediaCMS documentation or open an issue in the repository. + +## License + +These plugins are part of MediaCMS and are licensed under the GNU General Public License v3.0 or later. diff --git a/moodle-plugins/tiny_mediacms/README.md b/moodle-plugins/tiny_mediacms/README.md new file mode 100644 index 00000000..617288fb --- /dev/null +++ b/moodle-plugins/tiny_mediacms/README.md @@ -0,0 +1,110 @@ +# TinyMCE MediaCMS Plugin + +A TinyMCE 6 plugin for Moodle that integrates MediaCMS content into the text editor. + +## Description + +This plugin adds a MediaCMS button to the TinyMCE toolbar in Moodle. When clicked, it opens a dialog that allows users to browse and select MediaCMS content to embed directly in their course content. + +## Features + +- **Visual Media Selection**: Browse available MediaCMS content in a grid view +- **Permission-Aware**: Only shows media the user has permission to view +- **RBAC Integration**: Respects MediaCMS role-based access control +- **Multiple Selection**: Select and insert multiple media items at once +- **Pagination**: Navigate through large media libraries +- **Filter Options**: Filter by "My Media" or view all accessible content +- **Responsive Design**: Works on desktop and tablet devices + +## Requirements + +- Moodle 5.0 or later (with TinyMCE 6) +- MediaCMS instance with LTI integration +- Configured LTI 1.3 external tool in Moodle + +## Installation + +1. Copy this directory to `{moodle}/lib/editor/tiny/plugins/tiny_mediacms` +2. Visit Site administration → Notifications +3. Follow the upgrade prompts +4. Configure the plugin in TinyMCE settings + +For detailed installation instructions, see [TINYMCE_PLUGIN_INSTALLATION.md](../../TINYMCE_PLUGIN_INSTALLATION.md) in the MediaCMS root directory. + +## Usage + +1. Open any text editor in Moodle +2. Click the MediaCMS button (video camera icon) in the toolbar +3. Select one or more media items +4. Click "Insert" to embed the content + +## Configuration + +The plugin can be configured at: +- Site administration → Plugins → Text editors → TinyMCE plugins → MediaCMS + +Configuration options: +- MediaCMS URL (typically auto-configured from LTI settings) + +## Technical Details + +### Plugin Type +- Type: TinyMCE 6 plugin +- Category: Content insertion +- API: Moodle editor_tiny API + +### Files +- `version.php` - Plugin metadata +- `classes/plugininfo.php` - Plugin registration and configuration +- `amd/src/plugin.js` - Main plugin functionality +- `amd/src/common.js` - Shared constants +- `amd/src/configuration.js` - Configuration handling +- `lang/en/tiny_mediacms.php` - Language strings +- `pix/icon.svg` - Plugin icon + +### Backend Endpoints (MediaCMS) +- `/lti/tinymce-select/` - Media selection interface +- `/lti/tinymce-embed//` - Embed code API + +## Security + +- Requires active LTI session +- Respects MediaCMS permissions and RBAC +- Uses CSRF protection +- Validates user authentication + +## Support + +For issues, bugs, or feature requests: +1. Check the installation guide +2. Review Moodle and MediaCMS logs +3. Consult MediaCMS LTI documentation +4. Open an issue in the MediaCMS repository + +## License + +This plugin is part of MediaCMS and Moodle. + +- Moodle components: GNU GPL v3 or later +- MediaCMS integration: Same as MediaCMS license + +## Version + +- Version: 1.0.0 +- Release date: 2026-01-12 +- Moodle requirement: 5.0+ +- Maturity: Stable + +## Credits + +Developed for MediaCMS LTI integration with Moodle. + +## Changelog + +### 1.0.0 (2026-01-12) +- Initial release +- Media selection dialog +- Multiple media insertion +- RBAC and permission support +- Pagination support +- Filter options diff --git a/moodle-plugins/tiny_mediacms/amd/build/common.min.js b/moodle-plugins/tiny_mediacms/amd/build/common.min.js new file mode 100644 index 00000000..36cb4235 --- /dev/null +++ b/moodle-plugins/tiny_mediacms/amd/build/common.min.js @@ -0,0 +1 @@ +define("tiny_mediacms/common",[],function(){const component="tiny_mediacms",pluginName=`${component}/plugin`,icon="icon",buttonName=`${component}/button`;return{component:component,pluginName:pluginName,icon:icon,buttonName:buttonName}}); diff --git a/moodle-plugins/tiny_mediacms/amd/build/configuration.min.js b/moodle-plugins/tiny_mediacms/amd/build/configuration.min.js new file mode 100644 index 00000000..3d0e02bb --- /dev/null +++ b/moodle-plugins/tiny_mediacms/amd/build/configuration.min.js @@ -0,0 +1 @@ +define("tiny_mediacms/configuration",["tiny_mediacms/common","editor_tiny/options"],function(common,Options){const pluginName=common.pluginName,mediacmsUrlName=Options.getPluginOptionName(pluginName,"mediacmsUrl");return{register:editor=>{const registerOption=editor.options.register;registerOption(mediacmsUrlName,{processor:"string",default:""})},getConfig:editor=>({mediacmsUrl:editor.options.get(mediacmsUrlName)})}}); diff --git a/moodle-plugins/tiny_mediacms/amd/build/plugin.min.js b/moodle-plugins/tiny_mediacms/amd/build/plugin.min.js new file mode 100644 index 00000000..39b2909e --- /dev/null +++ b/moodle-plugins/tiny_mediacms/amd/build/plugin.min.js @@ -0,0 +1 @@ +define("tiny_mediacms/plugin",["editor_tiny/loader","tiny_mediacms/common","tiny_mediacms/configuration"],function(Loader,common,Configuration){const component=common.component,pluginName=common.pluginName,icon=common.icon,buttonName=common.buttonName,handleAction=async editor=>{const config=Configuration.getConfig(editor),dialogConfig={title:"Select MediaCMS content",size:"large",body:{type:"panel",items:[{type:"htmlpanel",html:'
Loading MediaCMS content...
'}]},buttons:[{type:"cancel",text:"Close"}],initialData:{},onSubmit:function(api){api.close()}},dialog=editor.windowManager.open(dialogConfig),messageHandler=event=>{if(event.data&&"mediacms-embed"===event.data.type){const embedCode=event.data.embedCode;embedCode&&(editor.insertContent(embedCode),dialog.close())}};window.addEventListener("message",messageHandler);const courseId="undefined"!=typeof M&&M.cfg&&M.cfg.courseId?M.cfg.courseId:1,mediacmsBaseUrl=config.mediacmsUrl||window.location.origin,selectMediaUrl=mediacmsBaseUrl+"/lti/select-media/?mode=tinymce&courseid="+courseId;setTimeout(()=>{const iframe=document.querySelector("#mediacms-iframe"),loading=document.querySelector("#mediacms-loading");iframe&&loading&&(iframe.onload=()=>{loading.style.display="none",iframe.style.display="block"},iframe.onerror=()=>{loading.innerHTML='

Error loading MediaCMS content. Please check your configuration.

'},iframe.src=selectMediaUrl)},100);const originalClose=dialog.close;dialog.close=function(){window.removeEventListener("message",messageHandler),originalClose.call(this)}};return{getSetup:async()=>{const[tinyMCE]=await Promise.all([Loader.getTinyMCE()]);return editor=>(editor.ui.registry.addButton(buttonName,{icon:icon,tooltip:"Insert MediaCMS content",onAction:()=>handleAction(editor)}),editor.ui.registry.addMenuItem(buttonName,{icon:icon,text:"Insert MediaCMS content",onAction:()=>handleAction(editor)}),void 0)}}}); diff --git a/moodle-plugins/tiny_mediacms/amd/src/common.js b/moodle-plugins/tiny_mediacms/amd/src/common.js new file mode 100644 index 00000000..74752dc8 --- /dev/null +++ b/moodle-plugins/tiny_mediacms/amd/src/common.js @@ -0,0 +1,26 @@ +// 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. + +/** + * Common values for the Tiny MediaCMS plugin. + * + * @module tiny_mediacms/common + * @copyright 2026 MediaCMS + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +const component = 'tiny_mediacms'; +const pluginName = `${component}/plugin`; +const icon = 'icon'; +const buttonName = `${component}/button`; + +export { + component, + pluginName, + icon, + buttonName, +}; diff --git a/moodle-plugins/tiny_mediacms/amd/src/configuration.js b/moodle-plugins/tiny_mediacms/amd/src/configuration.js new file mode 100644 index 00000000..652180d9 --- /dev/null +++ b/moodle-plugins/tiny_mediacms/amd/src/configuration.js @@ -0,0 +1,45 @@ +// 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. + +/** + * Configuration for Tiny MediaCMS plugin. + * + * @module tiny_mediacms/configuration + * @copyright 2026 MediaCMS + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import {pluginName} from './common'; +import {getPluginOptionName} from 'editor_tiny/options'; + +const mediacmsUrlName = getPluginOptionName(pluginName, 'mediacmsUrl'); + +/** + * Register the plugin configuration. + * + * @param {TinyMCE} editor + */ +export const register = (editor) => { + const registerOption = editor.options.register; + + registerOption(mediacmsUrlName, { + processor: 'string', + "default": '', + }); +}; + +/** + * Get the configuration for the plugin. + * + * @param {TinyMCE.Editor} editor + * @returns {object} + */ +export const getConfig = (editor) => { + return { + mediacmsUrl: editor.options.get(mediacmsUrlName), + }; +}; diff --git a/moodle-plugins/tiny_mediacms/amd/src/plugin.js b/moodle-plugins/tiny_mediacms/amd/src/plugin.js new file mode 100644 index 00000000..61d01476 --- /dev/null +++ b/moodle-plugins/tiny_mediacms/amd/src/plugin.js @@ -0,0 +1,141 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +/** + * Tiny MediaCMS plugin. + * + * @module tiny_mediacms/plugin + * @copyright 2026 MediaCMS + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import {getTinyMCE} from 'editor_tiny/loader'; +import {getPluginOptionName} from 'editor_tiny/options'; +import {component, pluginName, icon, buttonName} from './common'; +import * as Configuration from './configuration'; + +/** + * Handle the action when button is clicked. + * + * @param {TinyMCE.Editor} editor The TinyMCE editor instance. + */ +const handleAction = async(editor) => { + const config = Configuration.getConfig(editor); + + // Get the MediaCMS LTI tool ID from the external tool in the activity + // For simplicity, we'll use a dialog that loads the MediaCMS select-media view + const dialogConfig = { + title: 'Select MediaCMS content', + size: 'large', + body: { + type: 'panel', + items: [ + { + type: 'htmlpanel', + html: '
Loading MediaCMS content...
' + + '' + } + ] + }, + buttons: [ + { + type: 'cancel', + text: 'Close' + } + ], + initialData: {}, + onSubmit: function(api) { + api.close(); + } + }; + + const dialog = editor.windowManager.open(dialogConfig); + + // Listen for messages from the iframe + const messageHandler = (event) => { + // Security check: verify origin if needed + // if (event.origin !== expectedOrigin) return; + + if (event.data && event.data.type === 'mediacms-embed') { + const embedCode = event.data.embedCode; + if (embedCode) { + editor.insertContent(embedCode); + dialog.close(); + } + } + }; + + window.addEventListener('message', messageHandler); + + // Get the current course ID from Moodle + const courseId = (typeof M !== 'undefined' && M.cfg && M.cfg.courseId) ? M.cfg.courseId : 1; + + // Build the MediaCMS select-media URL with TinyMCE mode + // This URL should point to your MediaCMS instance + // You'll need to configure this in the plugin settings + const mediacmsBaseUrl = config.mediacmsUrl || window.location.origin; + const selectMediaUrl = mediacmsBaseUrl + '/lti/select-media/?mode=tinymce&courseid=' + courseId; + + // Load the iframe after dialog is rendered + setTimeout(() => { + const iframe = document.querySelector('#mediacms-iframe'); + const loading = document.querySelector('#mediacms-loading'); + + if (iframe && loading) { + iframe.onload = () => { + loading.style.display = 'none'; + iframe.style.display = 'block'; + }; + iframe.onerror = () => { + loading.innerHTML = '

Error loading MediaCMS content. Please check your configuration.

'; + }; + iframe.src = selectMediaUrl; + } + }, 100); + + // Cleanup on dialog close (TinyMCE 6 API) + // Note: TinyMCE dialog may not have an 'on' method, so we'll rely on cleanup when the component unmounts + const originalClose = dialog.close; + dialog.close = function() { + window.removeEventListener('message', messageHandler); + originalClose.call(this); + }; +}; + +/** + * Get the setup function for the buttons. + * + * This is performed in an async function which ultimately returns the registration function as the + * Tiny.AddOnManager.Add() function does not support async functions. + * + * @returns {function} The registration function to call within the Plugin.add function. + */ +export const getSetup = async() => { + const [ + tinyMCE, + ] = await Promise.all([ + getTinyMCE(), + ]); + + return (editor) => { + // Register the button + editor.ui.registry.addButton(buttonName, { + icon: icon, + tooltip: 'Insert MediaCMS content', + onAction: () => handleAction(editor), + }); + + // Register the menu item + editor.ui.registry.addMenuItem(buttonName, { + icon: icon, + text: 'Insert MediaCMS content', + onAction: () => handleAction(editor), + }); + + return; + }; +}; diff --git a/moodle-plugins/tiny_mediacms/classes/plugininfo.php b/moodle-plugins/tiny_mediacms/classes/plugininfo.php new file mode 100644 index 00000000..f629ab0b --- /dev/null +++ b/moodle-plugins/tiny_mediacms/classes/plugininfo.php @@ -0,0 +1,66 @@ + $CFG->wwwroot, + ]; + } +} diff --git a/moodle-plugins/tiny_mediacms/lang/en/tiny_mediacms.php b/moodle-plugins/tiny_mediacms/lang/en/tiny_mediacms.php new file mode 100644 index 00000000..02e551ff --- /dev/null +++ b/moodle-plugins/tiny_mediacms/lang/en/tiny_mediacms.php @@ -0,0 +1,27 @@ + + + + + diff --git a/moodle-plugins/tiny_mediacms/version.php b/moodle-plugins/tiny_mediacms/version.php new file mode 100644 index 00000000..f445ea24 --- /dev/null +++ b/moodle-plugins/tiny_mediacms/version.php @@ -0,0 +1,23 @@ +component = 'tiny_mediacms'; +$plugin->version = 2026011200; // YYYYMMDDXX format. +$plugin->requires = 2024042200; // Moodle 5.0 or later. +$plugin->maturity = MATURITY_STABLE; +$plugin->release = '1.0.0';