This commit is contained in:
Markos Gogoulos
2026-04-21 11:02:30 +03:00
parent 656176b002
commit 6145249f5c
18 changed files with 227 additions and 203 deletions
@@ -156,22 +156,23 @@ class text_filter extends \core_filters\text_filter {
$launchurl = new moodle_url('/filter/mediacms/launch.php', $launch_params); $launchurl = new moodle_url('/filter/mediacms/launch.php', $launch_params);
// Build iframe attributes // Build responsive CSS
$iframe_attrs = [ $max_width = ($width !== null) ? (int)$width : 640;
'src' => $launchurl->out(false), if ($width !== null && $height !== null && (int)$height > 0) {
'frameborder' => 0, $aspect_ratio_css = (int)$width . ' / ' . (int)$height;
'allowfullscreen' => 'allowfullscreen', } else {
'class' => 'mediacms-embed', $aspect_ratio_css = '16 / 9';
'title' => 'MediaCMS Video' }
]; $style = 'width:100%;max-width:' . $max_width . 'px;aspect-ratio:' . $aspect_ratio_css
. ';display:block;margin:0 auto;border:0;';
// Add width/height attributes only if provided $iframe_attrs = [
if ($width !== null) { 'src' => $launchurl->out(false),
$iframe_attrs['width'] = $width; 'style' => $style,
} 'frameborder' => '0',
if ($height !== null) { 'allowfullscreen' => 'allowfullscreen',
$iframe_attrs['height'] = $height; 'title' => 'MediaCMS Video',
} ];
$iframe = html_writer::tag('iframe', '', $iframe_attrs); $iframe = html_writer::tag('iframe', '', $iframe_attrs);
@@ -47,7 +47,8 @@ echo html_writer::tag('iframe', '', [
'src' => $src, 'src' => $src,
'allowfullscreen' => 'true', 'allowfullscreen' => 'true',
'allow' => 'autoplay *; fullscreen *; encrypted-media *; camera *; microphone *; display-capture *;', 'allow' => 'autoplay *; fullscreen *; encrypted-media *; camera *; microphone *; display-capture *;',
'style' => 'border:none;display:block;width:100%;height:calc(100vh - 120px);', 'style' => 'border:none;display:block;width:100%;height:100vh;',
// 'style' => 'border:none;display:block;width:100%;height:calc(100vh - 120px);',
]); ]);
echo $OUTPUT->footer(); echo $OUTPUT->footer();
@@ -5,6 +5,6 @@ define("tiny_mediacms/commands",["exports","core/str","./common","./iframeembed"
* @module tiny_mediacms/commands * @module tiny_mediacms/commands
* @copyright 2022 Huong Nguyen <huongnv13@gmail.com> * @copyright 2022 Huong Nguyen <huongnv13@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @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")||"a"===node.nodeName.toLowerCase()&&"true"===node.getAttribute("data-mediacms-textlink"),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=>{const selector=["iframe:not([data-mce-object]):not([data-mce-placeholder])",".tiny-iframe-responsive",".tiny-mediacms-iframe-wrapper",'a[data-mediacms-textlink="true"]'].join(",");return editor.selection.selectorChangedWithUnbind(selector,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")||"a"===node.nodeName.toLowerCase()&&"true"===node.getAttribute("data-mediacms-textlink"),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: -30px;\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=>{const selector=["iframe:not([data-mce-object]):not([data-mce-placeholder])",".tiny-iframe-responsive",".tiny-mediacms-iframe-wrapper",'a[data-mediacms-textlink="true"]'].join(",");return editor.selection.selectorChangedWithUnbind(selector,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 //# sourceMappingURL=commands.min.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,6 +5,6 @@ define("tiny_mediacms/plugin",["exports","editor_tiny/loader","editor_tiny/utils
* @module tiny_mediacms/plugin * @module tiny_mediacms/plugin
* @copyright 2022 Andrew Lyons <andrew@nicols.co.uk> * @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Commands=_interopRequireWildcard(Commands),Configuration=_interopRequireWildcard(Configuration),Options=_interopRequireWildcard(Options);const isMediaCMSUrl=url=>{if(!url)return!1;try{const urlObj=new URL(url);return("/embed"===urlObj.pathname||"/view"===urlObj.pathname)&&urlObj.searchParams.has("m")}catch(e){return!1}},MEDIACMS_URL_PATTERN=/(^|>|\s)(https?:\/\/[^\s<>"]+\/(?:embed|view)\?m=[^\s<>"]+)(<|\s|$)/g;var _default=new Promise((async resolve=>{const[tinyMCE,setupCommands,pluginMetadata]=await Promise.all([(0,_loader.getTinyMCE)(),Commands.getSetup(),(0,_utils.getPluginMetadata)(_common.component,_common.pluginName)]);tinyMCE.PluginManager.add("".concat(_common.component,"/plugin"),(editor=>(Options.register(editor),setupCommands(editor),(0,_autoconvert.setupAutoConvert)(editor),editor.on("BeforeSetContent",(e=>{e.content&&"string"==typeof e.content&&(e.content=e.content.replace(MEDIACMS_URL_PATTERN,((match,before,url,after)=>isMediaCMSUrl(url)?before+(url=>{let embedUrl=url;try{const urlObj=new URL(url);"/view"===urlObj.pathname&&(urlObj.pathname="/embed",embedUrl=urlObj.toString())}catch(e){}return'<iframe src="'.concat(embedUrl,'" ')+'style="width: 100%; aspect-ratio: 16 / 9; display: block; border: 0;" allowfullscreen="allowfullscreen"></iframe>'})(url)+after:match)))})),editor.on("GetContent",(e=>{if("html"===e.format){const tempDiv=document.createElement("div");tempDiv.innerHTML=e.content,tempDiv.querySelectorAll(".tiny-mediacms-edit-btn").forEach((btn=>btn.remove())),tempDiv.querySelectorAll("iframe").forEach((iframe=>{const src=iframe.getAttribute("src");if(isMediaCMSUrl(src)){const wrapper=iframe.closest(".tiny-mediacms-iframe-wrapper")||iframe.closest(".tiny-iframe-responsive"),urlText=document.createTextNode(src),p=document.createElement("p");p.appendChild(urlText),wrapper?(wrapper.parentNode.insertBefore(p,wrapper),wrapper.remove()):(iframe.parentNode.insertBefore(p,iframe),iframe.remove())}})),tempDiv.querySelectorAll(".tiny-mediacms-iframe-wrapper").forEach((wrapper=>{const iframe=wrapper.querySelector("iframe");iframe&&wrapper.parentNode.insertBefore(iframe,wrapper),wrapper.remove()})),tempDiv.querySelectorAll(".tiny-iframe-responsive").forEach((wrapper=>{const iframe=wrapper.querySelector("iframe");iframe&&wrapper.parentNode.insertBefore(iframe,wrapper),wrapper.remove()})),e.content=tempDiv.innerHTML}})),pluginMetadata))),resolve(["".concat(_common.component,"/plugin"),Configuration])}));return _exports.default=_default,_exports.default})); */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Commands=_interopRequireWildcard(Commands),Configuration=_interopRequireWildcard(Configuration),Options=_interopRequireWildcard(Options);const isMediaCMSUrl=url=>{if(!url)return!1;try{const urlObj=new URL(url);return("/embed"===urlObj.pathname||"/view"===urlObj.pathname)&&urlObj.searchParams.has("m")}catch(e){return!1}},convertUrlsToIframes=html=>{const tempDiv=document.createElement("div");tempDiv.innerHTML=html;const nodesToReplace=[],walk=el=>{for(const child of Array.from(el.childNodes))if(child.nodeType===Node.TEXT_NODE){const url=child.textContent.trim();isMediaCMSUrl(url)&&nodesToReplace.push({node:child,url:url})}else child.nodeType===Node.ELEMENT_NODE&&"a"!==child.tagName.toLowerCase()&&walk(child)};return walk(tempDiv),nodesToReplace.forEach((_ref=>{let{node:node,url:url}=_ref;const wrapper=document.createElement("div");wrapper.innerHTML=(url=>{let embedUrl=url;try{const urlObj=new URL(url);"/view"===urlObj.pathname&&(urlObj.pathname="/embed",embedUrl=urlObj.toString())}catch(e){}return'<iframe src="'.concat(embedUrl,'" width="560" height="315" ')+'style="width:100%;max-width:560px;aspect-ratio:560 / 315;display:block;margin:0 auto;border:0;" frameborder="0" allowfullscreen></iframe>'})(url);const iframe=wrapper.firstChild;iframe&&node.parentNode.replaceChild(iframe,node)})),tempDiv.innerHTML};var _default=new Promise((async resolve=>{const[tinyMCE,setupCommands,pluginMetadata]=await Promise.all([(0,_loader.getTinyMCE)(),Commands.getSetup(),(0,_utils.getPluginMetadata)(_common.component,_common.pluginName)]);tinyMCE.PluginManager.add("".concat(_common.component,"/plugin"),(editor=>(Options.register(editor),setupCommands(editor),(0,_autoconvert.setupAutoConvert)(editor),editor.on("BeforeSetContent",(e=>{e.content&&"string"==typeof e.content&&(e.content=convertUrlsToIframes(e.content))})),editor.on("GetContent",(e=>{if("html"===e.format){const tempDiv=document.createElement("div");tempDiv.innerHTML=e.content,tempDiv.querySelectorAll(".tiny-mediacms-edit-btn").forEach((btn=>btn.remove())),tempDiv.querySelectorAll(".tiny-mediacms-iframe-wrapper, .tiny-iframe-responsive").forEach((wrapper=>{const iframe=wrapper.querySelector("iframe");iframe&&wrapper.parentNode.insertBefore(iframe,wrapper),wrapper.remove()})),e.content=tempDiv.innerHTML}})),pluginMetadata))),resolve(["".concat(_common.component,"/plugin"),Configuration])}));return _exports.default=_default,_exports.default}));
//# sourceMappingURL=plugin.min.js.map //# sourceMappingURL=plugin.min.js.map
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
define("tiny_mediacms/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={IMAGE:{actions:{submit:".tiny_imagecms_urlentrysubmit",imageBrowser:".openimagecmsbrowser",addUrl:".tiny_imagecms_addurl",deleteImage:".tiny_imagecms_deleteicon"},elements:{form:"form.tiny_imagecms_form",alignSettings:".tiny_imagecms_button",alt:".tiny_imagecms_altentry",altWarning:".tiny_imagecms_altwarning",height:".tiny_imagecms_heightentry",width:".tiny_imagecms_widthentry",url:".tiny_imagecms_urlentry",urlWarning:".tiny_imagecms_urlwarning",size:".tiny_imagecms_size",presentation:".tiny_imagecms_presentation",constrain:".tiny_imagecms_constrain",customStyle:".tiny_imagecms_customstyle",preview:".tiny_imagecms_preview",previewBox:".tiny_imagecms_preview_box",loaderIcon:".tiny_imagecms_loader",loaderIconContainer:".tiny_imagecms_loader_container",insertImage:".tiny_imagecms_insert_image",modalFooter:".modal-footer",dropzoneContainer:".tiny_imagecms_dropzone_container",fileInput:"#tiny_imagecms_fileinput",fileNameLabel:".tiny_imagecms_filename",sizeOriginal:".tiny_imagecms_sizeoriginal",sizeCustom:".tiny_imagecms_sizecustom",properties:".tiny_imagecms_properties"},styles:{responsive:"img-fluid"}},EMBED:{actions:{submit:".tiny_mediacms_submit",mediaBrowser:".openmediacmsbrowser"},elements:{form:"form.tiny_mediacms_form",source:".tiny_mediacms_source",track:".tiny_mediacms_track",mediaSource:".tiny_mediacms_media_source",linkSource:".tiny_mediacms_link_source",linkSize:".tiny_mediacms_link_size",posterSource:".tiny_mediacms_poster_source",posterSize:".tiny_mediacms_poster_size",displayOptions:".tiny_mediacms_display_options",name:".tiny_mediacms_name_entry",title:".tiny_mediacms_title_entry",url:".tiny_mediacms_url_entry",width:".tiny_mediacms_width_entry",height:".tiny_mediacms_height_entry",trackSource:".tiny_mediacms_track_source",trackKind:".tiny_mediacms_track_kind_entry",trackLabel:".tiny_mediacms_track_label_entry",trackLang:".tiny_mediacms_track_lang_entry",trackDefault:".tiny_mediacms_track_default",mediaControl:".tiny_mediacms_controls",mediaAutoplay:".tiny_mediacms_autoplay",mediaMute:".tiny_mediacms_mute",mediaLoop:".tiny_mediacms_loop",advancedSettings:".tiny_mediacms_advancedsettings",linkTab:'li[data-medium-type="link"]',videoTab:'li[data-medium-type="video"]',audioTab:'li[data-medium-type="audio"]',linkPane:'.tab-pane[data-medium-type="link"]',videoPane:'.tab-pane[data-medium-type="video"]',audioPane:'.tab-pane[data-medium-type="audio"]',trackSubtitlesTab:'li[data-track-kind="subtitles"]',trackCaptionsTab:'li[data-track-kind="captions"]',trackDescriptionsTab:'li[data-track-kind="descriptions"]',trackChaptersTab:'li[data-track-kind="chapters"]',trackMetadataTab:'li[data-track-kind="metadata"]',trackSubtitlesPane:'.tab-pane[data-track-kind="subtitles"]',trackCaptionsPane:'.tab-pane[data-track-kind="captions"]',trackDescriptionsPane:'.tab-pane[data-track-kind="descriptions"]',trackChaptersPane:'.tab-pane[data-track-kind="chapters"]',trackMetadataPane:'.tab-pane[data-track-kind="metadata"]'},mediaTypes:{link:"LINK",video:"VIDEO",audio:"AUDIO"},trackKinds:{subtitles:"SUBTITLES",captions:"CAPTIONS",descriptions:"DESCRIPTIONS",chapters:"CHAPTERS",metadata:"METADATA"}},IFRAME:{actions:{remove:'[data-action="remove"]'},elements:{form:"form.tiny_iframecms_form",url:".tiny_iframecms_url",urlWarning:".tiny_iframecms_url_warning",showTitle:".tiny_iframecms_showtitle",linkTitle:".tiny_iframecms_linktitle",showRelated:".tiny_iframecms_showrelated",showUserAvatar:".tiny_iframecms_showuseravatar",textLinkOnly:".tiny_iframecms_textlinkonly",startAt:".tiny_iframecms_startat",startAtEnabled:".tiny_iframecms_startat_enabled",aspectRatio:".tiny_iframecms_aspectratio",width:".tiny_iframecms_width",height:".tiny_iframecms_height",preview:".tiny_iframecms_preview",previewContainer:".tiny_iframecms_preview_container",tabs:".tiny_iframecms_tabs",tabUrlBtn:".tiny_iframecms_tab_url_btn",tabIframeLibraryBtn:".tiny_iframecms_tab_iframe_library_btn",tabUploadMediaBtn:".tiny_iframecms_upload_media_btn",paneUrl:".tiny_iframecms_pane_url",paneIframeLibrary:".tiny_iframecms_pane_iframe_library",iframeLibraryContainer:".tiny_iframecms_iframe_library_container",iframeLibraryPlaceholder:".tiny_iframecms_iframe_library_placeholder",iframeLibraryLoading:".tiny_iframecms_iframe_library_loading",iframeLibraryFrame:".tiny_iframecms_iframe_library_frame"},aspectRatios:{"16:9":{width:560,height:315},"4:3":{width:560,height:420},"1:1":{width:400,height:400},custom:null}}},_exports.default})); define("tiny_mediacms/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={IMAGE:{actions:{submit:".tiny_imagecms_urlentrysubmit",imageBrowser:".openimagecmsbrowser",addUrl:".tiny_imagecms_addurl",deleteImage:".tiny_imagecms_deleteicon"},elements:{form:"form.tiny_imagecms_form",alignSettings:".tiny_imagecms_button",alt:".tiny_imagecms_altentry",altWarning:".tiny_imagecms_altwarning",height:".tiny_imagecms_heightentry",width:".tiny_imagecms_widthentry",url:".tiny_imagecms_urlentry",urlWarning:".tiny_imagecms_urlwarning",size:".tiny_imagecms_size",presentation:".tiny_imagecms_presentation",constrain:".tiny_imagecms_constrain",customStyle:".tiny_imagecms_customstyle",preview:".tiny_imagecms_preview",previewBox:".tiny_imagecms_preview_box",loaderIcon:".tiny_imagecms_loader",loaderIconContainer:".tiny_imagecms_loader_container",insertImage:".tiny_imagecms_insert_image",modalFooter:".modal-footer",dropzoneContainer:".tiny_imagecms_dropzone_container",fileInput:"#tiny_imagecms_fileinput",fileNameLabel:".tiny_imagecms_filename",sizeOriginal:".tiny_imagecms_sizeoriginal",sizeCustom:".tiny_imagecms_sizecustom",properties:".tiny_imagecms_properties"},styles:{responsive:"img-fluid"}},EMBED:{actions:{submit:".tiny_mediacms_submit",mediaBrowser:".openmediacmsbrowser"},elements:{form:"form.tiny_mediacms_form",source:".tiny_mediacms_source",track:".tiny_mediacms_track",mediaSource:".tiny_mediacms_media_source",linkSource:".tiny_mediacms_link_source",linkSize:".tiny_mediacms_link_size",posterSource:".tiny_mediacms_poster_source",posterSize:".tiny_mediacms_poster_size",displayOptions:".tiny_mediacms_display_options",name:".tiny_mediacms_name_entry",title:".tiny_mediacms_title_entry",url:".tiny_mediacms_url_entry",width:".tiny_mediacms_width_entry",height:".tiny_mediacms_height_entry",trackSource:".tiny_mediacms_track_source",trackKind:".tiny_mediacms_track_kind_entry",trackLabel:".tiny_mediacms_track_label_entry",trackLang:".tiny_mediacms_track_lang_entry",trackDefault:".tiny_mediacms_track_default",mediaControl:".tiny_mediacms_controls",mediaAutoplay:".tiny_mediacms_autoplay",mediaMute:".tiny_mediacms_mute",mediaLoop:".tiny_mediacms_loop",advancedSettings:".tiny_mediacms_advancedsettings",linkTab:'li[data-medium-type="link"]',videoTab:'li[data-medium-type="video"]',audioTab:'li[data-medium-type="audio"]',linkPane:'.tab-pane[data-medium-type="link"]',videoPane:'.tab-pane[data-medium-type="video"]',audioPane:'.tab-pane[data-medium-type="audio"]',trackSubtitlesTab:'li[data-track-kind="subtitles"]',trackCaptionsTab:'li[data-track-kind="captions"]',trackDescriptionsTab:'li[data-track-kind="descriptions"]',trackChaptersTab:'li[data-track-kind="chapters"]',trackMetadataTab:'li[data-track-kind="metadata"]',trackSubtitlesPane:'.tab-pane[data-track-kind="subtitles"]',trackCaptionsPane:'.tab-pane[data-track-kind="captions"]',trackDescriptionsPane:'.tab-pane[data-track-kind="descriptions"]',trackChaptersPane:'.tab-pane[data-track-kind="chapters"]',trackMetadataPane:'.tab-pane[data-track-kind="metadata"]'},mediaTypes:{link:"LINK",video:"VIDEO",audio:"AUDIO"},trackKinds:{subtitles:"SUBTITLES",captions:"CAPTIONS",descriptions:"DESCRIPTIONS",chapters:"CHAPTERS",metadata:"METADATA"}},IFRAME:{actions:{remove:'[data-action="remove"]'},elements:{form:"form.tiny_iframecms_form",url:".tiny_iframecms_url",urlWarning:".tiny_iframecms_url_warning",showTitle:".tiny_iframecms_showtitle",linkTitle:".tiny_iframecms_linktitle",showRelated:".tiny_iframecms_showrelated",showUserAvatar:".tiny_iframecms_showuseravatar",textLinkOnly:".tiny_iframecms_textlinkonly",startAt:".tiny_iframecms_startat",startAtEnabled:".tiny_iframecms_startat_enabled",width:".tiny_iframecms_width",height:".tiny_iframecms_height",preview:".tiny_iframecms_preview",previewContainer:".tiny_iframecms_preview_container",tabs:".tiny_iframecms_tabs",tabUrlBtn:".tiny_iframecms_tab_url_btn",tabIframeLibraryBtn:".tiny_iframecms_tab_iframe_library_btn",tabUploadMediaBtn:".tiny_iframecms_upload_media_btn",paneUrl:".tiny_iframecms_pane_url",paneIframeLibrary:".tiny_iframecms_pane_iframe_library",iframeLibraryContainer:".tiny_iframecms_iframe_library_container",iframeLibraryPlaceholder:".tiny_iframecms_iframe_library_placeholder",iframeLibraryLoading:".tiny_iframecms_iframe_library_loading",iframeLibraryFrame:".tiny_iframecms_iframe_library_frame"}}},_exports.default}));
//# sourceMappingURL=selectors.min.js.map //# sourceMappingURL=selectors.min.js.map
File diff suppressed because one or more lines are too long
@@ -115,7 +115,7 @@ const setupIframeOverlays = (editor, handleIframeAction) => {
} }
.tiny-mediacms-edit-btn { .tiny-mediacms-edit-btn {
position: absolute; position: absolute;
top: -15px; top: -30px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7); background: rgba(0, 0, 0, 0.7);
@@ -139,6 +139,12 @@ export default class IframeEmbed {
return isNaN(parsed) ? null : parsed; return isNaN(parsed) ? null : parsed;
} }
computeAspectRatioCSS(values) {
const w = values.width || 560;
const h = values.height || 315;
return `${w} / ${h}`;
}
buildEmbedUrl(parsed, options) { buildEmbedUrl(parsed, options) {
if (parsed.isGeneric) { if (parsed.isGeneric) {
return parsed.rawUrl; return parsed.rawUrl;
@@ -167,13 +173,6 @@ export default class IframeEmbed {
); );
url.searchParams.set('linkTitle', options.linkTitle ? '1' : '0'); url.searchParams.set('linkTitle', options.linkTitle ? '1' : '0');
if (options.width) {
url.searchParams.set('width', options.width.toString());
}
if (options.height) {
url.searchParams.set('height', options.height.toString());
}
if (options.startAtEnabled && options.startAt) { if (options.startAtEnabled && options.startAt) {
const seconds = this.timeStringToSeconds(options.startAt); const seconds = this.timeStringToSeconds(options.startAt);
if (seconds !== null && seconds > 0) { if (seconds !== null && seconds > 0) {
@@ -197,14 +196,8 @@ export default class IframeEmbed {
: fallback; : fallback;
}; };
let width, height; const width = (this.isUpdating && data.width) ? data.width : 560;
if (this.isUpdating && (data.width || data.height)) { const height = (this.isUpdating && data.height) ? data.height : 315;
width = data.width || 640;
height = data.height || 360;
} else {
width = 640;
height = 360;
}
return { return {
elementid: this.editor.getElement().id, elementid: this.editor.getElement().id,
@@ -217,12 +210,8 @@ export default class IframeEmbed {
textLinkOnly: data.textLinkOnly || false, textLinkOnly: data.textLinkOnly || false,
startAtEnabled: data.startAtEnabled || false, startAtEnabled: data.startAtEnabled || false,
startAt: data.startAt || '0:00', startAt: data.startAt || '0:00',
width: width, width,
height: height, height,
is16_9: !data.aspectRatio || data.aspectRatio === '16:9',
is4_3: data.aspectRatio === '4:3',
is1_1: data.aspectRatio === '1:1',
isCustom: data.aspectRatio === 'custom',
}; };
} }
@@ -298,21 +287,31 @@ export default class IframeEmbed {
const src = this.selectedIframe.getAttribute('src'); const src = this.selectedIframe.getAttribute('src');
const parsed = this.parseInput(src); const parsed = this.parseInput(src);
let width = parsed?.width || this.selectedIframe.getAttribute('width') || null; // Parse responsive dimensions from inline style
let height = parsed?.height || this.selectedIframe.getAttribute('height') || null; const style = this.selectedIframe.getAttribute('style') || '';
const maxWidthMatch = style.match(/max-width:\s*(\d+(?:\.\d+)?)px/);
const aspectRatioMatch = style.match(/aspect-ratio:\s*(\d+(?:\.\d+)?)\s*\/\s*(\d+(?:\.\d+)?)/);
width = width ? parseInt(width) : null; const maxWidth = maxWidthMatch ? parseInt(maxWidthMatch[1]) : 560;
height = height ? parseInt(height) : null; let height = 315;
if (aspectRatioMatch) {
const rw = parseFloat(aspectRatioMatch[1]);
const rh = parseFloat(aspectRatioMatch[2]);
if (rw > 0) {
height = Math.round(maxWidth * rh / rw);
}
}
return { return {
url: src, url: src,
width: width, width: maxWidth,
height: height, height,
showTitle: parsed?.showTitle ?? true, showTitle: parsed?.showTitle ?? true,
linkTitle: parsed?.linkTitle ?? true, linkTitle: parsed?.linkTitle ?? true,
showRelated: parsed?.showRelated ?? true, showRelated: parsed?.showRelated ?? true,
showUserAvatar: parsed?.showUserAvatar ?? true, showUserAvatar: parsed?.showUserAvatar ?? true,
startAtEnabled: parsed?.startAt !== null, startAtEnabled: !!(parsed?.startAt),
startAt: parsed?.startAt || '0:00', startAt: parsed?.startAt || '0:00',
}; };
} }
@@ -340,9 +339,6 @@ export default class IframeEmbed {
startAt: form startAt: form
.querySelector(Selectors.IFRAME.elements.startAt) .querySelector(Selectors.IFRAME.elements.startAt)
.value.trim(), .value.trim(),
aspectRatio: form.querySelector(
Selectors.IFRAME.elements.aspectRatio,
).value,
width: this.parseWidthHeight( width: this.parseWidthHeight(
form.querySelector(Selectors.IFRAME.elements.width).value, form.querySelector(Selectors.IFRAME.elements.width).value,
), ),
@@ -382,8 +378,9 @@ export default class IframeEmbed {
const context = { const context = {
src: embedUrl, src: embedUrl,
width: values.width, maxWidth: values.width || 560,
height: values.height, height: values.height || 315,
aspectRatioCSS: this.computeAspectRatioCSS(values),
}; };
const { html } = await Templates.renderForPromise( const { html } = await Templates.renderForPromise(
@@ -447,22 +444,20 @@ export default class IframeEmbed {
<div class="alert alert-info"> <div class="alert alert-info">
<strong>Text link preview:</strong><br> <strong>Text link preview:</strong><br>
<a href="${hrefUrl}" target="_blank" data-mediacms-textlink="true">${linkText}</a> <a href="${hrefUrl}" target="_blank" data-mediacms-textlink="true">${linkText}</a>
<br><small class="text-muted mt-2 d-block">This link will not be auto-converted by the MediaCMS filter.</small>
</div> </div>
`; `;
} else { } else {
const previewWidth = Math.min(values.width, 400); const previewWidth = Math.min(values.width || 560, 400);
const scale = previewWidth / values.width; const previewHeight = Math.round(previewWidth * (values.height || 315) / (values.width || 560));
const previewHeight = Math.round(values.height * scale);
previewContainer.innerHTML = ` previewContainer.innerHTML = `
<iframe <iframe
src="${embedUrl}" src="${embedUrl}"
width="${previewWidth}" width="${previewWidth}"
height="${previewHeight}" height="${previewHeight}"
style="display:block;border:0;"
frameborder="0" frameborder="0"
allowfullscreen allowfullscreen>
style="max-width: 100%;">
</iframe> </iframe>
`; `;
} }
@@ -475,56 +470,18 @@ export default class IframeEmbed {
}, 500); }, 500);
} }
handleAspectRatioChange(root) { handleWidthChange(root) {
const form = root.querySelector(Selectors.IFRAME.elements.form); const form = root.querySelector(Selectors.IFRAME.elements.form);
const aspectRatio = form.querySelector( const widthInput = form.querySelector(Selectors.IFRAME.elements.width);
Selectors.IFRAME.elements.aspectRatio,
).value;
const dimensions = Selectors.IFRAME.aspectRatios[aspectRatio];
if (dimensions && aspectRatio !== 'custom') {
form.querySelector(Selectors.IFRAME.elements.width).value =
dimensions.width;
form.querySelector(Selectors.IFRAME.elements.height).value =
dimensions.height;
}
this.updatePreview(root);
}
handleWidthChange(root, newWidth) {
const form = root.querySelector(Selectors.IFRAME.elements.form);
const aspectRatio = form.querySelector(Selectors.IFRAME.elements.aspectRatio).value;
const heightInput = form.querySelector(Selectors.IFRAME.elements.height); const heightInput = form.querySelector(Selectors.IFRAME.elements.height);
const newWidth = parseInt(widthInput.value);
if (aspectRatio !== 'custom' && newWidth) { if (!isNaN(newWidth) && newWidth > 0) {
const width = parseInt(newWidth) || 0; heightInput.value = Math.round(newWidth * 9 / 16);
const arr = aspectRatio.split(':');
const x = parseInt(arr[0]);
const y = parseInt(arr[1]);
const calculatedHeight = Math.round((width * y) / x);
heightInput.value = calculatedHeight;
} }
this.handleInputChange(root); this.handleInputChange(root);
} }
handleHeightChange(root, newHeight) { handleHeightChange(root) {
const form = root.querySelector(Selectors.IFRAME.elements.form);
const aspectRatio = form.querySelector(Selectors.IFRAME.elements.aspectRatio).value;
const widthInput = form.querySelector(Selectors.IFRAME.elements.width);
if (aspectRatio !== 'custom' && newHeight) {
const height = parseInt(newHeight) || 0;
const arr = aspectRatio.split(':');
const x = parseInt(arr[0]);
const y = parseInt(arr[1]);
const calculatedWidth = Math.round((height * x) / y);
widthInput.value = calculatedWidth;
}
this.handleInputChange(root); this.handleInputChange(root);
} }
@@ -573,6 +530,14 @@ export default class IframeEmbed {
} else { } else {
this.editor.insertContent(html); this.editor.insertContent(html);
} }
setTimeout(() => {
const body = this.editor.getBody();
body.querySelectorAll('p').forEach(p => {
if (p.innerHTML.trim() === '' || p.innerHTML === '<br>') {
p.remove();
}
});
}, 50);
} }
} }
} }
@@ -636,17 +601,13 @@ export default class IframeEmbed {
() => this.handleInputChange(root, true), () => this.handleInputChange(root, true),
); );
form.querySelector(
Selectors.IFRAME.elements.aspectRatio,
).addEventListener('change', () => this.handleAspectRatioChange(root));
form.querySelector(Selectors.IFRAME.elements.width).addEventListener( form.querySelector(Selectors.IFRAME.elements.width).addEventListener(
'input', 'input',
(e) => this.handleWidthChange(root, e.target.value), () => this.handleWidthChange(root),
); );
form.querySelector(Selectors.IFRAME.elements.height).addEventListener( form.querySelector(Selectors.IFRAME.elements.height).addEventListener(
'input', 'input',
(e) => this.handleHeightChange(root, e.target.value), () => this.handleHeightChange(root),
); );
$root.on(ModalEvents.save, () => this.handleDialogueSubmission(modal)); $root.on(ModalEvents.save, () => this.handleDialogueSubmission(modal));
@@ -1024,15 +985,14 @@ export default class IframeEmbed {
if (data.action === 'selectMedia' || data.action === 'mediaSelected') { if (data.action === 'selectMedia' || data.action === 'mediaSelected') {
const embedUrl = data.embedUrl || data.url || ''; const embedUrl = data.embedUrl || data.url || '';
const videoId = data.mediaId || data.videoId || data.id || '';
if (embedUrl) { if (embedUrl) {
this.selectIframeLibraryVideo(root, embedUrl, videoId); this.selectIframeLibraryVideo(root, embedUrl);
} }
return; return;
} }
} }
selectIframeLibraryVideo(root, embedUrl, videoId) { selectIframeLibraryVideo(root, embedUrl) {
const form = root.querySelector(Selectors.IFRAME.elements.form); const form = root.querySelector(Selectors.IFRAME.elements.form);
const urlInput = form.querySelector(Selectors.IFRAME.elements.url); const urlInput = form.querySelector(Selectors.IFRAME.elements.url);
@@ -68,17 +68,49 @@ const mediaCMSUrlToIframe = (url) => {
// Keep original URL if parsing fails // Keep original URL if parsing fails
} }
return `<iframe src="${embedUrl}" ` + return `<iframe src="${embedUrl}" width="560" height="315" ` +
`style="width: 100%; aspect-ratio: 16 / 9; display: block; border: 0;" ` + `style="width:100%;max-width:560px;aspect-ratio:560 / 315;display:block;margin:0 auto;border:0;" ` +
`allowfullscreen="allowfullscreen"></iframe>`; `frameborder="0" allowfullscreen></iframe>`;
}; };
/** /**
* Regular expression to match standalone MediaCMS URLs in content. * Convert standalone MediaCMS URL text nodes to iframes.
* Matches URLs that are on their own line or surrounded by whitespace/tags. * Uses DOM traversal so URLs inside <a> tags (text links) are never touched.
* The URL must contain /embed?m= or /view?m= pattern. *
* @param {string} html - Raw HTML string from the editor
* @returns {string} HTML with standalone URLs replaced by iframe HTML
*/ */
const MEDIACMS_URL_PATTERN = /(^|>|\s)(https?:\/\/[^\s<>"]+\/(?:embed|view)\?m=[^\s<>"]+)(<|\s|$)/g; const convertUrlsToIframes = (html) => {
const tempDiv = document.createElement('div');
tempDiv.innerHTML = html;
const nodesToReplace = [];
const walk = (el) => {
for (const child of Array.from(el.childNodes)) {
if (child.nodeType === Node.TEXT_NODE) {
const url = child.textContent.trim();
if (isMediaCMSUrl(url)) {
nodesToReplace.push({node: child, url});
}
} else if (child.nodeType === Node.ELEMENT_NODE && child.tagName.toLowerCase() !== 'a') {
walk(child);
}
// Do not recurse into <a> tags — text links must be preserved as-is
}
};
walk(tempDiv);
nodesToReplace.forEach(({node, url}) => {
const wrapper = document.createElement('div');
wrapper.innerHTML = mediaCMSUrlToIframe(url);
const iframe = wrapper.firstChild;
if (iframe) {
node.parentNode.replaceChild(iframe, node);
}
});
return tempDiv.innerHTML;
};
// eslint-disable-next-line no-async-promise-executor // eslint-disable-next-line no-async-promise-executor
export default new Promise(async(resolve) => { export default new Promise(async(resolve) => {
@@ -102,69 +134,26 @@ export default new Promise(async(resolve) => {
// Setup auto-conversion of pasted MediaCMS URLs. // Setup auto-conversion of pasted MediaCMS URLs.
setupAutoConvert(editor); setupAutoConvert(editor);
// Convert MediaCMS URLs to iframes when content is loaded into the editor. // Convert standalone MediaCMS URL text nodes to iframes when loading content.
// This handles content from the database that was saved as just URLs. // Text links (<a data-mediacms-textlink>) are preserved because DOM traversal skips <a> tags.
editor.on('BeforeSetContent', (e) => { editor.on('BeforeSetContent', (e) => {
if (e.content && typeof e.content === 'string') { if (e.content && typeof e.content === 'string') {
// Replace standalone MediaCMS URLs with iframes e.content = convertUrlsToIframes(e.content);
e.content = e.content.replace(MEDIACMS_URL_PATTERN, (match, before, url, after) => {
// Verify it's a valid MediaCMS URL
if (isMediaCMSUrl(url)) {
return before + mediaCMSUrlToIframe(url) + after;
}
return match;
});
} }
}); });
// Convert MediaCMS iframes back to just embed URLs when saving. // Clean up editor-only overlay elements when saving, preserving iframe HTML with its
// This stores only the URL in the database, not the full iframe HTML. // responsive styles (max-width, aspect-ratio) so dimensions survive the round-trip.
editor.on('GetContent', (e) => { editor.on('GetContent', (e) => {
if (e.format === 'html') { if (e.format === 'html') {
// Create a temporary container to manipulate the HTML
const tempDiv = document.createElement('div'); const tempDiv = document.createElement('div');
tempDiv.innerHTML = e.content; tempDiv.innerHTML = e.content;
// Remove edit buttons // Remove edit buttons added by the overlay system (editor-only UI)
tempDiv.querySelectorAll('.tiny-mediacms-edit-btn').forEach(btn => btn.remove()); tempDiv.querySelectorAll('.tiny-mediacms-edit-btn').forEach(btn => btn.remove());
// Process all iframes - convert MediaCMS iframes to just URLs // Unwrap overlay divs, keeping the iframe HTML intact with its responsive styles
tempDiv.querySelectorAll('iframe').forEach(iframe => { tempDiv.querySelectorAll('.tiny-mediacms-iframe-wrapper, .tiny-iframe-responsive').forEach(wrapper => {
const src = iframe.getAttribute('src');
if (isMediaCMSUrl(src)) {
// Check if iframe is inside a wrapper
const wrapper = iframe.closest('.tiny-mediacms-iframe-wrapper') ||
iframe.closest('.tiny-iframe-responsive');
// Create a text node with just the URL
const urlText = document.createTextNode(src);
// Wrap in a paragraph for proper formatting
const p = document.createElement('p');
p.appendChild(urlText);
if (wrapper) {
// Replace the entire wrapper with the URL
wrapper.parentNode.insertBefore(p, wrapper);
wrapper.remove();
} else {
// Replace just the iframe with the URL
iframe.parentNode.insertBefore(p, iframe);
iframe.remove();
}
}
});
// Clean up any remaining wrappers that might not have had MediaCMS iframes
tempDiv.querySelectorAll('.tiny-mediacms-iframe-wrapper').forEach(wrapper => {
const iframe = wrapper.querySelector('iframe');
if (iframe) {
wrapper.parentNode.insertBefore(iframe, wrapper);
}
wrapper.remove();
});
tempDiv.querySelectorAll('.tiny-iframe-responsive').forEach(wrapper => {
const iframe = wrapper.querySelector('iframe'); const iframe = wrapper.querySelector('iframe');
if (iframe) { if (iframe) {
wrapper.parentNode.insertBefore(iframe, wrapper); wrapper.parentNode.insertBefore(iframe, wrapper);
@@ -134,7 +134,6 @@ export default {
textLinkOnly: '.tiny_iframecms_textlinkonly', textLinkOnly: '.tiny_iframecms_textlinkonly',
startAt: '.tiny_iframecms_startat', startAt: '.tiny_iframecms_startat',
startAtEnabled: '.tiny_iframecms_startat_enabled', startAtEnabled: '.tiny_iframecms_startat_enabled',
aspectRatio: '.tiny_iframecms_aspectratio',
width: '.tiny_iframecms_width', width: '.tiny_iframecms_width',
height: '.tiny_iframecms_height', height: '.tiny_iframecms_height',
preview: '.tiny_iframecms_preview', preview: '.tiny_iframecms_preview',
@@ -153,11 +152,5 @@ export default {
iframeLibraryLoading: '.tiny_iframecms_iframe_library_loading', iframeLibraryLoading: '.tiny_iframecms_iframe_library_loading',
iframeLibraryFrame: '.tiny_iframecms_iframe_library_frame', iframeLibraryFrame: '.tiny_iframecms_iframe_library_frame',
}, },
aspectRatios: {
'16:9': { width: 560, height: 315 },
'4:3': { width: 560, height: 420 },
'1:1': { width: 400, height: 400 },
custom: null,
},
}, },
}; };
@@ -126,11 +126,6 @@ $string['showuseravatar'] = 'Show user avatar';
$string['responsive'] = 'Responsive'; $string['responsive'] = 'Responsive';
$string['textlinkonly'] = 'Insert text link only'; $string['textlinkonly'] = 'Insert text link only';
$string['startat'] = 'Start at'; $string['startat'] = 'Start at';
$string['aspectratio'] = 'Aspect Ratio';
$string['aspectratio_16_9'] = '16:9';
$string['aspectratio_4_3'] = '4:3';
$string['aspectratio_1_1'] = '1:1';
$string['aspectratio_custom'] = 'Custom';
$string['dimensions'] = 'Dimensions'; $string['dimensions'] = 'Dimensions';
$string['preview'] = 'Preview'; $string['preview'] = 'Preview';
$string['insertiframe'] = 'Insert'; $string['insertiframe'] = 'Insert';
@@ -88,19 +88,6 @@
</div> </div>
</div> </div>
<!-- Aspect Ratio -->
<div class="mb-3">
<label for="{{elementid}}_aspectratio" class="form-label font-weight-bold">
{{#str}} aspectratio, tiny_mediacms {{/str}}
</label>
<select class="form-control tiny_iframecms_aspectratio" id="{{elementid}}_aspectratio">
<option value="16:9" {{#is16_9}}selected{{/is16_9}}>{{#str}} aspectratio_16_9, tiny_mediacms {{/str}}</option>
<option value="4:3" {{#is4_3}}selected{{/is4_3}}>{{#str}} aspectratio_4_3, tiny_mediacms {{/str}}</option>
<option value="1:1" {{#is1_1}}selected{{/is1_1}}>{{#str}} aspectratio_1_1, tiny_mediacms {{/str}}</option>
<option value="custom" {{#isCustom}}selected{{/isCustom}}>{{#str}} aspectratio_custom, tiny_mediacms {{/str}}</option>
</select>
</div>
<!-- Dimensions --> <!-- Dimensions -->
<div class="mb-3"> <div class="mb-3">
<label class="form-label font-weight-bold"> <label class="form-label font-weight-bold">
@@ -110,7 +97,7 @@
<div class="col-6"> <div class="col-6">
<div class="input-group"> <div class="input-group">
<input type="number" class="form-control tiny_iframecms_width" <input type="number" class="form-control tiny_iframecms_width"
id="{{elementid}}_width" value="{{width}}" placeholder="640" min="1" step="1"> id="{{elementid}}_width" value="{{width}}" placeholder="560" min="1" step="1">
<span class="input-group-text">px</span> <span class="input-group-text">px</span>
</div> </div>
<small class="text-muted">{{#str}} width, tiny_mediacms {{/str}}</small> <small class="text-muted">{{#str}} width, tiny_mediacms {{/str}}</small>
@@ -118,7 +105,7 @@
<div class="col-6"> <div class="col-6">
<div class="input-group"> <div class="input-group">
<input type="number" class="form-control tiny_iframecms_height" <input type="number" class="form-control tiny_iframecms_height"
id="{{elementid}}_height" value="{{height}}" placeholder="360" min="1" step="1"> id="{{elementid}}_height" value="{{height}}" placeholder="315" min="1" step="1">
<span class="input-group-text">px</span> <span class="input-group-text">px</span>
</div> </div>
<small class="text-muted">{{#str}} height, tiny_mediacms {{/str}}</small> <small class="text-muted">{{#str}} height, tiny_mediacms {{/str}}</small>
@@ -28,4 +28,4 @@
"aspectRatioClass": "ratio-16-9" "aspectRatioClass": "ratio-16-9"
} }
}} }}
<iframe width="{{width}}" height="{{height}}" src="{{src}}" frameBorder="0" allowFullScreen></iframe> <div class="tiny-mediacms-iframe-wrapper" style="margin:0;padding:0;"><iframe src="{{src}}" width="{{maxWidth}}" height="{{height}}" style="width:100%;max-width:{{maxWidth}}px;height:auto;aspect-ratio:{{aspectRatioCSS}};display:block;margin:0 auto;border:0;" frameborder="0" allowfullscreen></iframe></div>
@@ -0,0 +1,98 @@
<div class="form-group{% if form.state.errors or form.confirm_state.errors %} has-error{% endif %}">
<div class="control-label-container">
<label class="control-label">State</label>
</div>
<div class="controls">
<div class="state-options">
{% for val, lbl in form.fields.state.choices %}{% if val == 'private' %}
<label class="state-option">
<input type="radio" name="state" value="private"
{% if form.state.value == 'private' %}checked{% endif %}>
Private
</label>
{% endif %}{% endfor %}
{% for val, lbl in form.fields.state.choices %}{% if val == 'unlisted' %}
<label class="state-option">
<input type="radio" name="state" value="unlisted"
{% if form.state.value == 'unlisted' %}checked{% endif %}>
Unlisted
</label>
{% endif %}{% endfor %}
{% if form.fields.shared %}
<label class="state-option shared-option">
<input type="checkbox" name="shared" id="id_shared"
{% if form.shared.value %}checked{% endif %}>
Shared
</label>
{% endif %}
{% for val, lbl in form.fields.state.choices %}{% if val == 'public' %}
<label class="state-option">
<input type="radio" name="state" value="public"
{% if form.state.value == 'public' %}checked{% endif %}>
Public
</label>
{% endif %}{% endfor %}
</div>
{% if form.state.errors %}
<div class="error-container" style="margin-top:0.5rem;">
{% for error in form.state.errors %}<p class="invalid-feedback">{{ error }}</p>{% endfor %}
</div>
{% endif %}
{% if form.fields.shared %}
<div id="shared-info" style="display:none; margin-top:0.5rem; font-size:0.875rem; color:#555;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:middle; margin-right:4px; flex-shrink:0;"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>To share media with someone, go to My Media &gt; select media &gt; Bulk Actions &gt; Share with&hellip;
</div>
{% endif %}
</div>
{% if form.fields.shared %}{% if form.was_shared %}
<div id="shared-deselect-warning" style="display:none; margin-top:0.75rem; padding:0.75rem; background:#fff3cd; border:1px solid #ffc107; border-radius:4px;">
<label style="display:flex; gap:0.5rem; align-items:flex-start; cursor:pointer; margin:0;">
<input type="checkbox" name="confirm_state" id="id_confirm_state"
{% if form.confirm_state.value %}checked{% endif %}
style="margin-top:3px; flex-shrink:0;">
<span id="shared-deselect-msg-private">I understand that changing to Private will remove all sharing. Currently this media is shared by me with other users (visible in 'My Media &gt; Shared by Me' page).</span>
<span id="shared-deselect-msg-other" style="display:none;">I understand that unchecking Shared will affect existing sharing settings.</span>
</label>
{% if form.confirm_state.errors %}
<div style="margin-top:0.5rem;">
{% for error in form.confirm_state.errors %}<p class="invalid-feedback" style="color:#dc3545;">{{ error }}</p>{% endfor %}
</div>
{% endif %}
</div>
{% endif %}{% endif %}
{% if form.fields.shared %}
<script>
(function() {
var sharedCb = document.getElementById('id_shared');
var warning = document.getElementById('shared-deselect-warning');
var sharedInfo = document.getElementById('shared-info');
var msgPrivate = document.getElementById('shared-deselect-msg-private');
var msgOther = document.getElementById('shared-deselect-msg-other');
function getSelectedState() {
var radios = document.querySelectorAll('input[name="state"]');
for (var i = 0; i < radios.length; i++) {
if (radios[i].checked) return radios[i].value;
}
return '';
}
function updateWarning() {
var isShared = sharedCb.checked;
if (warning) warning.style.display = isShared ? 'none' : 'block';
if (sharedInfo) sharedInfo.style.display = isShared ? 'block' : 'none';
if (!isShared) {
var state = getSelectedState();
if (msgPrivate) msgPrivate.style.display = state === 'private' ? 'inline' : 'none';
if (msgOther) msgOther.style.display = state !== 'private' ? 'inline' : 'none';
}
}
if (sharedCb) {
sharedCb.addEventListener('change', updateWarning);
document.querySelectorAll('input[name="state"]').forEach(function(r) {
r.addEventListener('change', updateWarning);
});
updateWarning();
}
})();
</script>
{% endif %}
</div>