From 7e7cd10549affb9dbd2b28409f6400306cf26bae Mon Sep 17 00:00:00 2001 From: Markos Gogoulos Date: Thu, 12 Feb 2026 13:20:35 +0200 Subject: [PATCH] wtv --- .../mediacms-moodle/tiny/mediacms/amd/build/commands.min.js | 2 +- .../mediacms-moodle/tiny/mediacms/amd/build/commands.min.js.map | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js index b4f9dcb7..52a5f010 100755 --- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js +++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js @@ -5,6 +5,6 @@ define("tiny_mediacms/commands",["exports","core/str","./common","./iframeembed" * @module tiny_mediacms/commands * @copyright 2022 Huong Nguyen * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.getSetup=void 0,_iframeembed=(obj=_iframeembed)&&obj.__esModule?obj:{default:obj};const isIframe=node=>"iframe"===node.nodeName.toLowerCase()||node.classList&&node.classList.contains("tiny-iframe-responsive")||node.classList&&node.classList.contains("tiny-mediacms-iframe-wrapper"),setupIframeOverlays=(editor,handleIframeAction)=>{const processIframes=()=>{const editorBody=editor.getBody();if(!editorBody)return;editorBody.querySelectorAll("iframe").forEach((iframe=>{var _iframe$parentElement;if(null!==(_iframe$parentElement=iframe.parentElement)&&void 0!==_iframe$parentElement&&_iframe$parentElement.classList.contains("tiny-mediacms-iframe-wrapper"))return;if(iframe.hasAttribute("data-mce-object")||iframe.hasAttribute("data-mce-placeholder"))return;const wrapper=editor.getDoc().createElement("div");wrapper.className="tiny-mediacms-iframe-wrapper",wrapper.setAttribute("contenteditable","false");const editBtn=editor.getDoc().createElement("button");editBtn.className="tiny-mediacms-edit-btn",editBtn.setAttribute("type","button"),editBtn.setAttribute("title","Edit media embed options"),editBtn.textContent="EDIT",iframe.parentNode.insertBefore(wrapper,iframe),wrapper.appendChild(iframe),wrapper.appendChild(editBtn)}))},handleOverlayClick=e=>{const editBtn=e.target.closest(".tiny-mediacms-edit-btn");if(!editBtn)return;e.preventDefault(),e.stopPropagation();const wrapper=editBtn.closest(".tiny-mediacms-iframe-wrapper");if(!wrapper)return;wrapper.querySelector("iframe")&&(editor.selection.select(wrapper),handleIframeAction())};editor.on("init",(()=>{(()=>{const editorDoc=editor.getDoc();if(!editorDoc)return;if(editorDoc.getElementById("tiny-mediacms-overlay-styles"))return;const style=editorDoc.createElement("style");style.id="tiny-mediacms-overlay-styles",style.textContent="\n .tiny-mediacms-iframe-wrapper {\n display: inline-block;\n position: relative;\n line-height: 0;\n vertical-align: top;\n margin-top: 40px;\n }\n .tiny-mediacms-iframe-wrapper iframe {\n display: block;\n }\n .tiny-mediacms-edit-btn {\n position: absolute;\n top: -35px;\n left: 50%;\n transform: translateX(-50%);\n background: rgba(0, 0, 0, 0.7);\n color: #ffffff;\n border: none;\n border-radius: 3px;\n cursor: pointer;\n z-index: 10;\n padding: 4px 12px;\n margin: 0;\n font-size: 12px;\n font-weight: bold;\n text-decoration: none;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n transition: background 0.15s, box-shadow 0.15s;\n display: inline-block;\n box-sizing: border-box;\n }\n .tiny-mediacms-edit-btn:hover {\n background: rgba(0, 0, 0, 0.85);\n box-shadow: 0 3px 6px rgba(0,0,0,0.4);\n }\n ",editorDoc.head.appendChild(style)})(),processIframes(),editor.getBody().addEventListener("click",handleOverlayClick)})),editor.on("SetContent",(()=>{processIframes()})),editor.on("PastePostProcess",(()=>{setTimeout(processIframes,100)})),editor.on("Undo Redo",(()=>{processIframes()})),editor.on("Change",(()=>{setTimeout(processIframes,50)})),editor.on("NodeChange",(()=>{processIframes()}))};_exports.getSetup=async()=>{const[iframeButtonText]=await(0,_str.getStrings)(["iframebuttontitle"].map((key=>({key:key,component:_common.component})))),[iframeButtonImage]=await Promise.all([(0,_utils.getButtonImage)("icon",_common.component)]);return editor=>{((editor,iframeButtonText,iframeButtonImage)=>{const handleIframeAction=()=>{new _iframeembed.default(editor).displayDialogue()};editor.ui.registry.addIcon(_common.iframeIcon,iframeButtonImage.html),editor.ui.registry.addToggleButton(_common.iframeButtonName,{icon:_common.iframeIcon,tooltip:iframeButtonText,onAction:handleIframeAction,onSetup:api=>editor.selection.selectorChangedWithUnbind("iframe:not([data-mce-object]):not([data-mce-placeholder]),.tiny-iframe-responsive,.tiny-mediacms-iframe-wrapper",api.setActive).unbind}),editor.ui.registry.addMenuItem(_common.iframeMenuItemName,{icon:_common.iframeIcon,text:iframeButtonText,onAction:handleIframeAction}),editor.ui.registry.addContextToolbar(_common.iframeButtonName,{predicate:isIframe,items:_common.iframeButtonName,position:"node",scope:"node"}),editor.ui.registry.addContextMenu(_common.iframeButtonName,{update:isIframe}),setupIframeOverlays(editor,handleIframeAction)})(editor,iframeButtonText,iframeButtonImage)}}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.getSetup=void 0,_iframeembed=(obj=_iframeembed)&&obj.__esModule?obj:{default:obj};const isIframe=node=>"iframe"===node.nodeName.toLowerCase()||node.classList&&node.classList.contains("tiny-iframe-responsive")||node.classList&&node.classList.contains("tiny-mediacms-iframe-wrapper"),setupIframeOverlays=(editor,handleIframeAction)=>{const processIframes=()=>{const editorBody=editor.getBody();if(!editorBody)return;editorBody.querySelectorAll("iframe").forEach((iframe=>{var _iframe$parentElement;if(null!==(_iframe$parentElement=iframe.parentElement)&&void 0!==_iframe$parentElement&&_iframe$parentElement.classList.contains("tiny-mediacms-iframe-wrapper"))return;if(iframe.hasAttribute("data-mce-object")||iframe.hasAttribute("data-mce-placeholder"))return;const wrapper=editor.getDoc().createElement("div");wrapper.className="tiny-mediacms-iframe-wrapper",wrapper.setAttribute("contenteditable","false");const editBtn=editor.getDoc().createElement("button");editBtn.className="tiny-mediacms-edit-btn",editBtn.setAttribute("type","button"),editBtn.setAttribute("title","Edit media embed options"),editBtn.textContent="EDIT",iframe.parentNode.insertBefore(wrapper,iframe),wrapper.appendChild(iframe),wrapper.appendChild(editBtn)}))},handleOverlayClick=e=>{const editBtn=e.target.closest(".tiny-mediacms-edit-btn");if(!editBtn)return;e.preventDefault(),e.stopPropagation();const wrapper=editBtn.closest(".tiny-mediacms-iframe-wrapper");if(!wrapper)return;wrapper.querySelector("iframe")&&(editor.selection.select(wrapper),handleIframeAction())};editor.on("init",(()=>{(()=>{const editorDoc=editor.getDoc();if(!editorDoc)return;if(editorDoc.getElementById("tiny-mediacms-overlay-styles"))return;const style=editorDoc.createElement("style");style.id="tiny-mediacms-overlay-styles",style.textContent="\n .tiny-mediacms-iframe-wrapper {\n display: inline-block;\n position: relative;\n line-height: 0;\n vertical-align: top;\n margin-top: 40px;\n }\n .tiny-mediacms-iframe-wrapper iframe {\n display: block;\n }\n .tiny-mediacms-edit-btn {\n position: absolute;\n top: -15px;\n left: 50%;\n transform: translateX(-50%);\n background: rgba(0, 0, 0, 0.7);\n color: #ffffff;\n border: none;\n border-radius: 3px;\n cursor: pointer;\n z-index: 10;\n padding: 4px 12px;\n margin: 0;\n font-size: 12px;\n font-weight: bold;\n text-decoration: none;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n transition: background 0.15s, box-shadow 0.15s;\n display: inline-block;\n box-sizing: border-box;\n }\n .tiny-mediacms-edit-btn:hover {\n background: rgba(0, 0, 0, 0.85);\n box-shadow: 0 3px 6px rgba(0,0,0,0.4);\n }\n ",editorDoc.head.appendChild(style)})(),processIframes(),editor.getBody().addEventListener("click",handleOverlayClick)})),editor.on("SetContent",(()=>{processIframes()})),editor.on("PastePostProcess",(()=>{setTimeout(processIframes,100)})),editor.on("Undo Redo",(()=>{processIframes()})),editor.on("Change",(()=>{setTimeout(processIframes,50)})),editor.on("NodeChange",(()=>{processIframes()}))};_exports.getSetup=async()=>{const[iframeButtonText]=await(0,_str.getStrings)(["iframebuttontitle"].map((key=>({key:key,component:_common.component})))),[iframeButtonImage]=await Promise.all([(0,_utils.getButtonImage)("icon",_common.component)]);return editor=>{((editor,iframeButtonText,iframeButtonImage)=>{const handleIframeAction=()=>{new _iframeembed.default(editor).displayDialogue()};editor.ui.registry.addIcon(_common.iframeIcon,iframeButtonImage.html),editor.ui.registry.addToggleButton(_common.iframeButtonName,{icon:_common.iframeIcon,tooltip:iframeButtonText,onAction:handleIframeAction,onSetup:api=>editor.selection.selectorChangedWithUnbind("iframe:not([data-mce-object]):not([data-mce-placeholder]),.tiny-iframe-responsive,.tiny-mediacms-iframe-wrapper",api.setActive).unbind}),editor.ui.registry.addMenuItem(_common.iframeMenuItemName,{icon:_common.iframeIcon,text:iframeButtonText,onAction:handleIframeAction}),editor.ui.registry.addContextToolbar(_common.iframeButtonName,{predicate:isIframe,items:_common.iframeButtonName,position:"node",scope:"node"}),editor.ui.registry.addContextMenu(_common.iframeButtonName,{update:isIframe}),setupIframeOverlays(editor,handleIframeAction)})(editor,iframeButtonText,iframeButtonImage)}}})); //# sourceMappingURL=commands.min.js.map \ No newline at end of file diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js.map b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js.map index 1d2d06d8..50b18a9b 100755 --- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js.map +++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/commands.min.js.map @@ -1 +1 @@ -{"version":3,"file":"commands.min.js","sources":["../src/commands.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 Media commands.\n *\n * @module tiny_mediacms/commands\n * @copyright 2022 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {getStrings} from 'core/str';\nimport {\n component,\n iframeButtonName,\n iframeMenuItemName,\n iframeIcon,\n} from './common';\nimport IframeEmbed from './iframeembed';\nimport {getButtonImage} from 'editor_tiny/utils';\n\nconst isIframe = (node) => node.nodeName.toLowerCase() === 'iframe' ||\n (node.classList && node.classList.contains('tiny-iframe-responsive')) ||\n (node.classList && node.classList.contains('tiny-mediacms-iframe-wrapper'));\n\n/**\n * Wrap iframes with overlay containers that allow hover detection.\n * Since iframes capture mouse events, we add an invisible overlay on top\n * that shows the edit button on hover.\n *\n * @param {TinyMCE} editor - The editor instance\n * @param {Function} handleIframeAction - The action to perform when clicking the button\n */\nconst setupIframeOverlays = (editor, handleIframeAction) => {\n /**\n * Process all iframes in the editor and add overlay wrappers.\n */\n const processIframes = () => {\n const editorBody = editor.getBody();\n if (!editorBody) {\n return;\n }\n\n const iframes = editorBody.querySelectorAll('iframe');\n iframes.forEach((iframe) => {\n // Skip if already wrapped\n if (iframe.parentElement?.classList.contains('tiny-mediacms-iframe-wrapper')) {\n return;\n }\n\n // Skip TinyMCE internal iframes\n if (iframe.hasAttribute('data-mce-object') || iframe.hasAttribute('data-mce-placeholder')) {\n return;\n }\n\n // Create wrapper div\n const wrapper = editor.getDoc().createElement('div');\n wrapper.className = 'tiny-mediacms-iframe-wrapper';\n wrapper.setAttribute('contenteditable', 'false');\n\n // Create edit button (positioned inside wrapper, over the iframe)\n const editBtn = editor.getDoc().createElement('button');\n editBtn.className = 'tiny-mediacms-edit-btn';\n editBtn.setAttribute('type', 'button');\n editBtn.setAttribute('title', 'Edit media embed options');\n // Use text \"EDIT\" instead of icon\n editBtn.textContent = 'EDIT';\n\n // Wrap the iframe: insert wrapper, move iframe into it, add button\n iframe.parentNode.insertBefore(wrapper, iframe);\n wrapper.appendChild(iframe);\n wrapper.appendChild(editBtn);\n });\n };\n\n /**\n * Add CSS styles for hover effects to the editor's document.\n */\n const addStyles = () => {\n const editorDoc = editor.getDoc();\n if (!editorDoc) {\n return;\n }\n\n // Check if styles already added\n if (editorDoc.getElementById('tiny-mediacms-overlay-styles')) {\n return;\n }\n\n const style = editorDoc.createElement('style');\n style.id = 'tiny-mediacms-overlay-styles';\n style.textContent = `\n .tiny-mediacms-iframe-wrapper {\n display: inline-block;\n position: relative;\n line-height: 0;\n vertical-align: top;\n margin-top: 40px;\n }\n .tiny-mediacms-iframe-wrapper iframe {\n display: block;\n }\n .tiny-mediacms-edit-btn {\n position: absolute;\n top: -35px;\n left: 50%;\n transform: translateX(-50%);\n background: rgba(0, 0, 0, 0.7);\n color: #ffffff;\n border: none;\n border-radius: 3px;\n cursor: pointer;\n z-index: 10;\n padding: 4px 12px;\n margin: 0;\n font-size: 12px;\n font-weight: bold;\n text-decoration: none;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n transition: background 0.15s, box-shadow 0.15s;\n display: inline-block;\n box-sizing: border-box;\n }\n .tiny-mediacms-edit-btn:hover {\n background: rgba(0, 0, 0, 0.85);\n box-shadow: 0 3px 6px rgba(0,0,0,0.4);\n }\n `;\n editorDoc.head.appendChild(style);\n };\n\n /**\n * Handle click on the edit button.\n *\n * @param {Event} e - The click event\n */\n const handleOverlayClick = (e) => {\n const target = e.target;\n\n // Check if clicked on edit button or its child (svg/path)\n const editBtn = target.closest('.tiny-mediacms-edit-btn');\n if (!editBtn) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n\n // Find the associated wrapper and iframe\n const wrapper = editBtn.closest('.tiny-mediacms-iframe-wrapper');\n if (!wrapper) {\n return;\n }\n\n const iframe = wrapper.querySelector('iframe');\n if (!iframe) {\n return;\n }\n\n // Select the wrapper so TinyMCE knows which element is selected\n editor.selection.select(wrapper);\n\n // Open the edit dialog\n handleIframeAction();\n };\n\n // Setup on editor init\n editor.on('init', () => {\n addStyles();\n processIframes();\n\n // Handle clicks on the overlay\n editor.getBody().addEventListener('click', handleOverlayClick);\n });\n\n // Re-process when content changes\n editor.on('SetContent', () => {\n processIframes();\n });\n\n // Re-process when content is pasted\n editor.on('PastePostProcess', () => {\n setTimeout(processIframes, 100);\n });\n\n // Re-process after undo/redo\n editor.on('Undo Redo', () => {\n processIframes();\n });\n\n // Re-process on any content change (covers modal updates)\n editor.on('Change', () => {\n setTimeout(processIframes, 50);\n });\n\n // Re-process when node changes (selection changes)\n editor.on('NodeChange', () => {\n processIframes();\n });\n};\n\nconst registerIframeCommand = (editor, iframeButtonText, iframeButtonImage) => {\n const handleIframeAction = () => {\n const iframeEmbed = new IframeEmbed(editor);\n iframeEmbed.displayDialogue();\n };\n\n // Register the iframe icon\n editor.ui.registry.addIcon(iframeIcon, iframeButtonImage.html);\n\n // Register the Menu Button as a toggle.\n // This means that when highlighted over an existing iframe element it will show as toggled on.\n editor.ui.registry.addToggleButton(iframeButtonName, {\n icon: iframeIcon,\n tooltip: iframeButtonText,\n onAction: handleIframeAction,\n onSetup: api => {\n return editor.selection.selectorChangedWithUnbind(\n 'iframe:not([data-mce-object]):not([data-mce-placeholder]),.tiny-iframe-responsive,.tiny-mediacms-iframe-wrapper',\n api.setActive\n ).unbind;\n }\n });\n\n editor.ui.registry.addMenuItem(iframeMenuItemName, {\n icon: iframeIcon,\n text: iframeButtonText,\n onAction: handleIframeAction,\n });\n\n editor.ui.registry.addContextToolbar(iframeButtonName, {\n predicate: isIframe,\n items: iframeButtonName,\n position: 'node',\n scope: 'node'\n });\n\n editor.ui.registry.addContextMenu(iframeButtonName, {\n update: isIframe,\n });\n\n // Setup iframe overlays with edit button on hover\n setupIframeOverlays(editor, handleIframeAction);\n};\n\nexport const getSetup = async() => {\n const [\n iframeButtonText,\n ] = await getStrings([\n 'iframebuttontitle',\n ].map((key) => ({key, component})));\n\n const [\n iframeButtonImage,\n ] = await Promise.all([\n getButtonImage('icon', component),\n ]);\n\n // Note: The function returned here must be synchronous and cannot use promises.\n // All promises must be resolved prior to returning the function.\n return (editor) => {\n registerIframeCommand(editor, iframeButtonText, iframeButtonImage);\n };\n};\n"],"names":["isIframe","node","nodeName","toLowerCase","classList","contains","setupIframeOverlays","editor","handleIframeAction","processIframes","editorBody","getBody","querySelectorAll","forEach","iframe","parentElement","_iframe$parentElement","hasAttribute","wrapper","getDoc","createElement","className","setAttribute","editBtn","textContent","parentNode","insertBefore","appendChild","handleOverlayClick","e","target","closest","preventDefault","stopPropagation","querySelector","selection","select","on","editorDoc","getElementById","style","id","head","addStyles","addEventListener","setTimeout","async","iframeButtonText","map","key","component","iframeButtonImage","Promise","all","IframeEmbed","displayDialogue","ui","registry","addIcon","iframeIcon","html","addToggleButton","iframeButtonName","icon","tooltip","onAction","onSetup","api","selectorChangedWithUnbind","setActive","unbind","addMenuItem","iframeMenuItemName","text","addContextToolbar","predicate","items","position","scope","addContextMenu","update","registerIframeCommand"],"mappings":";;;;;;;8JAiCMA,SAAYC,MAAyC,WAAhCA,KAAKC,SAASC,eACpCF,KAAKG,WAAaH,KAAKG,UAAUC,SAAS,2BAC1CJ,KAAKG,WAAaH,KAAKG,UAAUC,SAAS,gCAUzCC,oBAAsB,CAACC,OAAQC,4BAI3BC,eAAiB,WACbC,WAAaH,OAAOI,cACrBD,kBAIWA,WAAWE,iBAAiB,UACpCC,SAASC,oEAETA,OAAOC,gDAAPC,sBAAsBZ,UAAUC,SAAS,0CAKzCS,OAAOG,aAAa,oBAAsBH,OAAOG,aAAa,qCAK5DC,QAAUX,OAAOY,SAASC,cAAc,OAC9CF,QAAQG,UAAY,+BACpBH,QAAQI,aAAa,kBAAmB,eAGlCC,QAAUhB,OAAOY,SAASC,cAAc,UAC9CG,QAAQF,UAAY,yBACpBE,QAAQD,aAAa,OAAQ,UAC7BC,QAAQD,aAAa,QAAS,4BAE9BC,QAAQC,YAAc,OAGtBV,OAAOW,WAAWC,aAAaR,QAASJ,QACxCI,QAAQS,YAAYb,QACpBI,QAAQS,YAAYJ,aAiEtBK,mBAAsBC,UAIlBN,QAHSM,EAAEC,OAGMC,QAAQ,+BAC1BR,eAILM,EAAEG,iBACFH,EAAEI,wBAGIf,QAAUK,QAAQQ,QAAQ,qCAC3Bb,eAIUA,QAAQgB,cAAc,YAMrC3B,OAAO4B,UAAUC,OAAOlB,SAGxBV,uBAIJD,OAAO8B,GAAG,QAAQ,KAzFA,YACRC,UAAY/B,OAAOY,aACpBmB,oBAKDA,UAAUC,eAAe,6CAIvBC,MAAQF,UAAUlB,cAAc,SACtCoB,MAAMC,GAAK,+BACXD,MAAMhB,syCAqCNc,UAAUI,KAAKf,YAAYa,QAwC3BG,GACAlC,iBAGAF,OAAOI,UAAUiC,iBAAiB,QAAShB,uBAI/CrB,OAAO8B,GAAG,cAAc,KACpB5B,oBAIJF,OAAO8B,GAAG,oBAAoB,KAC1BQ,WAAWpC,eAAgB,QAI/BF,OAAO8B,GAAG,aAAa,KACnB5B,oBAIJF,OAAO8B,GAAG,UAAU,KAChBQ,WAAWpC,eAAgB,OAI/BF,OAAO8B,GAAG,cAAc,KACpB5B,uCAgDgBqC,gBAEhBC,wBACM,mBAAW,CACjB,qBACFC,KAAKC,OAAUA,IAAAA,IAAKC,UAAAA,wBAGlBC,yBACMC,QAAQC,IAAI,EAClB,yBAAe,OAAQH,4BAKnB3C,SA3DkB,EAACA,OAAQwC,iBAAkBI,2BAC/C3C,mBAAqB,KACH,IAAI8C,qBAAY/C,QACxBgD,mBAIhBhD,OAAOiD,GAAGC,SAASC,QAAQC,mBAAYR,kBAAkBS,MAIzDrD,OAAOiD,GAAGC,SAASI,gBAAgBC,yBAAkB,CACjDC,KAAMJ,mBACNK,QAASjB,iBACTkB,SAAUzD,mBACV0D,QAASC,KACE5D,OAAO4B,UAAUiC,0BACpB,kHACAD,IAAIE,WACNC,SAIV/D,OAAOiD,GAAGC,SAASc,YAAYC,2BAAoB,CAC/CT,KAAMJ,mBACNc,KAAM1B,iBACNkB,SAAUzD,qBAGdD,OAAOiD,GAAGC,SAASiB,kBAAkBZ,yBAAkB,CACnDa,UAAW3E,SACX4E,MAAOd,yBACPe,SAAU,OACVC,MAAO,SAGXvE,OAAOiD,GAAGC,SAASsB,eAAejB,yBAAkB,CAChDkB,OAAQhF,WAIZM,oBAAoBC,OAAQC,qBAmBxByE,CAAsB1E,OAAQwC,iBAAkBI"} \ No newline at end of file +{"version":3,"file":"commands.min.js","sources":["../src/commands.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 Media commands.\n *\n * @module tiny_mediacms/commands\n * @copyright 2022 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {getStrings} from 'core/str';\nimport {\n component,\n iframeButtonName,\n iframeMenuItemName,\n iframeIcon,\n} from './common';\nimport IframeEmbed from './iframeembed';\nimport {getButtonImage} from 'editor_tiny/utils';\n\nconst isIframe = (node) => node.nodeName.toLowerCase() === 'iframe' ||\n (node.classList && node.classList.contains('tiny-iframe-responsive')) ||\n (node.classList && node.classList.contains('tiny-mediacms-iframe-wrapper'));\n\n/**\n * Wrap iframes with overlay containers that allow hover detection.\n * Since iframes capture mouse events, we add an invisible overlay on top\n * that shows the edit button on hover.\n *\n * @param {TinyMCE} editor - The editor instance\n * @param {Function} handleIframeAction - The action to perform when clicking the button\n */\nconst setupIframeOverlays = (editor, handleIframeAction) => {\n /**\n * Process all iframes in the editor and add overlay wrappers.\n */\n const processIframes = () => {\n const editorBody = editor.getBody();\n if (!editorBody) {\n return;\n }\n\n const iframes = editorBody.querySelectorAll('iframe');\n iframes.forEach((iframe) => {\n // Skip if already wrapped\n if (iframe.parentElement?.classList.contains('tiny-mediacms-iframe-wrapper')) {\n return;\n }\n\n // Skip TinyMCE internal iframes\n if (iframe.hasAttribute('data-mce-object') || iframe.hasAttribute('data-mce-placeholder')) {\n return;\n }\n\n // Create wrapper div\n const wrapper = editor.getDoc().createElement('div');\n wrapper.className = 'tiny-mediacms-iframe-wrapper';\n wrapper.setAttribute('contenteditable', 'false');\n\n // Create edit button (positioned inside wrapper, over the iframe)\n const editBtn = editor.getDoc().createElement('button');\n editBtn.className = 'tiny-mediacms-edit-btn';\n editBtn.setAttribute('type', 'button');\n editBtn.setAttribute('title', 'Edit media embed options');\n // Use text \"EDIT\" instead of icon\n editBtn.textContent = 'EDIT';\n\n // Wrap the iframe: insert wrapper, move iframe into it, add button\n iframe.parentNode.insertBefore(wrapper, iframe);\n wrapper.appendChild(iframe);\n wrapper.appendChild(editBtn);\n });\n };\n\n /**\n * Add CSS styles for hover effects to the editor's document.\n */\n const addStyles = () => {\n const editorDoc = editor.getDoc();\n if (!editorDoc) {\n return;\n }\n\n // Check if styles already added\n if (editorDoc.getElementById('tiny-mediacms-overlay-styles')) {\n return;\n }\n\n const style = editorDoc.createElement('style');\n style.id = 'tiny-mediacms-overlay-styles';\n style.textContent = `\n .tiny-mediacms-iframe-wrapper {\n display: inline-block;\n position: relative;\n line-height: 0;\n vertical-align: top;\n margin-top: 40px;\n }\n .tiny-mediacms-iframe-wrapper iframe {\n display: block;\n }\n .tiny-mediacms-edit-btn {\n position: absolute;\n top: -15px;\n left: 50%;\n transform: translateX(-50%);\n background: rgba(0, 0, 0, 0.7);\n color: #ffffff;\n border: none;\n border-radius: 3px;\n cursor: pointer;\n z-index: 10;\n padding: 4px 12px;\n margin: 0;\n font-size: 12px;\n font-weight: bold;\n text-decoration: none;\n box-shadow: 0 2px 4px rgba(0,0,0,0.3);\n transition: background 0.15s, box-shadow 0.15s;\n display: inline-block;\n box-sizing: border-box;\n }\n .tiny-mediacms-edit-btn:hover {\n background: rgba(0, 0, 0, 0.85);\n box-shadow: 0 3px 6px rgba(0,0,0,0.4);\n }\n `;\n editorDoc.head.appendChild(style);\n };\n\n /**\n * Handle click on the edit button.\n *\n * @param {Event} e - The click event\n */\n const handleOverlayClick = (e) => {\n const target = e.target;\n\n // Check if clicked on edit button or its child (svg/path)\n const editBtn = target.closest('.tiny-mediacms-edit-btn');\n if (!editBtn) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n\n // Find the associated wrapper and iframe\n const wrapper = editBtn.closest('.tiny-mediacms-iframe-wrapper');\n if (!wrapper) {\n return;\n }\n\n const iframe = wrapper.querySelector('iframe');\n if (!iframe) {\n return;\n }\n\n // Select the wrapper so TinyMCE knows which element is selected\n editor.selection.select(wrapper);\n\n // Open the edit dialog\n handleIframeAction();\n };\n\n // Setup on editor init\n editor.on('init', () => {\n addStyles();\n processIframes();\n\n // Handle clicks on the overlay\n editor.getBody().addEventListener('click', handleOverlayClick);\n });\n\n // Re-process when content changes\n editor.on('SetContent', () => {\n processIframes();\n });\n\n // Re-process when content is pasted\n editor.on('PastePostProcess', () => {\n setTimeout(processIframes, 100);\n });\n\n // Re-process after undo/redo\n editor.on('Undo Redo', () => {\n processIframes();\n });\n\n // Re-process on any content change (covers modal updates)\n editor.on('Change', () => {\n setTimeout(processIframes, 50);\n });\n\n // Re-process when node changes (selection changes)\n editor.on('NodeChange', () => {\n processIframes();\n });\n};\n\nconst registerIframeCommand = (editor, iframeButtonText, iframeButtonImage) => {\n const handleIframeAction = () => {\n const iframeEmbed = new IframeEmbed(editor);\n iframeEmbed.displayDialogue();\n };\n\n // Register the iframe icon\n editor.ui.registry.addIcon(iframeIcon, iframeButtonImage.html);\n\n // Register the Menu Button as a toggle.\n // This means that when highlighted over an existing iframe element it will show as toggled on.\n editor.ui.registry.addToggleButton(iframeButtonName, {\n icon: iframeIcon,\n tooltip: iframeButtonText,\n onAction: handleIframeAction,\n onSetup: api => {\n return editor.selection.selectorChangedWithUnbind(\n 'iframe:not([data-mce-object]):not([data-mce-placeholder]),.tiny-iframe-responsive,.tiny-mediacms-iframe-wrapper',\n api.setActive\n ).unbind;\n }\n });\n\n editor.ui.registry.addMenuItem(iframeMenuItemName, {\n icon: iframeIcon,\n text: iframeButtonText,\n onAction: handleIframeAction,\n });\n\n editor.ui.registry.addContextToolbar(iframeButtonName, {\n predicate: isIframe,\n items: iframeButtonName,\n position: 'node',\n scope: 'node'\n });\n\n editor.ui.registry.addContextMenu(iframeButtonName, {\n update: isIframe,\n });\n\n // Setup iframe overlays with edit button on hover\n setupIframeOverlays(editor, handleIframeAction);\n};\n\nexport const getSetup = async() => {\n const [\n iframeButtonText,\n ] = await getStrings([\n 'iframebuttontitle',\n ].map((key) => ({key, component})));\n\n const [\n iframeButtonImage,\n ] = await Promise.all([\n getButtonImage('icon', component),\n ]);\n\n // Note: The function returned here must be synchronous and cannot use promises.\n // All promises must be resolved prior to returning the function.\n return (editor) => {\n registerIframeCommand(editor, iframeButtonText, iframeButtonImage);\n };\n};\n"],"names":["isIframe","node","nodeName","toLowerCase","classList","contains","setupIframeOverlays","editor","handleIframeAction","processIframes","editorBody","getBody","querySelectorAll","forEach","iframe","parentElement","_iframe$parentElement","hasAttribute","wrapper","getDoc","createElement","className","setAttribute","editBtn","textContent","parentNode","insertBefore","appendChild","handleOverlayClick","e","target","closest","preventDefault","stopPropagation","querySelector","selection","select","on","editorDoc","getElementById","style","id","head","addStyles","addEventListener","setTimeout","async","iframeButtonText","map","key","component","iframeButtonImage","Promise","all","IframeEmbed","displayDialogue","ui","registry","addIcon","iframeIcon","html","addToggleButton","iframeButtonName","icon","tooltip","onAction","onSetup","api","selectorChangedWithUnbind","setActive","unbind","addMenuItem","iframeMenuItemName","text","addContextToolbar","predicate","items","position","scope","addContextMenu","update","registerIframeCommand"],"mappings":";;;;;;;8JAiCMA,SAAYC,MAAyC,WAAhCA,KAAKC,SAASC,eACpCF,KAAKG,WAAaH,KAAKG,UAAUC,SAAS,2BAC1CJ,KAAKG,WAAaH,KAAKG,UAAUC,SAAS,gCAUzCC,oBAAsB,CAACC,OAAQC,4BAI3BC,eAAiB,WACbC,WAAaH,OAAOI,cACrBD,kBAIWA,WAAWE,iBAAiB,UACpCC,SAASC,oEAETA,OAAOC,gDAAPC,sBAAsBZ,UAAUC,SAAS,0CAKzCS,OAAOG,aAAa,oBAAsBH,OAAOG,aAAa,qCAK5DC,QAAUX,OAAOY,SAASC,cAAc,OAC9CF,QAAQG,UAAY,+BACpBH,QAAQI,aAAa,kBAAmB,eAGlCC,QAAUhB,OAAOY,SAASC,cAAc,UAC9CG,QAAQF,UAAY,yBACpBE,QAAQD,aAAa,OAAQ,UAC7BC,QAAQD,aAAa,QAAS,4BAE9BC,QAAQC,YAAc,OAGtBV,OAAOW,WAAWC,aAAaR,QAASJ,QACxCI,QAAQS,YAAYb,QACpBI,QAAQS,YAAYJ,aAiEtBK,mBAAsBC,UAIlBN,QAHSM,EAAEC,OAGMC,QAAQ,+BAC1BR,eAILM,EAAEG,iBACFH,EAAEI,wBAGIf,QAAUK,QAAQQ,QAAQ,qCAC3Bb,eAIUA,QAAQgB,cAAc,YAMrC3B,OAAO4B,UAAUC,OAAOlB,SAGxBV,uBAIJD,OAAO8B,GAAG,QAAQ,KAzFA,YACRC,UAAY/B,OAAOY,aACpBmB,oBAKDA,UAAUC,eAAe,6CAIvBC,MAAQF,UAAUlB,cAAc,SACtCoB,MAAMC,GAAK,+BACXD,MAAMhB,syCAqCNc,UAAUI,KAAKf,YAAYa,QAwC3BG,GACAlC,iBAGAF,OAAOI,UAAUiC,iBAAiB,QAAShB,uBAI/CrB,OAAO8B,GAAG,cAAc,KACpB5B,oBAIJF,OAAO8B,GAAG,oBAAoB,KAC1BQ,WAAWpC,eAAgB,QAI/BF,OAAO8B,GAAG,aAAa,KACnB5B,oBAIJF,OAAO8B,GAAG,UAAU,KAChBQ,WAAWpC,eAAgB,OAI/BF,OAAO8B,GAAG,cAAc,KACpB5B,uCAgDgBqC,gBAEhBC,wBACM,mBAAW,CACjB,qBACFC,KAAKC,OAAUA,IAAAA,IAAKC,UAAAA,wBAGlBC,yBACMC,QAAQC,IAAI,EAClB,yBAAe,OAAQH,4BAKnB3C,SA3DkB,EAACA,OAAQwC,iBAAkBI,2BAC/C3C,mBAAqB,KACH,IAAI8C,qBAAY/C,QACxBgD,mBAIhBhD,OAAOiD,GAAGC,SAASC,QAAQC,mBAAYR,kBAAkBS,MAIzDrD,OAAOiD,GAAGC,SAASI,gBAAgBC,yBAAkB,CACjDC,KAAMJ,mBACNK,QAASjB,iBACTkB,SAAUzD,mBACV0D,QAASC,KACE5D,OAAO4B,UAAUiC,0BACpB,kHACAD,IAAIE,WACNC,SAIV/D,OAAOiD,GAAGC,SAASc,YAAYC,2BAAoB,CAC/CT,KAAMJ,mBACNc,KAAM1B,iBACNkB,SAAUzD,qBAGdD,OAAOiD,GAAGC,SAASiB,kBAAkBZ,yBAAkB,CACnDa,UAAW3E,SACX4E,MAAOd,yBACPe,SAAU,OACVC,MAAO,SAGXvE,OAAOiD,GAAGC,SAASsB,eAAejB,yBAAkB,CAChDkB,OAAQhF,WAIZM,oBAAoBC,OAAQC,qBAmBxByE,CAAsB1E,OAAQwC,iBAAkBI"} \ No newline at end of file