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

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