This commit is contained in:
Markos Gogoulos
2026-01-16 13:44:46 +02:00
parent 15c8dec041
commit 8ab9030d14
12 changed files with 492 additions and 0 deletions

46
moodle-plugins/README.md Normal file
View File

@@ -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.

View File

@@ -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/<token>/` - 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

View File

@@ -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}});

View File

@@ -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)})}});

View File

@@ -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:'<div id="mediacms-loading" style="text-align: center; padding: 20px;">Loading MediaCMS content...</div><iframe id="mediacms-iframe" style="width: 100%; height: 500px; border: none; display: none;"></iframe>'}]},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='<p style="color: red;">Error loading MediaCMS content. Please check your configuration.</p>'},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)}}});

View File

@@ -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,
};

View File

@@ -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),
};
};

View File

@@ -0,0 +1,141 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
/**
* 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: '<div id="mediacms-loading" style="text-align: center; padding: 20px;">Loading MediaCMS content...</div>' +
'<iframe id="mediacms-iframe" style="width: 100%; height: 500px; border: none; display: none;"></iframe>'
}
]
},
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 = '<p style="color: red;">Error loading MediaCMS content. Please check your configuration.</p>';
};
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;
};
};

View File

@@ -0,0 +1,66 @@
<?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.
/**
* Tiny MediaCMS plugin info.
*
* @package tiny_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tiny_mediacms;
use context;
use editor_tiny\plugin;
use editor_tiny\plugin_with_buttons;
use editor_tiny\plugin_with_configuration;
/**
* Tiny MediaCMS plugin for Moodle.
*
* @package tiny_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class plugininfo extends plugin implements plugin_with_buttons, plugin_with_configuration {
/**
* Get a list of the buttons provided by this plugin.
*
* @return string[]
*/
public static function get_available_buttons(): array {
return [
'tiny_mediacms/button',
];
}
/**
* Get the configuration for this plugin.
*
* @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_tiny\editor|null $editor The editor instance in which the plugin is initialized
* @return array
*/
public static function get_plugin_configuration_for_context(
context $context,
array $options,
array $fpoptions,
?\editor_tiny\editor $editor = null
): array {
global $CFG;
// Return the MediaCMS LTI tool URL configuration
return [
'mediacmsUrl' => $CFG->wwwroot,
];
}
}

View File

@@ -0,0 +1,27 @@
<?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.
/**
* Language strings for tiny_mediacms plugin.
*
* @package tiny_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['pluginname'] = 'MediaCMS';
$string['privacy:metadata'] = 'The MediaCMS plugin does not store any personal data.';
$string['button_title'] = 'Insert MediaCMS content';
$string['dialog_title'] = 'Select MediaCMS content';
$string['insert'] = 'Insert';
$string['cancel'] = 'Cancel';
$string['loading'] = 'Loading MediaCMS content...';
$string['error_no_tool'] = 'No MediaCMS LTI tool configured for this course.';
$string['error_loading'] = 'Error loading MediaCMS content. Please try again.';

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="4" width="20" height="16" rx="2" stroke="currentColor" stroke-width="2" fill="none"/>
<polygon points="10,9 10,15 16,12" fill="currentColor"/>
<circle cx="18" cy="7" r="2" fill="#ff0000"/>
</svg>

After

Width:  |  Height:  |  Size: 319 B

View File

@@ -0,0 +1,23 @@
<?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.
/**
* Tiny MediaCMS plugin version details.
*
* @package tiny_mediacms
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->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';