diff --git a/lms-plugins/mediacms-moodle/dist/mediacms-moodle-v1.0.0.zip b/lms-plugins/mediacms-moodle/dist/mediacms-moodle-v1.0.0.zip
index ad26dbb5..c3a7b387 100644
Binary files a/lms-plugins/mediacms-moodle/dist/mediacms-moodle-v1.0.0.zip and b/lms-plugins/mediacms-moodle/dist/mediacms-moodle-v1.0.0.zip differ
diff --git a/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php b/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php
index 3c642dbe..7b11d9aa 100644
--- a/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php
+++ b/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php
@@ -111,7 +111,7 @@ class text_filter extends \core_filters\text_filter {
parse_str($parsed_url['query'], $query_params);
// Extract embed-related parameters
- $supported_params = ['showTitle', 'showRelated', 'showUserAvatar', 'linkTitle', 't', 'width', 'height'];
+ $supported_params = ['showTitle', 'showUserAvatar', 'linkTitle', 't', 'width', 'height'];
foreach ($supported_params as $param) {
if (isset($query_params[$param])) {
$embed_params[$param] = $query_params[$param];
diff --git a/lms-plugins/mediacms-moodle/filter/mediacms/launch.php b/lms-plugins/mediacms-moodle/filter/mediacms/launch.php
index 6b0d9b26..6192c6b2 100644
--- a/lms-plugins/mediacms-moodle/filter/mediacms/launch.php
+++ b/lms-plugins/mediacms-moodle/filter/mediacms/launch.php
@@ -22,7 +22,6 @@ $width = optional_param('width', 0, PARAM_INT);
// Extract embed parameters
$showTitle = optional_param('showTitle', '', PARAM_TEXT);
-$showRelated = optional_param('showRelated', '', PARAM_TEXT);
$showUserAvatar = optional_param('showUserAvatar', '', PARAM_TEXT);
$linkTitle = optional_param('linkTitle', '', PARAM_TEXT);
$startTime = optional_param('t', '', PARAM_TEXT);
@@ -61,9 +60,6 @@ $custom_params = ["media_friendly_token=" . $mediatoken];
if ($showTitle !== '') {
$custom_params[] = "embed_show_title=" . $showTitle;
}
-if ($showRelated !== '') {
- $custom_params[] = "embed_show_related=" . $showRelated;
-}
if ($showUserAvatar !== '') {
$custom_params[] = "embed_show_user_avatar=" . $showUserAvatar;
}
@@ -89,9 +85,6 @@ $page_params = [
if ($showTitle !== '') {
$page_params['showTitle'] = $showTitle;
}
-if ($showRelated !== '') {
- $page_params['showRelated'] = $showRelated;
-}
if ($showUserAvatar !== '') {
$page_params['showUserAvatar'] = $showUserAvatar;
}
@@ -127,9 +120,6 @@ $hidden_fields = '';
}
-if ($showRelated !== '') {
- $hidden_fields .= '';
-}
if ($showUserAvatar !== '') {
$hidden_fields .= '';
}
diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js
index 3cb705d4..ba33ec01 100755
--- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js
+++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js
@@ -10,6 +10,6 @@ define("tiny_mediacms/autoconvert",["exports","./options"],(function(_exports,_o
* @copyright 2024
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-const MEDIACMS_VIEW_URL_PATTERN=/^(https?:\/\/[^\/]+)\/view\?m=([a-zA-Z0-9_-]+)$/,parseMediaCMSUrl=text=>{if(!text||"string"!=typeof text)return null;const trimmed=text.trim(),match=trimmed.match(MEDIACMS_VIEW_URL_PATTERN);return match?{baseUrl:match[1],videoId:match[2],originalUrl:trimmed}:null},isDomainAllowed=(parsed,config)=>{const configuredBaseUrl=config.autoConvertBaseUrl||config.mediacmsBaseUrl;if(!configuredBaseUrl)return!0;try{const configuredUrl=new URL(configuredBaseUrl),pastedUrl=new URL(parsed.baseUrl);return configuredUrl.host===pastedUrl.host}catch(e){return!0}},generateEmbedHtml=function(parsed){let options=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const embedUrl=new URL("".concat(parsed.baseUrl,"/embed"));embedUrl.searchParams.set("m",parsed.videoId),embedUrl.searchParams.set("showTitle",!1!==options.showTitle?"1":"0"),embedUrl.searchParams.set("showRelated",!1!==options.showRelated?"1":"0"),embedUrl.searchParams.set("showUserAvatar",!1!==options.showUserAvatar?"1":"0"),embedUrl.searchParams.set("linkTitle",!1!==options.linkTitle?"1":"0");const html='';return html};_exports.setupAutoConvert=editor=>{const config=(0,_options.getData)(editor)||{};!1!==config.autoConvertEnabled&&(editor.on("paste",(e=>{handlePasteEvent(editor,e,config)})),editor.on("input",(e=>{handleInputEvent(editor,e,config)})))};const handlePasteEvent=(editor,e,config)=>{const clipboardData=e.clipboardData||window.clipboardData;if(!clipboardData)return;const text=clipboardData.getData("text/plain")||clipboardData.getData("text");if(!text)return;const parsed=parseMediaCMSUrl(text);if(!parsed)return;if(!isDomainAllowed(parsed,config))return;e.preventDefault(),e.stopPropagation();const embedHtml=generateEmbedHtml(parsed,config.autoConvertOptions||{});setTimeout((()=>{editor.insertContent(embedHtml),editor.selection.collapse(!1)}),0)},handleInputEvent=(editor,e,config)=>{if("insertFromPaste"!==e.inputType&&"insertText"!==e.inputType)return;const node=editor.selection.getNode();if(!node||"P"!==node.nodeName)return;const text=node.textContent||"",parsed=parseMediaCMSUrl(text);if(!parsed||!isDomainAllowed(parsed,config))return;const trimmedHtml=node.innerHTML.trim();if(trimmedHtml!==text.trim()&&!trimmedHtml.startsWith(text.trim()))return;const embedHtml=generateEmbedHtml(parsed,config.autoConvertOptions||{});setTimeout((()=>{const currentText=node.textContent||"",currentParsed=parseMediaCMSUrl(currentText);currentParsed&¤tParsed.originalUrl===parsed.originalUrl&&(editor.selection.select(node),editor.insertContent(embedHtml))}),100)};_exports.isMediaCMSUrl=text=>null!==parseMediaCMSUrl(text);_exports.convertToEmbed=function(url){let options=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const parsed=parseMediaCMSUrl(url);return parsed?generateEmbedHtml(parsed,options):null}}));
+const MEDIACMS_VIEW_URL_PATTERN=/^(https?:\/\/[^\/]+)\/view\?m=([a-zA-Z0-9_-]+)$/,parseMediaCMSUrl=text=>{if(!text||"string"!=typeof text)return null;const trimmed=text.trim(),match=trimmed.match(MEDIACMS_VIEW_URL_PATTERN);return match?{baseUrl:match[1],videoId:match[2],originalUrl:trimmed}:null},isDomainAllowed=(parsed,config)=>{const configuredBaseUrl=config.autoConvertBaseUrl||config.mediacmsBaseUrl;if(!configuredBaseUrl)return!0;try{const configuredUrl=new URL(configuredBaseUrl),pastedUrl=new URL(parsed.baseUrl);return configuredUrl.host===pastedUrl.host}catch(e){return!0}},generateEmbedHtml=function(parsed){let options=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const embedUrl=new URL("".concat(parsed.baseUrl,"/embed"));embedUrl.searchParams.set("m",parsed.videoId),embedUrl.searchParams.set("showTitle",!1!==options.showTitle?"1":"0"),embedUrl.searchParams.set("showUserAvatar",!1!==options.showUserAvatar?"1":"0"),embedUrl.searchParams.set("linkTitle",!1!==options.linkTitle?"1":"0");const html='';return html};_exports.setupAutoConvert=editor=>{const config=(0,_options.getData)(editor)||{};!1!==config.autoConvertEnabled&&(editor.on("paste",(e=>{handlePasteEvent(editor,e,config)})),editor.on("input",(e=>{handleInputEvent(editor,e,config)})))};const handlePasteEvent=(editor,e,config)=>{const clipboardData=e.clipboardData||window.clipboardData;if(!clipboardData)return;const text=clipboardData.getData("text/plain")||clipboardData.getData("text");if(!text)return;const parsed=parseMediaCMSUrl(text);if(!parsed)return;if(!isDomainAllowed(parsed,config))return;e.preventDefault(),e.stopPropagation();const embedHtml=generateEmbedHtml(parsed,config.autoConvertOptions||{});setTimeout((()=>{editor.insertContent(embedHtml),editor.selection.collapse(!1)}),0)},handleInputEvent=(editor,e,config)=>{if("insertFromPaste"!==e.inputType&&"insertText"!==e.inputType)return;const node=editor.selection.getNode();if(!node||"P"!==node.nodeName)return;const text=node.textContent||"",parsed=parseMediaCMSUrl(text);if(!parsed||!isDomainAllowed(parsed,config))return;const trimmedHtml=node.innerHTML.trim();if(trimmedHtml!==text.trim()&&!trimmedHtml.startsWith(text.trim()))return;const embedHtml=generateEmbedHtml(parsed,config.autoConvertOptions||{});setTimeout((()=>{const currentText=node.textContent||"",currentParsed=parseMediaCMSUrl(currentText);currentParsed&¤tParsed.originalUrl===parsed.originalUrl&&(editor.selection.select(node),editor.insertContent(embedHtml))}),100)};_exports.isMediaCMSUrl=text=>null!==parseMediaCMSUrl(text);_exports.convertToEmbed=function(url){let options=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const parsed=parseMediaCMSUrl(url);return parsed?generateEmbedHtml(parsed,options):null}}));
//# sourceMappingURL=autoconvert.min.js.map
\ No newline at end of file
diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js.map b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js.map
index b4e265a2..9a02c863 100755
--- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js.map
+++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/autoconvert.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"autoconvert.min.js","sources":["../src/autoconvert.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 .\n\n/**\n * Tiny MediaCMS Auto-convert module.\n *\n * This module automatically converts pasted MediaCMS URLs into embedded videos.\n * When a user pastes a MediaCMS video URL (e.g., https://deic.mediacms.io/view?m=JpBd1Zvdl),\n * it will be automatically converted to an iframe embed.\n *\n * @module tiny_mediacms/autoconvert\n * @copyright 2024\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {getData} from './options';\n\n/**\n * Regular expression patterns for MediaCMS URLs.\n * Matches URLs like:\n * - https://deic.mediacms.io/view?m=JpBd1Zvdl\n * - https://example.mediacms.io/view?m=VIDEO_ID\n * - Custom domains configured in the plugin\n */\nconst MEDIACMS_VIEW_URL_PATTERN = /^(https?:\\/\\/[^\\/]+)\\/view\\?m=([a-zA-Z0-9_-]+)$/;\n\n/**\n * Check if a string is a valid MediaCMS view URL.\n *\n * @param {string} text - The text to check\n * @returns {Object|null} - Parsed URL info or null if not a valid MediaCMS URL\n */\nconst parseMediaCMSUrl = (text) => {\n if (!text || typeof text !== 'string') {\n return null;\n }\n\n const trimmed = text.trim();\n\n // Check for MediaCMS view URL pattern\n const match = trimmed.match(MEDIACMS_VIEW_URL_PATTERN);\n if (match) {\n return {\n baseUrl: match[1],\n videoId: match[2],\n originalUrl: trimmed,\n };\n }\n\n return null;\n};\n\n/**\n * Check if the pasted URL's domain is allowed based on configuration.\n *\n * @param {Object} parsed - Parsed URL info\n * @param {Object} config - Plugin configuration\n * @returns {boolean} - True if the domain is allowed\n */\nconst isDomainAllowed = (parsed, config) => {\n // If no specific base URL is configured, allow all MediaCMS domains\n const configuredBaseUrl = config.autoConvertBaseUrl || config.mediacmsBaseUrl;\n if (!configuredBaseUrl) {\n return true;\n }\n\n // Check if the URL's base matches the configured base URL\n try {\n const configuredUrl = new URL(configuredBaseUrl);\n const pastedUrl = new URL(parsed.baseUrl);\n return configuredUrl.host === pastedUrl.host;\n } catch (e) {\n // If URL parsing fails, allow the conversion\n return true;\n }\n};\n\n/**\n * Generate the iframe embed HTML for a MediaCMS video.\n *\n * @param {Object} parsed - Parsed URL info\n * @param {Object} options - Embed options\n * @returns {string} - The iframe HTML\n */\nconst generateEmbedHtml = (parsed, options = {}) => {\n // Build the embed URL with default options\n const embedUrl = new URL(`${parsed.baseUrl}/embed`);\n embedUrl.searchParams.set('m', parsed.videoId);\n\n // Apply default options (all enabled by default for best user experience)\n embedUrl.searchParams.set('showTitle', options.showTitle !== false ? '1' : '0');\n embedUrl.searchParams.set('showRelated', options.showRelated !== false ? '1' : '0');\n embedUrl.searchParams.set('showUserAvatar', options.showUserAvatar !== false ? '1' : '0');\n embedUrl.searchParams.set('linkTitle', options.linkTitle !== false ? '1' : '0');\n\n // Generate responsive iframe HTML matching the template output format.\n // Uses aspect-ratio CSS for responsive sizing (16:9 default).\n // The wrapper will be added by editor for UI (edit button), then stripped on save.\n const html = ``;\n\n return html;\n};\n\n/**\n * Set up auto-conversion for the editor.\n * This registers event handlers to detect pasted MediaCMS URLs.\n *\n * @param {TinyMCE} editor - The TinyMCE editor instance\n */\nexport const setupAutoConvert = (editor) => {\n const config = getData(editor) || {};\n\n // Check if auto-convert is enabled (default: true)\n if (config.autoConvertEnabled === false) {\n return;\n }\n\n // Handle paste events\n editor.on('paste', (e) => {\n handlePasteEvent(editor, e, config);\n });\n\n // Also handle input events for drag-and-drop text or keyboard paste\n editor.on('input', (e) => {\n handleInputEvent(editor, e, config);\n });\n};\n\n/**\n * Handle paste events to detect and convert MediaCMS URLs.\n *\n * @param {TinyMCE} editor - The TinyMCE editor instance\n * @param {Event} e - The paste event\n * @param {Object} config - Plugin configuration\n */\nconst handlePasteEvent = (editor, e, config) => {\n // Get pasted text from clipboard\n const clipboardData = e.clipboardData || window.clipboardData;\n if (!clipboardData) {\n return;\n }\n\n // Try to get plain text first\n const text = clipboardData.getData('text/plain') || clipboardData.getData('text');\n if (!text) {\n return;\n }\n\n // Check if it's a MediaCMS URL\n const parsed = parseMediaCMSUrl(text);\n if (!parsed) {\n return;\n }\n\n // Check if domain is allowed\n if (!isDomainAllowed(parsed, config)) {\n return;\n }\n\n // Prevent default paste behavior\n e.preventDefault();\n e.stopPropagation();\n\n // Generate and insert the embed HTML\n const embedHtml = generateEmbedHtml(parsed, config.autoConvertOptions || {});\n\n // Use a slight delay to ensure the editor is ready\n setTimeout(() => {\n editor.insertContent(embedHtml);\n // Move cursor after the inserted content\n editor.selection.collapse(false);\n }, 0);\n};\n\n/**\n * Handle input events to catch URLs that might have been pasted without triggering paste event.\n * This is a fallback for certain browsers/scenarios.\n *\n * @param {TinyMCE} editor - The TinyMCE editor instance\n * @param {Event} e - The input event\n * @param {Object} config - Plugin configuration\n */\nconst handleInputEvent = (editor, e, config) => {\n // Only process inputType 'insertFromPaste' if paste event didn't catch it\n if (e.inputType !== 'insertFromPaste' && e.inputType !== 'insertText') {\n return;\n }\n\n // Get the current node and check if it contains just a URL\n const node = editor.selection.getNode();\n if (!node || node.nodeName !== 'P') {\n return;\n }\n\n // Check if the paragraph contains only a MediaCMS URL\n const text = node.textContent || '';\n const parsed = parseMediaCMSUrl(text);\n\n if (!parsed || !isDomainAllowed(parsed, config)) {\n return;\n }\n\n // Don't convert if there's other content in the paragraph\n const trimmedHtml = node.innerHTML.trim();\n if (trimmedHtml !== text.trim() && !trimmedHtml.startsWith(text.trim())) {\n return;\n }\n\n // Generate the embed HTML\n const embedHtml = generateEmbedHtml(parsed, config.autoConvertOptions || {});\n\n // Replace the paragraph content with the embed\n // Use a slight delay to let the input event complete\n setTimeout(() => {\n // Re-check that the node still contains the URL (user might have typed more)\n const currentText = node.textContent || '';\n const currentParsed = parseMediaCMSUrl(currentText);\n\n if (currentParsed && currentParsed.originalUrl === parsed.originalUrl) {\n // Select and replace the entire node\n editor.selection.select(node);\n editor.insertContent(embedHtml);\n }\n }, 100);\n};\n\n/**\n * Check if a text is a MediaCMS URL (public helper).\n *\n * @param {string} text - The text to check\n * @returns {boolean} - True if it's a MediaCMS URL\n */\nexport const isMediaCMSUrl = (text) => {\n return parseMediaCMSUrl(text) !== null;\n};\n\n/**\n * Convert a MediaCMS URL to embed HTML (public helper).\n *\n * @param {string} url - The MediaCMS URL\n * @param {Object} options - Embed options\n * @returns {string|null} - The embed HTML or null if not a valid URL\n */\nexport const convertToEmbed = (url, options = {}) => {\n const parsed = parseMediaCMSUrl(url);\n if (!parsed) {\n return null;\n }\n return generateEmbedHtml(parsed, options);\n};\n"],"names":["MEDIACMS_VIEW_URL_PATTERN","parseMediaCMSUrl","text","trimmed","trim","match","baseUrl","videoId","originalUrl","isDomainAllowed","parsed","config","configuredBaseUrl","autoConvertBaseUrl","mediacmsBaseUrl","configuredUrl","URL","pastedUrl","host","e","generateEmbedHtml","options","embedUrl","searchParams","set","showTitle","showRelated","showUserAvatar","linkTitle","html","toString","editor","autoConvertEnabled","on","handlePasteEvent","handleInputEvent","clipboardData","window","getData","preventDefault","stopPropagation","embedHtml","autoConvertOptions","setTimeout","insertContent","selection","collapse","inputType","node","getNode","nodeName","textContent","trimmedHtml","innerHTML","startsWith","currentText","currentParsed","select","url"],"mappings":";;;;;;;;;;;;MAoCMA,0BAA4B,kDAQ5BC,iBAAoBC,WACjBA,MAAwB,iBAATA,YACT,WAGLC,QAAUD,KAAKE,OAGfC,MAAQF,QAAQE,MAAML,kCACxBK,MACO,CACHC,QAASD,MAAM,GACfE,QAASF,MAAM,GACfG,YAAaL,SAId,MAULM,gBAAkB,CAACC,OAAQC,gBAEvBC,kBAAoBD,OAAOE,oBAAsBF,OAAOG,oBACzDF,yBACM,YAKDG,cAAgB,IAAIC,IAAIJ,mBACxBK,UAAY,IAAID,IAAIN,OAAOJ,gBAC1BS,cAAcG,OAASD,UAAUC,KAC1C,MAAOC,UAEE,IAWTC,kBAAoB,SAACV,YAAQW,+DAAU,SAEnCC,SAAW,IAAIN,cAAON,OAAOJ,mBACnCgB,SAASC,aAAaC,IAAI,IAAKd,OAAOH,SAGtCe,SAASC,aAAaC,IAAI,aAAmC,IAAtBH,QAAQI,UAAsB,IAAM,KAC3EH,SAASC,aAAaC,IAAI,eAAuC,IAAxBH,QAAQK,YAAwB,IAAM,KAC/EJ,SAASC,aAAaC,IAAI,kBAA6C,IAA3BH,QAAQM,eAA2B,IAAM,KACrFL,SAASC,aAAaC,IAAI,aAAmC,IAAtBH,QAAQO,UAAsB,IAAM,WAKrEC,KAAO,uBAAgBP,SAASQ,iBAAzB,2HAIND,gCASsBE,eACvBpB,QAAS,oBAAQoB,SAAW,IAGA,IAA9BpB,OAAOqB,qBAKXD,OAAOE,GAAG,SAAUd,IAChBe,iBAAiBH,OAAQZ,EAAGR,WAIhCoB,OAAOE,GAAG,SAAUd,IAChBgB,iBAAiBJ,OAAQZ,EAAGR,mBAW9BuB,iBAAmB,CAACH,OAAQZ,EAAGR,gBAE3ByB,cAAgBjB,EAAEiB,eAAiBC,OAAOD,kBAC3CA,2BAKClC,KAAOkC,cAAcE,QAAQ,eAAiBF,cAAcE,QAAQ,YACrEpC,kBAKCQ,OAAST,iBAAiBC,UAC3BQ,kBAKAD,gBAAgBC,OAAQC,eAK7BQ,EAAEoB,iBACFpB,EAAEqB,wBAGIC,UAAYrB,kBAAkBV,OAAQC,OAAO+B,oBAAsB,IAGzEC,YAAW,KACPZ,OAAOa,cAAcH,WAErBV,OAAOc,UAAUC,UAAS,KAC3B,IAWDX,iBAAmB,CAACJ,OAAQZ,EAAGR,aAEb,oBAAhBQ,EAAE4B,WAAmD,eAAhB5B,EAAE4B,uBAKrCC,KAAOjB,OAAOc,UAAUI,cACzBD,MAA0B,MAAlBA,KAAKE,sBAKZhD,KAAO8C,KAAKG,aAAe,GAC3BzC,OAAST,iBAAiBC,UAE3BQ,SAAWD,gBAAgBC,OAAQC,qBAKlCyC,YAAcJ,KAAKK,UAAUjD,UAC/BgD,cAAgBlD,KAAKE,SAAWgD,YAAYE,WAAWpD,KAAKE,qBAK1DqC,UAAYrB,kBAAkBV,OAAQC,OAAO+B,oBAAsB,IAIzEC,YAAW,WAEDY,YAAcP,KAAKG,aAAe,GAClCK,cAAgBvD,iBAAiBsD,aAEnCC,eAAiBA,cAAchD,cAAgBE,OAAOF,cAEtDuB,OAAOc,UAAUY,OAAOT,MACxBjB,OAAOa,cAAcH,cAE1B,6BASuBvC,MACQ,OAA3BD,iBAAiBC,8BAUE,SAACwD,SAAKrC,+DAAU,SACpCX,OAAST,iBAAiByD,YAC3BhD,OAGEU,kBAAkBV,OAAQW,SAFtB"}
\ No newline at end of file
+{"version":3,"file":"autoconvert.min.js","sources":["../src/autoconvert.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 .\n\n/**\n * Tiny MediaCMS Auto-convert module.\n *\n * This module automatically converts pasted MediaCMS URLs into embedded videos.\n * When a user pastes a MediaCMS video URL (e.g., https://deic.mediacms.io/view?m=JpBd1Zvdl),\n * it will be automatically converted to an iframe embed.\n *\n * @module tiny_mediacms/autoconvert\n * @copyright 2024\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {getData} from './options';\n\n/**\n * Regular expression patterns for MediaCMS URLs.\n * Matches URLs like:\n * - https://deic.mediacms.io/view?m=JpBd1Zvdl\n * - https://example.mediacms.io/view?m=VIDEO_ID\n * - Custom domains configured in the plugin\n */\nconst MEDIACMS_VIEW_URL_PATTERN = /^(https?:\\/\\/[^\\/]+)\\/view\\?m=([a-zA-Z0-9_-]+)$/;\n\n/**\n * Check if a string is a valid MediaCMS view URL.\n *\n * @param {string} text - The text to check\n * @returns {Object|null} - Parsed URL info or null if not a valid MediaCMS URL\n */\nconst parseMediaCMSUrl = (text) => {\n if (!text || typeof text !== 'string') {\n return null;\n }\n\n const trimmed = text.trim();\n\n // Check for MediaCMS view URL pattern\n const match = trimmed.match(MEDIACMS_VIEW_URL_PATTERN);\n if (match) {\n return {\n baseUrl: match[1],\n videoId: match[2],\n originalUrl: trimmed,\n };\n }\n\n return null;\n};\n\n/**\n * Check if the pasted URL's domain is allowed based on configuration.\n *\n * @param {Object} parsed - Parsed URL info\n * @param {Object} config - Plugin configuration\n * @returns {boolean} - True if the domain is allowed\n */\nconst isDomainAllowed = (parsed, config) => {\n // If no specific base URL is configured, allow all MediaCMS domains\n const configuredBaseUrl = config.autoConvertBaseUrl || config.mediacmsBaseUrl;\n if (!configuredBaseUrl) {\n return true;\n }\n\n // Check if the URL's base matches the configured base URL\n try {\n const configuredUrl = new URL(configuredBaseUrl);\n const pastedUrl = new URL(parsed.baseUrl);\n return configuredUrl.host === pastedUrl.host;\n } catch (e) {\n // If URL parsing fails, allow the conversion\n return true;\n }\n};\n\n/**\n * Generate the iframe embed HTML for a MediaCMS video.\n *\n * @param {Object} parsed - Parsed URL info\n * @param {Object} options - Embed options\n * @returns {string} - The iframe HTML\n */\nconst generateEmbedHtml = (parsed, options = {}) => {\n // Build the embed URL with default options\n const embedUrl = new URL(`${parsed.baseUrl}/embed`);\n embedUrl.searchParams.set('m', parsed.videoId);\n\n // Apply default options (all enabled by default for best user experience)\n embedUrl.searchParams.set('showTitle', options.showTitle !== false ? '1' : '0');\n embedUrl.searchParams.set('showUserAvatar', options.showUserAvatar !== false ? '1' : '0');\n embedUrl.searchParams.set('linkTitle', options.linkTitle !== false ? '1' : '0');\n\n // Generate responsive iframe HTML matching the template output format.\n // Uses aspect-ratio CSS for responsive sizing (16:9 default).\n // The wrapper will be added by editor for UI (edit button), then stripped on save.\n const html = ``;\n\n return html;\n};\n\n/**\n * Set up auto-conversion for the editor.\n * This registers event handlers to detect pasted MediaCMS URLs.\n *\n * @param {TinyMCE} editor - The TinyMCE editor instance\n */\nexport const setupAutoConvert = (editor) => {\n const config = getData(editor) || {};\n\n // Check if auto-convert is enabled (default: true)\n if (config.autoConvertEnabled === false) {\n return;\n }\n\n // Handle paste events\n editor.on('paste', (e) => {\n handlePasteEvent(editor, e, config);\n });\n\n // Also handle input events for drag-and-drop text or keyboard paste\n editor.on('input', (e) => {\n handleInputEvent(editor, e, config);\n });\n};\n\n/**\n * Handle paste events to detect and convert MediaCMS URLs.\n *\n * @param {TinyMCE} editor - The TinyMCE editor instance\n * @param {Event} e - The paste event\n * @param {Object} config - Plugin configuration\n */\nconst handlePasteEvent = (editor, e, config) => {\n // Get pasted text from clipboard\n const clipboardData = e.clipboardData || window.clipboardData;\n if (!clipboardData) {\n return;\n }\n\n // Try to get plain text first\n const text = clipboardData.getData('text/plain') || clipboardData.getData('text');\n if (!text) {\n return;\n }\n\n // Check if it's a MediaCMS URL\n const parsed = parseMediaCMSUrl(text);\n if (!parsed) {\n return;\n }\n\n // Check if domain is allowed\n if (!isDomainAllowed(parsed, config)) {\n return;\n }\n\n // Prevent default paste behavior\n e.preventDefault();\n e.stopPropagation();\n\n // Generate and insert the embed HTML\n const embedHtml = generateEmbedHtml(parsed, config.autoConvertOptions || {});\n\n // Use a slight delay to ensure the editor is ready\n setTimeout(() => {\n editor.insertContent(embedHtml);\n // Move cursor after the inserted content\n editor.selection.collapse(false);\n }, 0);\n};\n\n/**\n * Handle input events to catch URLs that might have been pasted without triggering paste event.\n * This is a fallback for certain browsers/scenarios.\n *\n * @param {TinyMCE} editor - The TinyMCE editor instance\n * @param {Event} e - The input event\n * @param {Object} config - Plugin configuration\n */\nconst handleInputEvent = (editor, e, config) => {\n // Only process inputType 'insertFromPaste' if paste event didn't catch it\n if (e.inputType !== 'insertFromPaste' && e.inputType !== 'insertText') {\n return;\n }\n\n // Get the current node and check if it contains just a URL\n const node = editor.selection.getNode();\n if (!node || node.nodeName !== 'P') {\n return;\n }\n\n // Check if the paragraph contains only a MediaCMS URL\n const text = node.textContent || '';\n const parsed = parseMediaCMSUrl(text);\n\n if (!parsed || !isDomainAllowed(parsed, config)) {\n return;\n }\n\n // Don't convert if there's other content in the paragraph\n const trimmedHtml = node.innerHTML.trim();\n if (trimmedHtml !== text.trim() && !trimmedHtml.startsWith(text.trim())) {\n return;\n }\n\n // Generate the embed HTML\n const embedHtml = generateEmbedHtml(parsed, config.autoConvertOptions || {});\n\n // Replace the paragraph content with the embed\n // Use a slight delay to let the input event complete\n setTimeout(() => {\n // Re-check that the node still contains the URL (user might have typed more)\n const currentText = node.textContent || '';\n const currentParsed = parseMediaCMSUrl(currentText);\n\n if (currentParsed && currentParsed.originalUrl === parsed.originalUrl) {\n // Select and replace the entire node\n editor.selection.select(node);\n editor.insertContent(embedHtml);\n }\n }, 100);\n};\n\n/**\n * Check if a text is a MediaCMS URL (public helper).\n *\n * @param {string} text - The text to check\n * @returns {boolean} - True if it's a MediaCMS URL\n */\nexport const isMediaCMSUrl = (text) => {\n return parseMediaCMSUrl(text) !== null;\n};\n\n/**\n * Convert a MediaCMS URL to embed HTML (public helper).\n *\n * @param {string} url - The MediaCMS URL\n * @param {Object} options - Embed options\n * @returns {string|null} - The embed HTML or null if not a valid URL\n */\nexport const convertToEmbed = (url, options = {}) => {\n const parsed = parseMediaCMSUrl(url);\n if (!parsed) {\n return null;\n }\n return generateEmbedHtml(parsed, options);\n};\n"],"names":["MEDIACMS_VIEW_URL_PATTERN","parseMediaCMSUrl","text","trimmed","trim","match","baseUrl","videoId","originalUrl","isDomainAllowed","parsed","config","configuredBaseUrl","autoConvertBaseUrl","mediacmsBaseUrl","configuredUrl","URL","pastedUrl","host","e","generateEmbedHtml","options","embedUrl","searchParams","set","showTitle","showUserAvatar","linkTitle","html","toString","editor","autoConvertEnabled","on","handlePasteEvent","handleInputEvent","clipboardData","window","getData","preventDefault","stopPropagation","embedHtml","autoConvertOptions","setTimeout","insertContent","selection","collapse","inputType","node","getNode","nodeName","textContent","trimmedHtml","innerHTML","startsWith","currentText","currentParsed","select","url"],"mappings":";;;;;;;;;;;;MAoCMA,0BAA4B,kDAQ5BC,iBAAoBC,WACjBA,MAAwB,iBAATA,YACT,WAGLC,QAAUD,KAAKE,OAGfC,MAAQF,QAAQE,MAAML,kCACxBK,MACO,CACHC,QAASD,MAAM,GACfE,QAASF,MAAM,GACfG,YAAaL,SAId,MAULM,gBAAkB,CAACC,OAAQC,gBAEvBC,kBAAoBD,OAAOE,oBAAsBF,OAAOG,oBACzDF,yBACM,YAKDG,cAAgB,IAAIC,IAAIJ,mBACxBK,UAAY,IAAID,IAAIN,OAAOJ,gBAC1BS,cAAcG,OAASD,UAAUC,KAC1C,MAAOC,UAEE,IAWTC,kBAAoB,SAACV,YAAQW,+DAAU,SAEnCC,SAAW,IAAIN,cAAON,OAAOJ,mBACnCgB,SAASC,aAAaC,IAAI,IAAKd,OAAOH,SAGtCe,SAASC,aAAaC,IAAI,aAAmC,IAAtBH,QAAQI,UAAsB,IAAM,KAC3EH,SAASC,aAAaC,IAAI,kBAA6C,IAA3BH,QAAQK,eAA2B,IAAM,KACrFJ,SAASC,aAAaC,IAAI,aAAmC,IAAtBH,QAAQM,UAAsB,IAAM,WAKrEC,KAAO,uBAAgBN,SAASO,iBAAzB,2HAIND,gCASsBE,eACvBnB,QAAS,oBAAQmB,SAAW,IAGA,IAA9BnB,OAAOoB,qBAKXD,OAAOE,GAAG,SAAUb,IAChBc,iBAAiBH,OAAQX,EAAGR,WAIhCmB,OAAOE,GAAG,SAAUb,IAChBe,iBAAiBJ,OAAQX,EAAGR,mBAW9BsB,iBAAmB,CAACH,OAAQX,EAAGR,gBAE3BwB,cAAgBhB,EAAEgB,eAAiBC,OAAOD,kBAC3CA,2BAKCjC,KAAOiC,cAAcE,QAAQ,eAAiBF,cAAcE,QAAQ,YACrEnC,kBAKCQ,OAAST,iBAAiBC,UAC3BQ,kBAKAD,gBAAgBC,OAAQC,eAK7BQ,EAAEmB,iBACFnB,EAAEoB,wBAGIC,UAAYpB,kBAAkBV,OAAQC,OAAO8B,oBAAsB,IAGzEC,YAAW,KACPZ,OAAOa,cAAcH,WAErBV,OAAOc,UAAUC,UAAS,KAC3B,IAWDX,iBAAmB,CAACJ,OAAQX,EAAGR,aAEb,oBAAhBQ,EAAE2B,WAAmD,eAAhB3B,EAAE2B,uBAKrCC,KAAOjB,OAAOc,UAAUI,cACzBD,MAA0B,MAAlBA,KAAKE,sBAKZ/C,KAAO6C,KAAKG,aAAe,GAC3BxC,OAAST,iBAAiBC,UAE3BQ,SAAWD,gBAAgBC,OAAQC,qBAKlCwC,YAAcJ,KAAKK,UAAUhD,UAC/B+C,cAAgBjD,KAAKE,SAAW+C,YAAYE,WAAWnD,KAAKE,qBAK1DoC,UAAYpB,kBAAkBV,OAAQC,OAAO8B,oBAAsB,IAIzEC,YAAW,WAEDY,YAAcP,KAAKG,aAAe,GAClCK,cAAgBtD,iBAAiBqD,aAEnCC,eAAiBA,cAAc/C,cAAgBE,OAAOF,cAEtDsB,OAAOc,UAAUY,OAAOT,MACxBjB,OAAOa,cAAcH,cAE1B,6BASuBtC,MACQ,OAA3BD,iBAAiBC,8BAUE,SAACuD,SAAKpC,+DAAU,SACpCX,OAAST,iBAAiBwD,YAC3B/C,OAGEU,kBAAkBV,OAAQW,SAFtB"}
\ No newline at end of file
diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js
index 81a092fb..97d61d05 100755
--- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js
+++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js
@@ -1,3 +1,3 @@
-define("tiny_mediacms/iframeembed",["exports","core/templates","core/str","core/modal_events","./common","./iframemodal","./selectors","./options"],(function(_exports,_templates,_str,ModalEvents,_common,_iframemodal,_selectors,_options){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 _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,_templates=_interopRequireDefault(_templates),ModalEvents=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(ModalEvents),_iframemodal=_interopRequireDefault(_iframemodal),_selectors=_interopRequireDefault(_selectors);return _exports.default=class{constructor(editor){_defineProperty(this,"editor",null),_defineProperty(this,"currentModal",null),_defineProperty(this,"isUpdating",!1),_defineProperty(this,"selectedIframe",null),_defineProperty(this,"debounceTimer",null),_defineProperty(this,"iframeLibraryUrl","https://temp.web357.com/mediacms/deic-mediacms-embed-videos.html"),this.editor=editor}parseInput(input){if(!input||!input.trim())return null;const iframeMatch=(input=input.trim()).match(/